Code

Merge branch 'ff/aggregate'
authorFlorian Forster <octo@collectd.org>
Sun, 11 Nov 2012 07:58:18 +0000 (08:58 +0100)
committerFlorian Forster <octo@collectd.org>
Sun, 11 Nov 2012 07:58:18 +0000 (08:58 +0100)
Conflicts:
src/Makefile.am

60 files changed:
AUTHORS
bindings/Makefile.am
configure.in
contrib/README
contrib/collectd.service [new file with mode: 0644]
contrib/collectd_network.py
contrib/collection3/bin/index.cgi
contrib/collection3/lib/Collectd/Graph/Type/Df.pm
contrib/migrate-4-5.px
src/Makefile.am
src/amqp.c
src/apcups.c
src/collectd.c
src/collectd.conf.in
src/collectd.conf.pod
src/collectdctl.c
src/common.c
src/contextswitch.c
src/curl_xml.c
src/df.c
src/disk.c
src/email.c
src/ethstat.c
src/exec.c
src/liboconfig/parser.y
src/memcachec.c
src/memcached.c
src/meta_data.c
src/mysql.c
src/netapp.c
src/netlink.c
src/network.c
src/nfs.c
src/ntpd.c
src/oracle.c
src/postgresql.c
src/processes.c
src/redis.c
src/rrdcached.c
src/rrdtool.c
src/snmp.c
src/swap.c
src/tcpconns.c
src/unixsock.c
src/uptime.c
src/utils_avltree.c
src/utils_cache.c
src/utils_db_query.c
src/utils_db_query.h
src/utils_dns.c
src/utils_fbhash.c
src/utils_format_graphite.c [new file with mode: 0644]
src/utils_format_graphite.h [new file with mode: 0644]
src/utils_format_json.c
src/utils_rrdcreate.c
src/varnish.c
src/write_graphite.c
src/write_mongodb.c
src/zfs_arc.c
version-gen.sh

diff --git a/AUTHORS b/AUTHORS
index 90560e347acef55d1dc50bac405725b65a6e41fa..78dbad146745dc81edeb800909297eebd3735028 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -200,6 +200,9 @@ Sven Trenkel <collectd at semidefinite.de>
  - netapp plugin.
  - python plugin.
 
+Thomas Meson <zllak at hycik.org>
+ - Graphite support for the AMQP plugin.
+
 Tomasz Pala <gotar at pld-linux.org>
  - conntrack plugin.
 
index f39e9bbb2778b60a47c138a4ea3ee8f02563126d..3876cc2c06d3f6ae70b08243cd18343b1c3f5a6f 100644 (file)
@@ -10,28 +10,55 @@ EXTRA_DIST = perl/Makefile.PL \
             perl/lib/Collectd/Plugins/Monitorus.pm \
             perl/lib/Collectd/Plugins/OpenVZ.pm
 
+CLEANFILES = \
+       buildperl/Collectd.pm \
+       buildperl/Collectd/Plugins/OpenVZ.pm \
+       buildperl/Collectd/Unixsock.pm \
+       buildperl/Makefile.PL \
+       .perl-directory-stamp
+
+DISTCLEANFILES = \
+       buildperl/Collectd.pm \
+       buildperl/Collectd/Plugins/OpenVZ.pm \
+       buildperl/Collectd/Unixsock.pm \
+       buildperl/Makefile.PL \
+       .perl-directory-stamp
+
 all-local: @PERL_BINDINGS@
 
+
 install-exec-local:
-       [ ! -f perl/Makefile ] || ( cd perl && $(MAKE) install )
+       [ ! -f buildperl/Makefile ] || ( cd buildperl && $(MAKE) install )
+
+# Perl 'make uninstall' does not work as well as wanted.
+# So we do the work here.
+uninstall-local:
+       rm -f $(DESTDIR)$(mandir)/man3/Collectd::Unixsock.3pm
+       rm -f $(DESTDIR)$(datarootdir)/perl5/Collectd.pm
+       rm -f $(DESTDIR)$(datarootdir)/perl5/Collectd/Plugins/OpenVZ.pm
+       rm -f $(DESTDIR)$(datarootdir)/perl5/Collectd/Unixsock.pm
+       rm -f $(DESTDIR)$(prefix)/lib64/perl5/perllocal.pod
+       rm -f $(DESTDIR)$(prefix)/lib64/perl5/auto/Collectd/.packlist
 
 clean-local:
-       [ ! -f perl/Makefile ] || ( cd perl && $(MAKE) realclean )
+       rm -rf buildperl
 
-perl: perl/Makefile
-       cd perl && $(MAKE)
+perl: buildperl/Makefile
+       cd buildperl && $(MAKE)
 
-perl/Makefile: .perl-directory-stamp perl/Makefile.PL \
+buildperl/Makefile: .perl-directory-stamp buildperl/Makefile.PL \
        $(top_builddir)/config.status
-       cd perl && @PERL@ Makefile.PL PREFIX=$(prefix) @PERL_BINDINGS_OPTIONS@
+       cd buildperl && @PERL@ Makefile.PL INSTALL_BASE=$(prefix) @PERL_BINDINGS_OPTIONS@
+
+buildperl/Makefile.PL: .perl-directory-stamp $(top_builddir)/config.status
 
 .perl-directory-stamp:
-       if test ! -d perl; then \
-         mkdir -p perl/Collectd/Plugins; \
-         cp $(srcdir)/perl/Collectd.pm perl/; \
-         cp $(srcdir)/perl/Makefile.PL perl/; \
-         cp $(srcdir)/perl/Collectd/Unixsock.pm perl/Collectd/; \
-         cp $(srcdir)/perl/Collectd/Plugins/OpenVZ.pm perl/Collectd/Plugins/; \
+       if test ! -d buildperl; then \
+         mkdir -p buildperl/Collectd/Plugins; \
+         cp $(srcdir)/perl/lib/Collectd.pm buildperl/; \
+         cp $(srcdir)/perl/Makefile.PL buildperl/; \
+         cp $(srcdir)/perl/lib/Collectd/Unixsock.pm buildperl/Collectd/; \
+         cp $(srcdir)/perl/lib/Collectd/Plugins/OpenVZ.pm buildperl/Collectd/Plugins/; \
        fi
        touch $@
 
index cc3d4c4ed09ba5a841c1d3c7ef60644b316f28d6..83551076038882f3ee067d569dbd072f8b95a3d3 100644 (file)
@@ -91,6 +91,7 @@ fi
 if test "x$ac_system" = "xSolaris"
 then
        AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Define to enforce POSIX thread semantics under Solaris.])
+       AC_DEFINE(_REENTRANT,               1, [Define to enable reentrancy interfaces.])
 fi
 if test "x$ac_system" = "xAIX"
 then
@@ -532,6 +533,8 @@ AC_CHECK_HEADERS(netinet/if_ether.h, [], [],
 #endif
 ])
 
+AC_CHECK_HEADERS(netinet/ip_compat.h)
+
 # For the multimeter plugin
 have_termios_h="no"
 AC_CHECK_HEADERS(termios.h, [have_termios_h="yes"])
@@ -1225,6 +1228,7 @@ AC_CHECK_MEMBERS([struct kinfo_proc.ki_pid, struct kinfo_proc.ki_rssize, struct
                have_struct_kinfo_proc_freebsd="no"
        ],
        [
+AC_INCLUDES_DEFAULT
 #include <kvm.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
@@ -1241,6 +1245,7 @@ AC_CHECK_MEMBERS([struct kinfo_proc.kp_proc, struct kinfo_proc.kp_eproc],
                have_struct_kinfo_proc_openbsd="no"
        ],
        [
+AC_INCLUDES_DEFAULT
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #include <kvm.h>
@@ -1900,10 +1905,12 @@ fi
 # This could be in iptc or ip4tc
 if test "x$with_libiptc" = "xpkgconfig"
 then
+       SAVE_LIBS="$LIBS"
        AC_SEARCH_LIBS(iptc_init, [iptc ip4tc],
                        [with_libiptc="pkgconfig"],
                        [with_libiptc="no"],
                        [$with_libiptc_libs])
+       LIBS="$SAVE_LIBS"
 fi
 if test "x$with_libiptc" = "xpkgconfig"
 then
@@ -2502,6 +2509,76 @@ then
 fi
 if test "x$with_libnetlink" = "xyes"
 then
+       SAVE_CFLAGS="$CFLAGS"
+       CFLAGS="$CFLAGS $with_libnetlink_cflags"
+
+       AC_CACHE_CHECK(
+               [if function 'rtnl_dump_filter' expects five arguments],
+               [c_cv_rtnl_dump_filter_five_args],
+               AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+                               [
+AC_INCLUDES_DEFAULT
+#include <asm/types.h>
+#include <sys/socket.h>
+#if HAVE_LIBNETLINK_H
+# include <libnetlink.h>
+#elif HAVE_IPROUTE_LIBNETLINK_H
+# include <iproute/libnetlink.h>
+#elif HAVE_LINUX_LIBNETLINK_H
+# include <linux/libnetlink.h>
+#endif
+                               ],
+                               [
+if (rtnl_dump_filter(NULL, NULL, NULL, NULL, NULL))
+       return 1;
+return 0;
+                               ]
+                       )],
+                       [c_cv_rtnl_dump_filter_five_args="yes"],
+                       [c_cv_rtnl_dump_filter_five_args="no"]
+               )
+       )
+
+       AC_CACHE_CHECK(
+               [if function 'rtnl_dump_filter' expects three arguments],
+               [c_cv_rtnl_dump_filter_three_args],
+               AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+                               [
+AC_INCLUDES_DEFAULT
+#include <asm/types.h>
+#include <sys/socket.h>
+#if HAVE_LIBNETLINK_H
+# include <libnetlink.h>
+#elif HAVE_IPROUTE_LIBNETLINK_H
+# include <iproute/libnetlink.h>
+#elif HAVE_LINUX_LIBNETLINK_H
+# include <linux/libnetlink.h>
+#endif
+                               ],
+                               [
+if (rtnl_dump_filter(NULL, NULL, NULL))
+       return 1;
+return 0;
+                               ]
+                       )],
+                       [c_cv_rtnl_dump_filter_three_args="yes"],
+                       [c_cv_rtnl_dump_filter_three_args="no"]
+               )
+       )
+
+       CFLAGS="$SAVE_CFLAGS"
+
+       if test "x$c_cv_rtnl_dump_filter_five_args" = "xyes"
+       then
+               AC_DEFINE(RTNL_DUMP_FILTER_FIVE_ARGS, 1,
+                               [Define to 1 if function 'rtnl_dump_filter' expects five arguments.])
+       fi
+       if test "x$c_cv_rtnl_dump_filter_three_args" = "xyes"
+       then
+               AC_DEFINE(RTNL_DUMP_FILTER_THREE_ARGS, 1,
+                               [Define to 1 if function 'rtnl_dump_filter' expects three arguments.])
+       fi
+
        BUILD_WITH_LIBNETLINK_CFLAGS="$with_libnetlink_cflags"
        BUILD_WITH_LIBNETLINK_LIBS="$with_libnetlink_libs"
        AC_SUBST(BUILD_WITH_LIBNETLINK_CFLAGS)
@@ -2909,7 +2986,7 @@ AM_CONDITIONAL(BUILD_WITH_LIBPCAP, test "x$with_libpcap" = "xyes")
 perl_interpreter="perl"
 AC_ARG_WITH(libperl, [AS_HELP_STRING([--with-libperl@<:@=PREFIX@:>@], [Path to libperl.])],
 [
-       if test -x "$withval"
+       if test -f "$withval" && test -x "$withval"
        then
                perl_interpreter="$withval"
                with_libperl="yes"
@@ -4057,7 +4134,7 @@ AC_ARG_WITH(libvarnish, [AS_HELP_STRING([--with-libvarnish@<:@=PREFIX@:>@], [Pat
        then
                AC_MSG_NOTICE([Not checking for libvarnish: Manually configured])
                with_libvarnish_cflags="-I$withval/include"
-               with_libvarnish_libs="-L$withval/lib -lvarnish -lvarnishcompat -lvarnishapi"
+               with_libvarnish_libs="-L$withval/lib -lvarnishapi"
                with_libvarnish="yes"
        fi; fi; fi
 ],
@@ -4560,11 +4637,13 @@ fi
 if test "x$with_perfstat" = "xyes"
 then
        plugin_cpu="yes"
+       plugin_contextswitch="yes"
        plugin_disk="yes"
        plugin_memory="yes"
        plugin_swap="yes"
        plugin_interface="yes"
        plugin_load="yes"
+       plugin_uptime="yes"
 fi
 
 if test "x$with_procinfo" = "xyes"
index bc1fe9ff10d384d16bc212f01cb20a4e2b0903cd..1ebf1f146e6332ce88f90b894ec233bbbc196946 100644 (file)
@@ -101,3 +101,8 @@ solaris-smf
 -----------
   Manifest file for the Solaris SMF system and detailed information on how to
 register collectd as a service with this system.
+
+collectd.service
+----------------
+  Service file for systemd. Please ship this file as
+  /lib/systemd/system/collectd.service in any linux package of collectd.
diff --git a/contrib/collectd.service b/contrib/collectd.service
new file mode 100644 (file)
index 0000000..ee4d596
--- /dev/null
@@ -0,0 +1,15 @@
+[Unit]
+Description=statistics collection daemon
+Documentation=man:collectd(1)
+After=local-fs.target network.target
+Requires=local-fs.target network.target
+
+[Service]
+ExecStart=/usr/sbin/collectd -C /etc/collectd/collectd.conf -f
+Restart=always
+RestartSec=10
+StandardOutput=syslog
+StandardError=syslog
+
+[Install]
+WantedBy=multi-user.target
index 445b1838d0256dce0ce425daa2aadd8e0cdf5696..9af0fb008a72790e48562e7e6440c3bec8c6dd2a 100644 (file)
@@ -4,19 +4,23 @@
 #
 # Copyright Â© 2009 Adrian Perez <aperez@igalia.com>
 #
-# Distributed under terms of the GPLv2 license.
+# Distributed under terms of the GPLv2 license or newer.
+# 
+# Frank Marien (frank@apsu.be) 6 Sep 2012
+# - quick fixes for 5.1 binary protocol
+# - updated to python 3
+# - fixed for larger packet sizes (possible on lo interface)
+# - fixed comment typo (decode_network_string decodes a string)
 
 """
 Collectd network protocol implementation.
 """
 
-import socket
-import struct
-
+import socket,struct,sys
 try:
-    from cStringIO import StringIO
+  from io import StringIO
 except ImportError:
-    from StringIO import StringIO
+  from cStringIO import StringIO
 
 from datetime import datetime
 from copy import deepcopy
@@ -31,17 +35,19 @@ DEFAULT_IPv4_GROUP = "239.192.74.66"
 DEFAULT_IPv6_GROUP = "ff18::efc0:4a42"
 """Default IPv6 multicast group"""
 
-
+HR_TIME_DIV = (2.0**30)
 
 # Message kinds
 TYPE_HOST            = 0x0000
 TYPE_TIME            = 0x0001
+TYPE_TIME_HR         = 0x0008
 TYPE_PLUGIN          = 0x0002
 TYPE_PLUGIN_INSTANCE = 0x0003
 TYPE_TYPE            = 0x0004
 TYPE_TYPE_INSTANCE   = 0x0005
 TYPE_VALUES          = 0x0006
 TYPE_INTERVAL        = 0x0007
+TYPE_INTERVAL_HR     = 0x0009
 
 # For notifications
 TYPE_MESSAGE         = 0x0100
@@ -50,14 +56,14 @@ TYPE_SEVERITY        = 0x0101
 # DS kinds
 DS_TYPE_COUNTER      = 0
 DS_TYPE_GAUGE        = 1
-
+DS_TYPE_DERIVE       = 2
+DS_TYPE_ABSOLUTE     = 3
 
 header = struct.Struct("!2H")
 number = struct.Struct("!Q")
 short  = struct.Struct("!H")
 double = struct.Struct("<d")
 
-
 def decode_network_values(ptype, plen, buf):
     """Decodes a list of DS values in collectd network format
     """
@@ -70,13 +76,19 @@ def decode_network_values(ptype, plen, buf):
     assert double.size == number.size
 
     result = []
-    for dstype in map(ord, buf[header.size+short.size:off]):
+    for dstype in buf[header.size+short.size:off]:
         if dstype == DS_TYPE_COUNTER:
             result.append((dstype, number.unpack_from(buf, off)[0]))
             off += valskip
         elif dstype == DS_TYPE_GAUGE:
             result.append((dstype, double.unpack_from(buf, off)[0]))
             off += valskip
+        elif dstype == DS_TYPE_DERIVE:
+            result.append((dstype, number.unpack_from(buf, off)[0]))
+            off += valskip
+        elif dstype == DS_TYPE_ABSOLUTE:
+            result.append((dstype, number.unpack_from(buf, off)[0]))
+            off += valskip
         else:
             raise ValueError("DS type %i unsupported" % dstype)
 
@@ -84,13 +96,13 @@ def decode_network_values(ptype, plen, buf):
 
 
 def decode_network_number(ptype, plen, buf):
-    """Decodes a number (64-bit unsigned) in collectd network format.
+    """Decodes a number (64-bit unsigned) from collectd network format.
     """
     return number.unpack_from(buf, header.size)[0]
 
 
 def decode_network_string(msgtype, plen, buf):
-    """Decodes a floating point number (64-bit) in collectd network format.
+    """Decodes a string from collectd network format.
     """
     return buf[header.size:plen-1]
 
@@ -99,7 +111,9 @@ def decode_network_string(msgtype, plen, buf):
 _decoders = {
     TYPE_VALUES         : decode_network_values,
     TYPE_TIME           : decode_network_number,
+    TYPE_TIME_HR        : decode_network_number,
     TYPE_INTERVAL       : decode_network_number,
+    TYPE_INTERVAL_HR    : decode_network_number,
     TYPE_HOST           : decode_network_string,
     TYPE_PLUGIN         : decode_network_string,
     TYPE_PLUGIN_INSTANCE: decode_network_string,
@@ -115,6 +129,7 @@ def decode_network_packet(buf):
     """
     off = 0
     blen = len(buf)
+
     while off < blen:
         ptype, plen = header.unpack_from(buf, off)
 
@@ -128,9 +143,6 @@ def decode_network_packet(buf):
         off += plen
 
 
-
-
-
 class Data(object):
     time = 0
     host = None
@@ -140,7 +152,7 @@ class Data(object):
     typeinstance = None
 
     def __init__(self, **kw):
-        [setattr(self, k, v) for k, v in kw.iteritems()]
+        [setattr(self, k, v) for k, v in kw.items()]
 
     @property
     def datetime(self):
@@ -150,19 +162,19 @@ class Data(object):
     def source(self):
         buf = StringIO()
         if self.host:
-            buf.write(self.host)
+            buf.write(str(self.host))
         if self.plugin:
             buf.write("/")
-            buf.write(self.plugin)
+            buf.write(str(self.plugin))
         if self.plugininstance:
             buf.write("/")
-            buf.write(self.plugininstance)
+            buf.write(str(self.plugininstance))
         if self.type:
             buf.write("/")
-            buf.write(self.type)
+            buf.write(str(self.type))
         if self.typeinstance:
             buf.write("/")
-            buf.write(self.typeinstance)
+            buf.write(str(self.typeinstance))
         return buf.getvalue()
 
     def __str__(self):
@@ -215,8 +227,12 @@ def interpret_opcodes(iterable):
     for kind, data in iterable:
         if kind == TYPE_TIME:
             vl.time = nt.time = data
+        elif kind == TYPE_TIME_HR:
+            vl.time = nt.time = data / HR_TIME_DIV
         elif kind == TYPE_INTERVAL:
             vl.interval = data
+        elif kind == TYPE_INTERVAL_HR:
+            vl.interval = data / HR_TIME_DIV
         elif kind == TYPE_HOST:
             vl.host = nt.host = data
         elif kind == TYPE_PLUGIN:
@@ -248,7 +264,7 @@ class Reader(object):
     host = None
     port = DEFAULT_PORT
 
-    BUFFER_SIZE = 1024
+    BUFFER_SIZE = 16384
 
 
     def __init__(self, host=None, port=DEFAULT_PORT, multicast=False):
@@ -311,8 +327,6 @@ class Reader(object):
         """
         if iterable is None:
             iterable = self.decode()
-        if isinstance(iterable, basestring):
+        if isinstance(iterable, str):
             iterable = self.decode(iterable)
         return interpret_opcodes(iterable)
-
-
index 027961fa43ac73de432e0e7435768852c423f37b..a85027176c426dfd0f4e59c8fb109953d7237d42 100755 (executable)
@@ -240,6 +240,50 @@ HTML
   $html_started = 0;
 }
 
+sub contains_invalid_chars
+{
+  my $str = shift;
+
+  for (split (m//, $str))
+  {
+    my $n = ord ($_);
+
+    # Whitespace is allowed.
+    if (($n >= 9) && ($n <= 13))
+    {
+      next;
+    }
+    elsif ($n < 32)
+    {
+      return (1);
+    }
+  }
+
+  return;
+}
+
+sub contains_invalid_chars
+{
+  my $str = shift;
+
+  for (split (m//, $str))
+  {
+    my $n = ord ($_);
+
+    # Whitespace is allowed.
+    if (($n >= 9) && ($n <= 13))
+    {
+      next;
+    }
+    elsif ($n < 32)
+    {
+      return (1);
+    }
+  }
+
+  return;
+}
+
 sub show_selector
 {
   my $timespan_selection = get_timespan_selection ();
@@ -254,6 +298,7 @@ sub show_selector
 HTML
   for (sort (keys %$host_selection))
   {
+    next if contains_invalid_chars ($_);
     my $host = encode_entities ($_);
     my $selected = $host_selection->{$_}
     ? ' selected="selected"'
@@ -266,6 +311,7 @@ HTML
 HTML
   for (sort (keys %$plugin_selection))
   {
+    next if contains_invalid_chars ($_);
     my $plugin = encode_entities ($_);
     my $selected = $plugin_selection->{$_}
     ? ' selected="selected"'
@@ -278,6 +324,7 @@ HTML
 HTML
   for (sort { $TimeSpans->{$a} <=> $TimeSpans->{$b} } (keys (%$TimeSpans)))
   {
+    next if contains_invalid_chars ($_);
     my $name = encode_entities ($_);
     my $value = $TimeSpans->{$_};
     my $selected = ($value == $timespan_selection)
@@ -304,6 +351,7 @@ sub action_list_hosts
   for (sort @hosts)
   {
     my $url = encode_entities (script_name () . "?action=show_selection;hostname=$_");
+    next if contains_invalid_chars ($_);
     my $name = encode_entities ($_);
     print qq#      <li><a href="$url">$name</a></li>\n#;
   }
index 0fbd0d3593333354ad3f2ac1ad41e3b37dd485dd..4a70c41abef32245152a05c030b335ac5012970b 100644 (file)
@@ -34,7 +34,7 @@ sub new
   my $obj = Collectd::Graph::Type->new (@_);
   $obj->{'data_sources'} = [qw(free used)];
   $obj->{'rrd_opts'} = ['-v', 'Bytes'];
-  $obj->{'rrd_title'} = 'Disk space ({type_instance})';
+  $obj->{'rrd_title'} = 'Disk space ({instance})';
   $obj->{'rrd_format'} = '%5.1lf%sB';
   $obj->{'colors'} = [qw(00b000 ff0000)];
 
@@ -58,7 +58,7 @@ sub getRRDArgs
   my $faded_green = get_faded_color ('00ff00');
   my $faded_red = get_faded_color ('ff0000');
 
-  return (['-t', 'Diskspace (' . $ident->{'type_instance'} . ')', '-v', 'Bytes', '-l', '0',
+  return (['-t', $obj->getTitle ($ident), '-v', 'Bytes', '-l', '0',
     "DEF:free_min=${filename}:free:MIN",
     "DEF:free_avg=${filename}:free:AVERAGE",
     "DEF:free_max=${filename}:free:MAX",
index d3ff796d3ed7d1139edacfebd638746bb8062c5d..c2a95558b236e96477e94884c0ab703ff4fd942a 100755 (executable)
@@ -33,6 +33,7 @@ use File::Basename ('dirname');
 
 our $InDir = '/var/lib/collectd';
 our $RRDtool = 'rrdtool';
+our $RRDFilter = 'rrd_filter.px';
 
 our %TypesCounterToDerive = # {{{
 (
@@ -184,7 +185,15 @@ sub handle_file # {{{
   {
     my $dir = join ('/', @path);
     print "mkdir -p \"$dir/$plugin-$type_inst\"\n";
-    print "mv \"$path\" \"$dir/$plugin-$type_inst/$type.rrd\"\n";
+    if (($plugin eq 'df') and ($type eq 'df'))
+    {
+      print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-free.rrd\" --map free:value\n";
+      print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-used.rrd\" --map used:value\n";
+    }
+    else
+    {
+      print "mv \"$path\" \"$dir/$plugin-$type_inst/$type.rrd\"\n";
+    }
   }
 } # }}} sub handle_file
 
@@ -223,10 +232,12 @@ migrate-4-5.px [OPTIONS]
 
 Valid options are:
 
-  --indir <dir>      Source directory
-                     Default: $InDir
-  --rrdtool <path>   Path to the RRDtool binary
-                     Default: $RRDtool
+  --indir <dir>         Source directory
+                        Default: $InDir
+  --rrdtool <path>      Path to the RRDtool binary
+                        Default: $RRDtool
+  --rrdfilter <path>    Path to the rrd_filter.px script
+                        Default: $RRDFilter
 
 EOF
   exit (1);
@@ -234,8 +245,11 @@ EOF
 
 GetOptions ("indir|i=s" => \$InDir,
         "rrdtool=s" => \$RRDtool,
+        "rrdfilter=s" => \$RRDFilter,
         "help|h" => \&exit_usage) or exit_usage ();
 
+print "#!/bin/bash\n\n";
+
 scan_dir ($InDir);
 
 # vim: set sw=2 sts=2 et fdm=marker :
index 9d528c11c2a95acfffbbaf88b9eaba6380efd622..f4c699a35b1fdeb06f9da659a6318b3f86b21895 100644 (file)
@@ -43,7 +43,7 @@ collectd_SOURCES = collectd.c collectd.h \
 collectd_CPPFLAGS =  $(AM_CPPFLAGS) $(LTDLINCL)
 collectd_CFLAGS = $(AM_CFLAGS)
 collectd_LDFLAGS = -export-dynamic
-collectd_LDADD =
+collectd_LDADD = -lm
 collectd_DEPENDENCIES =
 
 # Link to these libraries..
@@ -70,7 +70,6 @@ collectd_LDADD += -ldevinfo
 endif
 if BUILD_AIX
 collectd_LDFLAGS += -Wl,-bexpall,-brtllib
-collectd_LDADD += -lm
 endif
 
 # The daemon needs to call sg_init, so we need to link it against libstatgrab,
@@ -134,6 +133,7 @@ if BUILD_PLUGIN_AMQP
 pkglib_LTLIBRARIES += amqp.la
 amqp_la_SOURCES = amqp.c \
                  utils_cmd_putval.c utils_cmd_putval.h \
+                 utils_format_graphite.c utils_format_graphite.h \
                  utils_format_json.c utils_format_json.h
 amqp_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
 amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
@@ -223,6 +223,10 @@ if BUILD_PLUGIN_CONTEXTSWITCH
 pkglib_LTLIBRARIES += contextswitch.la
 contextswitch_la_SOURCES = contextswitch.c
 contextswitch_la_LDFLAGS = -module -avoid-version
+contextswitch_la_LIBADD =
+if BUILD_WITH_PERFSTAT
+contextswitch_la_LIBADD += -lperfstat
+endif
 collectd_LDADD += "-dlopen" contextswitch.la
 collectd_DEPENDENCIES += contextswitch.la
 endif
@@ -1202,6 +1206,9 @@ uptime_la_LIBADD =
 if BUILD_WITH_LIBKSTAT
 uptime_la_LIBADD += -lkstat
 endif
+if BUILD_WITH_PERFSTAT
+uptime_la_LIBADD += -lperfstat
+endif
 collectd_LDADD += "-dlopen" uptime.la
 collectd_DEPENDENCIES += uptime.la
 endif
@@ -1267,7 +1274,8 @@ endif
 if BUILD_PLUGIN_WRITE_GRAPHITE
 pkglib_LTLIBRARIES += write_graphite.la
 write_graphite_la_SOURCES = write_graphite.c \
-                       utils_format_json.c utils_format_json.h
+                        utils_format_graphite.c utils_format_graphite.h \
+                        utils_format_json.c utils_format_json.h
 write_graphite_la_LDFLAGS = -module -avoid-version
 collectd_LDADD += "-dlopen" write_graphite.la
 collectd_DEPENDENCIES += write_graphite.la
@@ -1380,7 +1388,7 @@ EXTRA_DIST +=   collectd.conf.pod \
        fi
 
 pinba.pb-c.c pinba.pb-c.h: pinba.proto
-       protoc-c --c_out $(builddir) pinba.proto
+       protoc-c --c_out . pinba.proto
 
 install-exec-hook:
        $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
@@ -1395,6 +1403,11 @@ install-exec-hook:
        $(INSTALL) -m 0644 $(srcdir)/postgresql_default.conf \
                $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
 
+uninstall-hook:
+       rm -f $(DESTDIR)$(pkgdatadir)/types.db;
+       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 \
index 55d2a2ceff04f3772e43c21c4288ec6d97c1ddb2..c9e46c45df0cac7ef0e0cc4f3bdd2e1bda8ad96e 100644 (file)
@@ -31,6 +31,7 @@
 #include "plugin.h"
 #include "utils_cmd_putval.h"
 #include "utils_format_json.h"
+#include "utils_format_graphite.h"
 
 #include <pthread.h>
 
@@ -42,8 +43,9 @@
 #define CAMQP_DM_VOLATILE   1
 #define CAMQP_DM_PERSISTENT 2
 
-#define CAMQP_FORMAT_COMMAND 1
-#define CAMQP_FORMAT_JSON    2
+#define CAMQP_FORMAT_COMMAND    1
+#define CAMQP_FORMAT_JSON       2
+#define CAMQP_FORMAT_GRAPHITE   3
 
 #define CAMQP_CHANNEL 1
 
@@ -68,6 +70,10 @@ struct camqp_config_s
     uint8_t delivery_mode;
     _Bool   store_rates;
     int     format;
+    /* publish & graphite format only */
+    char    *prefix;
+    char    *postfix;
+    char    escape_char;
 
     /* subscribe only */
     char   *exchange_type;
@@ -129,6 +135,9 @@ static void camqp_config_free (void *ptr) /* {{{ */
     sfree (conf->exchange_type);
     sfree (conf->queue);
     sfree (conf->routing_key);
+    sfree (conf->prefix);
+    sfree (conf->postfix);
+
 
     sfree (conf);
 } /* }}} void camqp_config_free */
@@ -641,6 +650,7 @@ static void *camqp_subscribe_thread (void *user_data) /* {{{ */
 
     camqp_config_free (conf);
     pthread_exit (NULL);
+    return (NULL);
 } /* }}} void *camqp_subscribe_thread */
 
 static int camqp_subscribe_init (camqp_config_t *conf) /* {{{ */
@@ -698,6 +708,8 @@ static int camqp_write_locked (camqp_config_t *conf, /* {{{ */
         props.content_type = amqp_cstring_bytes("text/collectd");
     else if (conf->format == CAMQP_FORMAT_JSON)
         props.content_type = amqp_cstring_bytes("application/json");
+    else if (conf->format == CAMQP_FORMAT_GRAPHITE)
+        props.content_type = amqp_cstring_bytes("text/graphite");
     else
         assert (23 == 42);
     props.delivery_mode = conf->delivery_mode;
@@ -776,6 +788,18 @@ static int camqp_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
         format_json_value_list (buffer, &bfill, &bfree, ds, vl, conf->store_rates);
         format_json_finalize (buffer, &bfill, &bfree);
     }
+    else if (conf->format == CAMQP_FORMAT_GRAPHITE)
+    {
+        status = format_graphite (buffer, sizeof (buffer), ds, vl,
+                    conf->prefix, conf->postfix, conf->escape_char,
+                    conf->store_rates);
+        if (status != 0)
+        {
+            ERROR ("amqp plugin: format_graphite failed with status %i.",
+                    status);
+            return (status);
+        }
+    }
     else
     {
         ERROR ("amqp plugin: Invalid format (%i).", conf->format);
@@ -808,6 +832,8 @@ static int camqp_config_set_format (oconfig_item_t *ci, /* {{{ */
         conf->format = CAMQP_FORMAT_COMMAND;
     else if (strcasecmp ("JSON", string) == 0)
         conf->format = CAMQP_FORMAT_JSON;
+    else if (strcasecmp ("Graphite", string) == 0)
+        conf->format = CAMQP_FORMAT_GRAPHITE;
     else
     {
         WARNING ("amqp plugin: Invalid format string: %s",
@@ -848,6 +874,10 @@ static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */
     /* publish only */
     conf->delivery_mode = CAMQP_DM_VOLATILE;
     conf->store_rates = 0;
+    /* publish & graphite only */
+    conf->prefix = NULL;
+    conf->postfix = NULL;
+    conf->escape_char = '_';
     /* subscribe only */
     conf->exchange_type = NULL;
     conf->queue = NULL;
@@ -905,6 +935,20 @@ static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */
             status = cf_util_get_boolean (child, &conf->store_rates);
         else if ((strcasecmp ("Format", child->key) == 0) && publish)
             status = camqp_config_set_format (child, conf);
+        else if ((strcasecmp ("GraphitePrefix", child->key) == 0) && publish)
+            status = cf_util_get_string (child, &conf->prefix);
+        else if ((strcasecmp ("GraphitePostfix", child->key) == 0) && publish)
+            status = cf_util_get_string (child, &conf->postfix);
+        else if ((strcasecmp ("GraphiteEscapeChar", child->key) == 0) && publish)
+        {
+            char *tmp_buff = NULL;
+            status = cf_util_get_string (child, &tmp_buff);
+            if (strlen (tmp_buff) > 1)
+                WARNING ("amqp plugin: The option \"GraphiteEscapeChar\" handles "
+                        "only one character. Others will be ignored.");
+            conf->escape_char = tmp_buff[0];
+            sfree (tmp_buff);
+        }
         else
             WARNING ("amqp plugin: Ignoring unknown "
                     "configuration option \"%s\".", child->key);
index a0629d5f6ae0a87e13b08f1e53f6d69b0c1a85f3..4fbbde63aad113dcbefdbc2db47e545ca3b5c241 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * collectd - src/apcups.c
- * Copyright (C) 2006-2007  Florian octo Forster
+ * Copyright (C) 2006-2012  Florian octo Forster
  * Copyright (C) 2006       Anthony Gialluca <tonyabg at charter.net>
  * Copyright (C) 2000-2004  Kern Sibbald
  * Copyright (C) 1996-1999  Andre M. Hedrick <andre at suse.com>
@@ -73,6 +73,10 @@ static int   conf_port = NISPORT;
 
 static int global_sockfd = -1;
 
+static int count_retries = 0;
+static int count_iterations = 0;
+static _Bool close_socket = 0;
+
 static const char *config_keys[] =
 {
        "Host",
@@ -81,26 +85,31 @@ static const char *config_keys[] =
 };
 static int config_keys_num = 2;
 
-/* Close the network connection */
-static int apcups_shutdown (void)
+static int net_shutdown (int *fd)
 {
        uint16_t packet_size = 0;
 
-       if (global_sockfd < 0)
-               return (0);
+       if ((fd == NULL) || (*fd < 0))
+               return (EINVAL);
 
-       DEBUG ("Gracefully shutting down socket %i.", global_sockfd);
+       swrite (*fd, (void *) &packet_size, sizeof (packet_size));
+       close (*fd);
+       *fd = -1;
 
-       /* send EOF sentinel */
-       swrite (global_sockfd, (void *) &packet_size, sizeof (packet_size));
+       return (0);
+} /* int net_shutdown */
 
-       close (global_sockfd);
-       global_sockfd = -1;
+/* Close the network connection */
+static int apcups_shutdown (void)
+{
+       if (global_sockfd < 0)
+               return (0);
 
+       net_shutdown (&global_sockfd);
        return (0);
 } /* int apcups_shutdown */
 
-/*     
+/*
  * Open a TCP connection to the UPS network server
  * Returns -1 on error
  * Returns socket file descriptor otherwise
@@ -170,7 +179,7 @@ static int net_open (char *host, int port)
        return (sd);
 } /* int net_open (char *host, char *service, int port) */
 
-/* 
+/*
  * Receive a message from the other end. Each message consists of
  * two packets. The first is a header that contains the size
  * of the data that follows in the second packet.
@@ -186,6 +195,7 @@ static int net_recv (int *sockfd, char *buf, int buflen)
        /* get data size -- in short */
        if (sread (*sockfd, (void *) &packet_size, sizeof (packet_size)) != 0)
        {
+               close (*sockfd);
                *sockfd = -1;
                return (-1);
        }
@@ -193,7 +203,11 @@ static int net_recv (int *sockfd, char *buf, int buflen)
        packet_size = ntohs (packet_size);
        if (packet_size > buflen)
        {
-               DEBUG ("record length too large");
+               ERROR ("apcups plugin: Received %"PRIu16" bytes of payload "
+                               "but have only %i bytes of buffer available.",
+                               packet_size, buflen);
+               close (*sockfd);
+               *sockfd = -1;
                return (-2);
        }
 
@@ -203,6 +217,7 @@ static int net_recv (int *sockfd, char *buf, int buflen)
        /* now read the actual data */
        if (sread (*sockfd, (void *) buf, packet_size) != 0)
        {
+               close (*sockfd);
                *sockfd = -1;
                return (-1);
        }
@@ -229,6 +244,7 @@ static int net_send (int *sockfd, char *buff, int len)
 
        if (swrite (*sockfd, (void *) &packet_size, sizeof (packet_size)) != 0)
        {
+               close (*sockfd);
                *sockfd = -1;
                return (-1);
        }
@@ -236,6 +252,7 @@ static int net_send (int *sockfd, char *buff, int len)
        /* send data packet */
        if (swrite (*sockfd, (void *) buff, len) != 0)
        {
+               close (*sockfd);
                *sockfd = -1;
                return (-2);
        }
@@ -253,6 +270,8 @@ static int apc_query_server (char *host, int port,
        char   *toksaveptr;
        char   *key;
        double  value;
+       _Bool retry = 1;
+       int status;
 
 #if APCMAIN
 # define PRINT_VALUE(name, val) printf("  Found property: name = %s; value = %f;\n", name, val)
@@ -260,21 +279,51 @@ static int apc_query_server (char *host, int port,
 # define PRINT_VALUE(name, val) /**/
 #endif
 
-       if (global_sockfd < 0)
+       while (retry)
        {
-               global_sockfd = net_open (host, port);
                if (global_sockfd < 0)
                {
-                       ERROR ("apcups plugin: Connecting to the "
-                                       "apcupsd failed.");
+                       global_sockfd = net_open (host, port);
+                       if (global_sockfd < 0)
+                       {
+                               ERROR ("apcups plugin: Connecting to the "
+                                               "apcupsd failed.");
+                               return (-1);
+                       }
+               }
+
+
+               status = net_send (&global_sockfd, "status", strlen ("status"));
+               if (status != 0)
+               {
+                       /* net_send is closing the socket on error. */
+                       assert (global_sockfd < 0);
+                       if (retry)
+                       {
+                               retry = 0;
+                               count_retries++;
+                               continue;
+                       }
+
+                       ERROR ("apcups plugin: Writing to the socket failed.");
                        return (-1);
                }
-       }
 
-       if (net_send (&global_sockfd, "status", 6) < 0)
+               break;
+       } /* while (retry) */
+
+        /* When collectd's collection interval is larger than apcupsd's
+         * timeout, we would have to retry / re-connect each iteration. Try to
+         * detect this situation and shut down the socket gracefully in that
+         * case. Otherwise, keep the socket open to avoid overhead. */
+       count_iterations++;
+       if ((count_iterations == 10) && (count_retries > 2))
        {
-               ERROR ("apcups plugin: Writing to the socket failed.");
-               return (-1);
+               NOTICE ("apcups plugin: There have been %i retries in the "
+                               "first %i iterations. Will close the socket "
+                               "in future iterations.",
+                               count_retries, count_iterations);
+               close_socket = 1;
        }
 
        while ((n = net_recv (&global_sockfd, recvline, sizeof (recvline) - 1)) > 0)
@@ -298,7 +347,7 @@ static int apc_query_server (char *host, int port,
 
                        if (strcmp ("LINEV", key) == 0)
                                apcups_detail->linev = value;
-                       else if (strcmp ("BATTV", key) == 0) 
+                       else if (strcmp ("BATTV", key) == 0)
                                apcups_detail->battv = value;
                        else if (strcmp ("ITEMP", key) == 0)
                                apcups_detail->itemp = value;
@@ -316,10 +365,16 @@ static int apc_query_server (char *host, int port,
                        tokptr = strtok_r (NULL, ":", &toksaveptr);
                } /* while (tokptr != NULL) */
        }
-       
+       status = errno; /* save errno, net_shutdown() may re-set it. */
+
+       if (close_socket)
+               net_shutdown (&global_sockfd);
+
        if (n < 0)
        {
-               WARNING ("apcups plugin: Error reading from socket");
+               char errbuf[1024];
+               ERROR ("apcups plugin: Reading from socket failed: %s",
+                               sstrerror (status, errbuf, sizeof (errbuf)));
                return (-1);
        }
 
@@ -398,12 +453,12 @@ static int apcups_read (void)
        apcups_detail.timeleft =   -1.0;
        apcups_detail.itemp    = -300.0;
        apcups_detail.linefreq =   -1.0;
-  
+
        status = apc_query_server (conf_host == NULL
                        ? APCUPS_DEFAULT_HOST
                        : conf_host,
                        conf_port, &apcups_detail);
+
        /*
         * if we did not connect then do not bother submitting
         * zeros. We want rrd files to have NAN.
index d33d1d6685ff4755d9ab460a526313b468d6f71d..ceb184b012879d475e90f66108ac732ae2a193b3 100644 (file)
@@ -79,6 +79,7 @@ static void sig_usr1_handler (int __attribute__((unused)) signal)
        pthread_attr_init (&attr);
        pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
        pthread_create (&thread, &attr, do_flush, NULL);
+       pthread_attr_destroy (&attr);
 }
 
 static int init_hostname (void)
@@ -182,10 +183,11 @@ static int init_global_variables (void)
 
 static int change_basedir (const char *orig_dir)
 {
-       char *dir = strdup (orig_dir);
-       int dirlen;
+       char *dir;
+       size_t dirlen;
        int status;
 
+       dir = strdup (orig_dir);
        if (dir == NULL)
        {
                char errbuf[1024];
@@ -202,39 +204,41 @@ static int change_basedir (const char *orig_dir)
                return (-1);
 
        status = chdir (dir);
-       free (dir);
+       if (status == 0)
+       {
+               free (dir);
+               return (0);
+       }
+       else if (errno != ENOENT)
+       {
+               char errbuf[1024];
+               ERROR ("change_basedir: chdir (%s): %s", dir,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               free (dir);
+               return (-1);
+       }
 
+       status = mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO);
        if (status != 0)
        {
-               if (errno == ENOENT)
-               {
-                       if (mkdir (orig_dir, 0755) == -1)
-                       {
-                               char errbuf[1024];
-                               ERROR ("change_basedir: mkdir (%s): %s", orig_dir,
-                                               sstrerror (errno, errbuf,
-                                                       sizeof (errbuf)));
-                               return (-1);
-                       }
-                       else if (chdir (orig_dir) == -1)
-                       {
-                               char errbuf[1024];
-                               ERROR ("chdir (%s): %s", orig_dir,
-                                               sstrerror (errno, errbuf,
-                                                       sizeof (errbuf)));
-                               return (-1);
-                       }
-               }
-               else
-               {
-                       char errbuf[1024];
-                       ERROR ("chdir (%s): %s", orig_dir,
-                                       sstrerror (errno, errbuf,
-                                               sizeof (errbuf)));
-                       return (-1);
-               }
+               char errbuf[1024];
+               ERROR ("change_basedir: mkdir (%s): %s", dir,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               free (dir);
+               return (-1);
+       }
+
+       status = chdir (dir);
+       if (status != 0)
+       {
+               char errbuf[1024];
+               ERROR ("change_basedir: chdir (%s): %s", dir,
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               free (dir);
+               return (-1);
        }
 
+       free (dir);
        return (0);
 } /* static int change_basedir (char *dir) */
 
index ebddb2b8e7d37df701ca96094ccb955a6abf41ae..9f5dedcdf0ad64d38566212bb53fdb4f48f03fea 100644 (file)
 #</Plugin>
 
 #<Plugin memcached>
-#      Host "127.0.0.1"
-#      Port "11211"
+#      <Instance "local">
+#              Host "127.0.0.1"
+#              Port "11211"
+#      </Instance>
 #</Plugin>
 
 #<Plugin modbus>
 #      Host "localhost"
 #      Port 123
 #      ReverseLookups false
+#      IncludeUnitID true
 #</Plugin>
 
 #<Plugin nut>
 
 #<Plugin "swap">
 #      ReportByDevice false
+#      ReportBytes true
 #</Plugin>
 
 #<Plugin "table">
index 284c36c4dea93d7ff66f6167a16fd8da4d527930..f6f61c7e3da30285d516663ab9d901fbed2cb9ce 100644 (file)
@@ -25,22 +25,32 @@ controls which plugins to load. These plugins ultimately define collectd's
 behavior.
 
 The syntax of this config file is similar to the config file of the famous
-B<Apache Webserver>. Each line contains either a key-value-pair or a
-section-start or -end. Empty lines and everything after the hash-symbol `#' is
-ignored. Values are either string, enclosed in double-quotes,
-(floating-point-)numbers or a boolean expression, i.E<nbsp>e. either B<true> or
-B<false>. String containing of only alphanumeric characters and underscores do
-not need to be quoted. Lines may be wrapped by using `\' as the last character
-before the newline. This allows long lines to be split into multiple lines.
-Quoted strings may be wrapped as well. However, those are treated special in
-that whitespace at the beginning of the following lines will be ignored, which
-allows for nicely indenting the wrapped lines.
-
-The configuration is read and processed in order, i.E<nbsp>e. from top to
-bottom. So the plugins are loaded in the order listed in this config file. It
-is a good idea to load any logging plugins first in order to catch messages
-from plugins during configuration. Also, the C<LoadPlugin> option B<must> occur
-B<before> the C<E<lt>Plugin ...E<gt>> block.
+I<Apache> webserver. Each line contains either an option (a key and a list of
+one or more values) or a section-start or -end. Empty lines and everything
+after a non-quoted hash-symbol (C<#>) is ignored. I<Keys> are unquoted
+strings, consisting only of alphanumeric characters and the underscore (C<_>)
+character. Keys are handled case insensitive by I<collectd> itself and all
+plugins included with it. I<Values> can either be an I<unquoted string>, a
+I<quoted string> (enclosed in double-quotes) a I<number> or a I<boolean>
+expression. I<Unquoted strings> consist of only alphanumeric characters and
+underscores (C<_>) and do not need to be quoted. I<Quoted strings> are
+enclosed in double quotes (C<">). You can use the backslash character (C<\>)
+to include double quotes as part of the string. I<Numbers> can be specified in
+decimal and floating point format (using a dot C<.> as decimal separator),
+hexadecimal when using the C<0x> prefix and octal with a leading zero (C<0>).
+I<Boolean> values are either B<true> or B<false>.
+
+Lines may be wrapped by using C<\> as the last character before the newline.
+This allows long lines to be split into multiple lines. Quoted strings may be
+wrapped as well. However, those are treated special in that whitespace at the
+beginning of the following lines will be ignored, which allows for nicely
+indenting the wrapped lines.
+
+The configuration is read and processed in order, i.e. from top to bottom. So
+the plugins are loaded in the order listed in this config file. It is a good
+idea to load any logging plugins first in order to catch messages from plugins
+during configuration. Also, the C<LoadPlugin> option B<must> occur B<before>
+the appropriate C<E<lt>Plugin ...E<gt>> block.
 
 =head1 GLOBAL OPTIONS
 
@@ -320,6 +330,8 @@ possibly filtering or messages.
  #   Persistent false
  #   Format "command"
  #   StoreRates false
+ #   GraphitePrefix "collectd."
+ #   GraphiteEscapeChar "_"
    </Publish>
    
    # Receive values from an AMQP broker
@@ -420,6 +432,10 @@ If set to B<JSON>, the values are encoded in the I<JavaScript Object Notation>,
 an easy and straight forward exchange format. The C<Content-Type> header field
 will be set to C<application/json>.
 
+If set to B<Graphite>, values are encoded in the I<Graphite> format, which is
+"<metric> <value> <timestamp>\n". The C<Content-Type> header field will be set to
+C<text/graphite>.
+
 A subscribing client I<should> use the C<Content-Type> header field to
 determine how to decode the values. Currently, the I<AMQP plugin> itself can
 only decode the B<Command> format.
@@ -434,6 +450,25 @@ 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> (Publish and 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> (Publish and 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> (Publish and 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>).
+
 =back
 
 =head2 Plugin C<apache>
@@ -2049,6 +2084,17 @@ The C<memcached plugin> connects to a memcached server and queries statistics
 about cache utilization, memory and bandwidth used.
 L<http://www.danga.com/memcached/>
 
+ <Plugin "memcached">
+   <Instance "name">
+     Host "memcache.example.com"
+     Port 11211
+   </Instance>
+ </Plugin>
+
+The plugin configuration consists of one or more B<Instance> blocks which
+specify one I<memcached> connection each. Within the B<Instance> blocks, the
+following options are allowed:
+
 =over 4
 
 =item B<Host> I<Hostname>
@@ -2059,6 +2105,11 @@ Hostname to connect to. Defaults to B<127.0.0.1>.
 
 TCP-Port to connect to. Defaults to B<11211>.
 
+=item B<Socket> I<Path>
+
+Connect to I<memcached> using the UNIX domain socket at I<Path>. If this
+setting is given, the B<Host> and B<Port> settings are ignored.
+
 =back
 
 =head2 Plugin C<modbus>
@@ -3153,6 +3204,16 @@ IP-address may be used in a filename it is recommended to disable reverse
 lookups. The default is to do reverse lookups to preserve backwards
 compatibility, though.
 
+=item B<IncludeUnitID> B<true>|B<false>
+
+When a peer is a refclock, include the unit ID in the I<type instance>.
+Defaults to B<false> for backward compatibility.
+
+If two refclock peers use the same driver and this is B<false>, the plugin will
+try to write simultaneous measurements from both to the same type instance.
+This will result in error messages in the log and only one set of measurements
+making it through.
+
 =back
 
 =head2 Plugin C<nut>
@@ -3653,6 +3714,11 @@ used, the parameter expands to "localhost".
 
 The name of the database of the current connection.
 
+=item I<instance>
+
+The name of the database plugin instance. See the B<Instance> option of the
+database specification below for details.
+
 =item I<username>
 
 The username used to connect to the database.
@@ -3811,6 +3877,13 @@ Specify the password to be used when connecting to the server.
 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>
@@ -4171,6 +4244,10 @@ The B<Port> option is the TCP port on which the Redis instance accepts
 connections. Either a service name of a port number may be given. Please note
 that numerical port numbers must be given as a string, too.
 
+=item B<Password> I<Password>
+
+Use I<Password> to authenticate when connecting to I<Redis>.
+
 =item B<Timeout> I<Timeout in miliseconds>
 
 The B<Timeout> option set the socket timeout for node response. Since the Redis
@@ -4228,6 +4305,50 @@ Enables or disables the creation of RRD files. If the daemon is not running
 locally, or B<DataDir> is set to a relative path, this will not work as
 expected. Default is B<true>.
 
+=item B<StepSize> I<Seconds>
+
+B<Force> the stepsize of newly created RRD-files. Ideally (and per default)
+this setting is unset and the stepsize is set to the interval in which the data
+is collected. Do not use this option unless you absolutely have to for some
+reason. Setting this option may cause problems with the C<snmp plugin>, the
+C<exec plugin> or when the daemon is set up to receive data from other hosts.
+
+=item B<HeartBeat> I<Seconds>
+
+B<Force> the heartbeat of newly created RRD-files. This setting should be unset
+in which case the heartbeat is set to twice the B<StepSize> which should equal
+the interval in which data is collected. Do not set this option unless you have
+a very good reason to do so.
+
+=item B<RRARows> I<NumRows>
+
+The C<rrdtool plugin> calculates the number of PDPs per CDP based on the
+B<StepSize>, this setting and a timespan. This plugin creates RRD-files with
+three times five RRAs, i. e. five RRAs with the CFs B<MIN>, B<AVERAGE>, and
+B<MAX>. The five RRAs are optimized for graphs covering one hour, one day, one
+week, one month, and one year.
+
+So for each timespan, it calculates how many PDPs need to be consolidated into
+one CDP by calculating:
+  number of PDPs = timespan / (stepsize * rrarows)
+
+Bottom line is, set this no smaller than the width of you graphs in pixels. The
+default is 1200.
+
+=item B<RRATimespan> I<Seconds>
+
+Adds an RRA-timespan, given in seconds. Use this option multiple times to have
+more then one RRA. If this option is never used, the built-in default of (3600,
+86400, 604800, 2678400, 31622400) is used.
+
+For more information on how RRA-sizes are calculated see B<RRARows> above.
+
+=item B<XFF> I<Factor>
+
+Set the "XFiles Factor". The default is 0.1. If unsure, don't set this option.
+I<Factor> must be in the range C<[0.0-1.0)>, i.e. between zero (inclusive) and
+one (exclusive).
+
 =back
 
 =head2 Plugin C<rrdtool>
@@ -4285,6 +4406,8 @@ For more information on how RRA-sizes are calculated see B<RRARows> above.
 =item B<XFF> I<Factor>
 
 Set the "XFiles Factor". The default is 0.1. If unsure, don't set this option.
+I<Factor> must be in the range C<[0.0-1.0)>, i.e. between zero (inclusive) and
+one (exclusive).
 
 =item B<CacheFlush> I<Seconds>
 
@@ -4400,6 +4523,11 @@ and available space of each device will be reported separately.
 This option is only available if the I<Swap plugin> can read C</proc/swaps>
 (under Linux) or use the L<swapctl(2)> mechanism (under I<Solaris>).
 
+=item B<ReportBytes> B<false>|B<true>
+
+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.
+
 =back
 
 =head2 Plugin C<syslog>
@@ -5030,7 +5158,7 @@ number.
 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 once component, for example C<host.cpu-0.cpu-idle>.
+instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
 
 =item B<AlwaysAppendDS> B<false>|B<true>
 
index 3bd8f0410f846ddf21130bf93ac8059555a7c269..61b7fc55e2c24ff880730580abf2d48e0e0f571d 100644 (file)
@@ -485,7 +485,7 @@ static int putval (lcc_connection_t *c, int argc, char **argv)
       while (value != 0) {
         char *dot, *endptr;
 
-        tmp = strchr (argv[i], (int)':');
+        tmp = strchr (value, (int)':');
 
         if (tmp != NULL) {
           *tmp = '\0';
index 9098de5908db7bbb306915b8cc0480263774d1e1..b679bf70f4ccff6a385c47b5fb4f47ccbd26a8b1 100644 (file)
@@ -548,7 +548,7 @@ int check_create_dir (const char *file_orig)
                        {
                                if (errno == ENOENT)
                                {
-                                       if (mkdir (dir, 0755) == 0)
+                                       if (mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
                                                break;
 
                                        /* this might happen, if a different thread created
@@ -636,24 +636,23 @@ long long get_kstat_value (kstat_t *ksp, char *name)
        kstat_named_t *kn;
        long long retval = -1LL;
 
-#ifdef assert
-       assert (ksp != NULL);
-       assert (ksp->ks_type == KSTAT_TYPE_NAMED);
-#else
        if (ksp == NULL)
        {
-               ERROR ("ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
+               ERROR ("get_kstat_value (\"%s\"): ksp is NULL.", name);
                return (-1LL);
        }
        else if (ksp->ks_type != KSTAT_TYPE_NAMED)
        {
-               ERROR ("ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
+               ERROR ("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
+                               "is not KSTAT_TYPE_NAMED (%#x).",
+                               name,
+                               (unsigned int) ksp->ks_type,
+                               (unsigned int) KSTAT_TYPE_NAMED);
                return (-1LL);
        }
-#endif
 
        if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
-               return (retval);
+               return (-1LL);
 
        if (kn->data_type == KSTAT_DATA_INT32)
                retval = (long long) kn->value.i32;
index c207318f9d62425fbfb18e7e86727bce62b65bcb..344f76e76f0c29242ac20821d8efb25f83f12871 100644 (file)
 /* no global variables */
 /* #endif KERNEL_LINUX */
 
+#elif HAVE_PERFSTAT
+# include <sys/protosw.h>
+# include <libperfstat.h>
+/* #endif HAVE_PERFSTAT */
+
 #else
 # error "No applicable input method."
 #endif
@@ -121,7 +126,24 @@ static int cs_read (void)
 
        if (status == -2)
                ERROR ("contextswitch plugin: Unable to find context switch value.");
-#endif /* KERNEL_LINUX */
+/* #endif  KERNEL_LINUX */
+
+#elif HAVE_PERFSTAT
+       int status = 0;
+       perfstat_cpu_total_t perfcputotal;
+
+       status = perfstat_cpu_total(NULL, &perfcputotal, sizeof(perfstat_cpu_total_t), 1);
+       if (status < 0)
+       {
+               char errbuf[1024];
+               ERROR ("contextswitch plugin: perfstat_cpu_total: %s",
+                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       cs_submit(perfcputotal.pswitch);
+       status = 0;
+#endif /* defined(HAVE_PERFSTAT) */
 
        return status;
 }
index 052ea1e61244d92d509501ea0daf800f19f454f3..46e0d490967456156863413912fe234deeb5abda 100644 (file)
@@ -419,7 +419,8 @@ static int cx_handle_instance_xpath (xmlXPathContextPtr xpath_ctx, /* {{{ */
   return (0);
 } /* }}} int cx_handle_instance_xpath */
 
-static int  cx_handle_base_xpath (char *plugin_instance, /* {{{ */
+static int  cx_handle_base_xpath (char const *plugin_instance, /* {{{ */
+    char const *host,
     xmlXPathContextPtr xpath_ctx, const data_set_t *ds, 
     char *base_xpath, cx_xpath_t *xpath)
 {
@@ -461,7 +462,7 @@ static int  cx_handle_base_xpath (char *plugin_instance, /* {{{ */
   vl.values_len = ds->ds_num;
   sstrncpy (vl.type, xpath->type, sizeof (vl.type));
   sstrncpy (vl.plugin, "curl_xml", sizeof (vl.plugin));
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  sstrncpy (vl.host, (host != NULL) ? host : hostname_g, sizeof (vl.host));
   if (plugin_instance != NULL)
     sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance)); 
 
@@ -504,7 +505,8 @@ static int cx_handle_parsed_xml(xmlDocPtr doc, /* {{{ */
     ds = plugin_get_ds (xpath->type);
 
     if ( (cx_check_type(ds, xpath) == 0) &&
-         (cx_handle_base_xpath(db->instance, xpath_ctx, ds, le->key, xpath) == 0) )
+         (cx_handle_base_xpath(db->instance, db->host,
+                               xpath_ctx, ds, le->key, xpath) == 0) )
       status = 0; /* we got atleast one success */
 
     le = le->next;
index 41a03cbf6280067815419d8802c5d431c0fd239f..ded374b942e5d08d804dd027292eef2ef9f50fcb 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -228,6 +228,8 @@ static int df_read (void)
                {
                        if (strcmp (mnt_ptr->dir, "/") == 0)
                        {
+                               if (strcmp (mnt_ptr->type, "rootfs") == 0)
+                                       continue;
                                sstrncpy (disk_name, "root", sizeof (disk_name));
                        }
                        else
index fde0dcde9abd5112c48633a6dcd588ef8bb0f69b..7411c22588abd4e409f25027d784bd83b62af62a 100644 (file)
@@ -235,6 +235,16 @@ static void disk_submit (const char *plugin_instance,
        plugin_dispatch_values (&vl);
 } /* void disk_submit */
 
+#if KERNEL_LINUX
+static counter_t disk_calc_time_incr (counter_t delta_time, counter_t delta_ops)
+{
+       double avg_time = ((double) delta_time) / ((double) delta_ops);
+       double avg_time_incr = CDTIME_T_TO_DOUBLE (interval_g) * avg_time;
+
+       return ((counter_t) (avg_time_incr + .5));
+}
+#endif
+
 #if HAVE_IOKIT_IOKITLIB_H
 static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
 {
@@ -579,13 +589,11 @@ static int disk_read (void)
                                diff_write_time = write_time - ds->write_time;
 
                        if (diff_read_ops != 0)
-                               ds->avg_read_time += (diff_read_time
-                                               + (diff_read_ops / 2))
-                                       / diff_read_ops;
+                               ds->avg_read_time += disk_calc_time_incr (
+                                               diff_read_time, diff_read_ops);
                        if (diff_write_ops != 0)
-                               ds->avg_write_time += (diff_write_time
-                                               + (diff_write_ops / 2))
-                                       / diff_write_ops;
+                               ds->avg_write_time += disk_calc_time_incr (
+                                               diff_write_time, diff_write_ops);
 
                        ds->read_ops = read_ops;
                        ds->read_time = read_time;
index 8fc5509f3e7e5ece33a15015b0ffa40fde6d6ede..5870ab1de1498593d4636973a65444d4e918d558 100644 (file)
@@ -376,6 +376,7 @@ static void *collect (void *arg)
        } /* while (1) */
 
        pthread_exit ((void *)0);
+       return ((void *) 0);
 } /* static void *collect (void *) */
 
 static void *open_connection (void __attribute__((unused)) *arg)
@@ -548,7 +549,9 @@ static void *open_connection (void __attribute__((unused)) *arg)
 
                pthread_cond_signal (&conn_available);
        }
-       pthread_exit ((void *)0);
+
+       pthread_exit ((void *) 0);
+       return ((void *) 0);
 } /* static void *open_connection (void *) */
 
 static int email_init (void)
index ae1b68931d898830cca2a67e9aa2cc8034371803..08381a821087e275fb03922a32bc54c35ca7c3cd 100644 (file)
@@ -66,6 +66,7 @@ static int ethstat_add_interface (const oconfig_item_t *ci) /* {{{ */
   if (tmp == NULL)
     return (-1);
   interfaces = tmp;
+  interfaces[interfaces_num] = NULL;
 
   status = cf_util_get_string (ci, interfaces + interfaces_num);
   if (status != 0)
@@ -104,7 +105,7 @@ static int ethstat_add_map (const oconfig_item_t *ci) /* {{{ */
   memset (map, 0, sizeof (*map));
 
   sstrncpy (map->type, ci->values[1].value.string, sizeof (map->type));
-  if (ci->values_num == 2)
+  if (ci->values_num == 3)
     sstrncpy (map->type_instance, ci->values[2].value.string,
         sizeof (map->type_instance));
 
index c5ea155ebc53f10e4d191bc84dca0828476a953a..0e807c75bc18e7dc59547471b3c35c57915979ac 100644 (file)
@@ -635,17 +635,22 @@ static void *exec_read_one (void *arg) /* {{{ */
 
       if (len < 0)
       {
-        if (errno == EAGAIN || errno == EINTR)  continue;
+        if (errno == EAGAIN || errno == EINTR)
+          continue;
         break;
       }
       else if (len == 0)
       {
         /* We've reached EOF */
-        NOTICE ("exec plugin: Program `%s' has closed STDERR.",
-            pl->exec);
-        close (fd_err);
+        NOTICE ("exec plugin: Program `%s' has closed STDERR.", pl->exec);
+
+        /* Remove file descriptor form select() set. */
         FD_CLR (fd_err, &fdset);
+        copy = fdset;
         highest_fd = fd;
+
+        /* Clean up file descriptor */
+        close (fd_err);
         fd_err = -1;
         continue;
       }
@@ -822,6 +827,7 @@ static int exec_read (void) /* {{{ */
     pthread_attr_init (&attr);
     pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
     pthread_create (&t, &attr, exec_read_one, (void *) pl);
+    pthread_attr_destroy (&attr);
   } /* for (pl) */
 
   return (0);
@@ -865,6 +871,7 @@ static int exec_notification (const notification_t *n, /* {{{ */
     pthread_attr_init (&attr);
     pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
     pthread_create (&t, &attr, exec_notification_one, (void *) pln);
+    pthread_attr_destroy (&attr);
   } /* for (pl) */
 
   return (0);
index 5b7aa94a9e4deec315c5175f8503a4900536e3c1..19f58b2b75c4f19b9b196f5d15b85f8f78dd21ac 100644 (file)
@@ -148,6 +148,19 @@ block:
         $$.children = $2.statement;
         $$.children_num = $2.statement_num;
        }
+       | block_begin block_end
+       {
+        if (strcmp ($1.key, $2) != 0)
+        {
+               printf ("block_begin = %s; block_end = %s;\n", $1.key, $2);
+               yyerror ("Block not closed..\n");
+               exit (1);
+        }
+        free ($2); $2 = NULL;
+        $$ = $1;
+        $$.children = NULL;
+        $$.children_num = 0;
+       }
        ;
 
 statement:
@@ -191,6 +204,13 @@ entire_file:
         ci_root->children = $1.statement;
         ci_root->children_num = $1.statement_num;
        }
+       | /* epsilon */
+       {
+        ci_root = malloc (sizeof (oconfig_item_t));
+        memset (ci_root, '\0', sizeof (oconfig_item_t));
+        ci_root->children = NULL;
+        ci_root->children_num = 0;
+       }
        ;
 
 %%
index 8f51e22f01dd3c2d728d0cbc0a8e2cc61fba99e1..c57a831226d4da64691922a7a43983c5b37eeee1 100644 (file)
@@ -328,7 +328,7 @@ static int cmc_config_add_page (oconfig_item_t *ci) /* {{{ */
 
     if (strcasecmp ("Server", child->key) == 0)
       status = cmc_config_add_string ("Server", &page->server, child);
-    if (strcasecmp ("Key", child->key) == 0)
+    else if (strcasecmp ("Key", child->key) == 0)
       status = cmc_config_add_string ("Key", &page->key, child);
     else if (strcasecmp ("Match", child->key) == 0)
       /* Be liberal with failing matches => don't set `status'. */
index 48fa713b8dbbe3aebf83f7130cf3988d18717dd3..a09f45ec6dae1a2e537fe986af7677f4130bd662 100644 (file)
@@ -1,9 +1,10 @@
 /**
  * collectd - src/memcached.c, based on src/hddtemp.c
  * Copyright (C) 2007       Antony Dovgal
- * Copyright (C) 2007-2010  Florian Forster
+ * Copyright (C) 2007-2012  Florian Forster
  * Copyright (C) 2009       Doug MacEachern
  * Copyright (C) 2009       Franck Lombardi
+ * Copyright (C) 2012       Nicolas Szalay
  *
  * 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
@@ -24,6 +25,7 @@
  *   Florian octo Forster <octo at collectd.org>
  *   Doug MacEachern <dougm at hyperic.com>
  *   Franck Lombardi
+ *   Nicolas Szalay
  **/
 
 #include "collectd.h"
 #include "plugin.h"
 #include "configfile.h"
 
-# include <poll.h>
-# include <netdb.h>
-# include <sys/socket.h>
-# include <sys/un.h>
-# include <netinet/in.h>
-# include <netinet/tcp.h>
-
-/* Hack to work around the missing define in AIX */
-#ifndef MSG_DONTWAIT
-# define MSG_DONTWAIT MSG_NONBLOCK
-#endif
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
 
 #define MEMCACHED_DEF_HOST "127.0.0.1"
 #define MEMCACHED_DEF_PORT "11211"
 
-#define MEMCACHED_RETRY_COUNT 100
-
-static const char *config_keys[] =
+struct memcached_s
 {
-       "Socket",
-       "Host",
-       "Port"
+  char *name;
+  char *socket;
+  char *host;
+  char *port;
 };
-static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+typedef struct memcached_s memcached_t;
 
-static char *memcached_socket = NULL;
-static char *memcached_host = NULL;
-static char memcached_port[16];
+static _Bool memcached_have_instances = 0;
 
-static int memcached_query_daemon (char *buffer, int buffer_size) /* {{{ */
+static void memcached_free (memcached_t *st)
 {
-       int fd;
-       ssize_t status;
-       int buffer_fill;
-       int i = 0;
-
-       if (memcached_socket != NULL) {
-               struct sockaddr_un serv_addr;
-
-               memset (&serv_addr, 0, sizeof (serv_addr));
-               serv_addr.sun_family = AF_UNIX;
-               sstrncpy (serv_addr.sun_path, memcached_socket,
-                               sizeof (serv_addr.sun_path));
-
-               /* create our socket descriptor */
-               fd = socket (AF_UNIX, SOCK_STREAM, 0);
-               if (fd < 0) {
-                       char errbuf[1024];
-                       ERROR ("memcached: unix socket: %s", sstrerror (errno, errbuf,
-                                               sizeof (errbuf)));
-                       return -1;
-               }
-
-               /* connect to the memcached daemon */
-               status = (ssize_t) connect (fd, (struct sockaddr *) &serv_addr,
-                               sizeof (serv_addr));
-               if (status != 0) {
-                       shutdown (fd, SHUT_RDWR);
-                       close (fd);
-                       fd = -1;
-               }
-       }
-       else { /* if (memcached_socket == NULL) */
-               const char *host;
-               const char *port;
-
-               struct addrinfo  ai_hints;
-               struct addrinfo *ai_list, *ai_ptr;
-               int              ai_return = 0;
-
-               memset (&ai_hints, '\0', sizeof (ai_hints));
-               ai_hints.ai_flags    = 0;
+  if (st == NULL)
+    return;
+
+  sfree (st->name);
+  sfree (st->socket);
+  sfree (st->host);
+  sfree (st->port);
+}
+
+static int memcached_connect_unix (memcached_t *st)
+{
+  struct sockaddr_un serv_addr;
+  int fd;
+
+  memset (&serv_addr, 0, sizeof (serv_addr));
+  serv_addr.sun_family = AF_UNIX;
+  sstrncpy (serv_addr.sun_path, st->socket,
+      sizeof (serv_addr.sun_path));
+
+  /* create our socket descriptor */
+  fd = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (fd < 0)
+  {
+    char errbuf[1024];
+    ERROR ("memcached plugin: memcached_connect_unix: socket(2) failed: %s",
+        sstrerror (errno, errbuf, sizeof (errbuf)));
+    return (-1);
+  }
+
+  return (fd);
+} /* int memcached_connect_unix */
+
+static int memcached_connect_inet (memcached_t *st)
+{
+  char *host;
+  char *port;
+
+  struct addrinfo  ai_hints;
+  struct addrinfo *ai_list, *ai_ptr;
+  int status;
+  int fd = -1;
+
+  memset (&ai_hints, 0, sizeof (ai_hints));
+  ai_hints.ai_flags    = 0;
 #ifdef AI_ADDRCONFIG
-               /*      ai_hints.ai_flags   |= AI_ADDRCONFIG; */
+  ai_hints.ai_flags   |= AI_ADDRCONFIG;
 #endif
-               ai_hints.ai_family   = AF_INET;
-               ai_hints.ai_socktype = SOCK_STREAM;
-               ai_hints.ai_protocol = 0;
-
-               host = memcached_host;
-               if (host == NULL) {
-                       host = MEMCACHED_DEF_HOST;
-               }
-
-               port = memcached_port;
-               if (strlen (port) == 0) {
-                       port = MEMCACHED_DEF_PORT;
-               }
-
-               if ((ai_return = getaddrinfo (host, port, &ai_hints, &ai_list)) != 0) {
-                       char errbuf[1024];
-                       ERROR ("memcached: getaddrinfo (%s, %s): %s",
-                                       host, port,
-                                       (ai_return == EAI_SYSTEM)
-                                       ? sstrerror (errno, errbuf, sizeof (errbuf))
-                                       : gai_strerror (ai_return));
-                       return -1;
-               }
-
-               fd = -1;
-               for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
-                       /* create our socket descriptor */
-                       fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
-                       if (fd < 0) {
-                               char errbuf[1024];
-                               ERROR ("memcached: socket: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
-                               continue;
-                       }
-
-                       /* connect to the memcached daemon */
-                       status = (ssize_t) connect (fd, (struct sockaddr *) ai_ptr->ai_addr, ai_ptr->ai_addrlen);
-                       if (status != 0) {
-                               shutdown (fd, SHUT_RDWR);
-                               close (fd);
-                               fd = -1;
-                               continue;
-                       }
-
-                       /* A socket could be opened and connecting succeeded. We're
-                        * done. */
-                       break;
-               }
-
-               freeaddrinfo (ai_list);
-       }
-
-       if (fd < 0) {
-               ERROR ("memcached: Could not connect to daemon.");
-               return -1;
-       }
-
-       if (send(fd, "stats\r\n", sizeof("stats\r\n") - 1, MSG_DONTWAIT) != (sizeof("stats\r\n") - 1)) {
-               ERROR ("memcached: Could not send command to the memcached daemon.");
-               return -1;
-       }
-
-       {
-               struct pollfd p;
-               int status;
-
-               memset (&p, 0, sizeof (p));
-               p.fd = fd;
-               p.events = POLLIN | POLLERR | POLLHUP;
-               p.revents = 0;
-
-               status = poll (&p, /* nfds = */ 1,
-                               /* timeout = */ CDTIME_T_TO_MS (interval_g));
-               if (status <= 0)
-               {
-                       if (status == 0)
-                       {
-                               ERROR ("memcached: poll(2) timed out after %.3f seconds.",
-                                               CDTIME_T_TO_DOUBLE (interval_g));
-                       }
-                       else
-                       {
-                               char errbuf[1024];
-                               ERROR ("memcached: poll(2) failed: %s",
-                                               sstrerror (errno, errbuf, sizeof (errbuf)));
-                       }
-                       shutdown (fd, SHUT_RDWR);
-                       close (fd);
-                       return (-1);
-               }
-       }
-
-       /* receive data from the memcached daemon */
-       memset (buffer, '\0', buffer_size);
-
-       buffer_fill = 0;
-       while ((status = recv (fd, buffer + buffer_fill, buffer_size - buffer_fill, MSG_DONTWAIT)) != 0) {
-               if (i > MEMCACHED_RETRY_COUNT) {
-                       ERROR("recv() timed out");
-                       break;
-               }
-               i++;
-
-               if (status == -1) {
-                       char errbuf[1024];
-
-                       if (errno == EAGAIN) {
-                               continue;
-                       }
-
-                       ERROR ("memcached: Error reading from socket: %s",
-                                       sstrerror (errno, errbuf, sizeof (errbuf)));
-                       shutdown(fd, SHUT_RDWR);
-                       close (fd);
-                       return -1;
-               }
-               buffer_fill += status;
-
-               if (buffer_fill > 3 && buffer[buffer_fill-5] == 'E' && buffer[buffer_fill-4] == 'N' && buffer[buffer_fill-3] == 'D') {
-                       /* we got all the data */
-                       break;
-               }
-       }
-
-       if (buffer_fill >= buffer_size) {
-               buffer[buffer_size - 1] = '\0';
-               WARNING ("memcached: Message from memcached has been truncated.");
-       } else if (buffer_fill == 0) {
-               WARNING ("memcached: Peer has unexpectedly shut down the socket. "
-                               "Buffer: `%s'", buffer);
-               shutdown(fd, SHUT_RDWR);
-               close(fd);
-               return -1;
-       }
-
-       shutdown(fd, SHUT_RDWR);
-       close(fd);
-       return 0;
+  ai_hints.ai_family   = AF_UNSPEC;
+  ai_hints.ai_socktype = SOCK_STREAM;
+  ai_hints.ai_protocol = 0;
+
+  host = (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST;
+  port = (st->port != NULL) ? st->port : MEMCACHED_DEF_PORT;
+
+  ai_list = NULL;
+  status = getaddrinfo (host, port, &ai_hints, &ai_list);
+  if (status != 0)
+  {
+    char errbuf[1024];
+    ERROR ("memcached plugin: memcached_connect_inet: "
+        "getaddrinfo(%s,%s) failed: %s",
+        host, port,
+        (status == EAI_SYSTEM)
+        ? sstrerror (errno, errbuf, sizeof (errbuf))
+        : gai_strerror (status));
+    return (-1);
+  }
+
+  for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+  {
+    /* create our socket descriptor */
+    fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+    if (fd < 0)
+    {
+      char errbuf[1024];
+      WARNING ("memcached plugin: memcached_connect_inet: "
+          "socket(2) failed: %s",
+          sstrerror (errno, errbuf, sizeof (errbuf)));
+      continue;
+    }
+
+    /* connect to the memcached daemon */
+    status = (int) connect (fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+    if (status != 0)
+    {
+      shutdown (fd, SHUT_RDWR);
+      close (fd);
+      fd = -1;
+      continue;
+    }
+
+    /* A socket could be opened and connecting succeeded. We're done. */
+    break;
+  }
+
+  freeaddrinfo (ai_list);
+  return (fd);
+} /* int memcached_connect_inet */
+
+static int memcached_connect (memcached_t *st)
+{
+  if (st->socket != NULL)
+    return (memcached_connect_unix (st));
+  else
+    return (memcached_connect_inet (st));
 }
-/* }}} */
 
-static int memcached_config (const char *key, const char *value) /* {{{ */
+static int memcached_query_daemon (char *buffer, size_t buffer_size, memcached_t *st)
 {
-       if (strcasecmp (key, "Socket") == 0) {
-               if (memcached_socket != NULL) {
-                       free (memcached_socket);
-               }
-               memcached_socket = strdup (value);
-       } else if (strcasecmp (key, "Host") == 0) {
-               if (memcached_host != NULL) {
-                       free (memcached_host);
-               }
-               memcached_host = strdup (value);
-       } else if (strcasecmp (key, "Port") == 0) {
-               int port = (int) (atof (value));
-               if ((port > 0) && (port <= 65535)) {
-                       ssnprintf (memcached_port, sizeof (memcached_port), "%i", port);
-               } else {
-                       sstrncpy (memcached_port, value, sizeof (memcached_port));
-               }
-       } else {
-               return -1;
-       }
-
-       return 0;
+  int fd = -1;
+  int status;
+  size_t buffer_fill;
+
+  fd = memcached_connect (st);
+  if (fd < 0) {
+    ERROR ("memcached plugin: Instance \"%s\" could not connect to daemon.",
+        st->name);
+    return -1;
+  }
+
+  status = (int) swrite (fd, "stats\r\n", strlen ("stats\r\n"));
+  if (status != 0)
+  {
+    char errbuf[1024];
+    ERROR ("memcached plugin: write(2) failed: %s",
+        sstrerror (errno, errbuf, sizeof (errbuf)));
+    shutdown(fd, SHUT_RDWR);
+    close (fd);
+    return (-1);
+  }
+
+  /* receive data from the memcached daemon */
+  memset (buffer, 0, buffer_size);
+
+  buffer_fill = 0;
+  while ((status = (int) recv (fd, buffer + buffer_fill,
+          buffer_size - buffer_fill, /* flags = */ 0)) != 0)
+  {
+    char const end_token[5] = {'E', 'N', 'D', '\r', '\n'};
+    if (status < 0)
+    {
+      char errbuf[1024];
+
+      if ((errno == EAGAIN) || (errno == EINTR))
+          continue;
+
+      ERROR ("memcached: Error reading from socket: %s",
+          sstrerror (errno, errbuf, sizeof (errbuf)));
+      shutdown(fd, SHUT_RDWR);
+      close (fd);
+      return (-1);
+    }
+
+    buffer_fill += (size_t) status;
+    if (buffer_fill > buffer_size)
+    {
+      buffer_fill = buffer_size;
+      WARNING ("memcached plugin: Message was truncated.");
+      break;
+    }
+
+    /* If buffer ends in end_token, we have all the data. */
+    if (memcmp (buffer + buffer_fill - sizeof (end_token),
+          end_token, sizeof (end_token)) == 0)
+      break;
+  } /* while (recv) */
+
+  status = 0;
+  if (buffer_fill == 0)
+  {
+    WARNING ("memcached plugin: No data returned by memcached.");
+    status = -1;
+  }
+
+  shutdown(fd, SHUT_RDWR);
+  close(fd);
+  return (status);
+} /* int memcached_query_daemon */
+
+static void memcached_init_vl (value_list_t *vl, memcached_t const *st)
+{
+  sstrncpy (vl->plugin, "memcached", sizeof (vl->plugin));
+  if (strcmp (st->name, "__legacy__") == 0) /* legacy mode */
+  {
+    sstrncpy (vl->host, hostname_g, sizeof (vl->host));
+  }
+  else
+  {
+    if (st->socket != NULL)
+      sstrncpy (vl->host, hostname_g, sizeof (vl->host));
+    else
+      sstrncpy (vl->host,
+          (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST,
+          sizeof (vl->host));
+    sstrncpy (vl->plugin_instance, st->name, sizeof (vl->plugin_instance));
+  }
 }
-/* }}} */
 
 static void submit_derive (const char *type, const char *type_inst,
-               derive_t value) /* {{{ */
+    derive_t value, memcached_t *st)
 {
-       value_t values[1];
-       value_list_t vl = VALUE_LIST_INIT;
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
-       values[0].derive = value;
+  values[0].derive = value;
 
-       vl.values = values;
-       vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
-       sstrncpy (vl.type, type, sizeof (vl.type));
-       if (type_inst != NULL)
-               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+  vl.values = values;
+  vl.values_len = 1;
+  sstrncpy (vl.type, type, sizeof (vl.type));
+  if (type_inst != NULL)
+    sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (&vl);
-} /* void memcached_submit_cmd */
-/* }}} */
+  plugin_dispatch_values (&vl);
+}
 
 static void submit_derive2 (const char *type, const char *type_inst,
-               derive_t value0, derive_t value1) /* {{{ */
+    derive_t value0, derive_t value1, memcached_t *st)
 {
-       value_t values[2];
-       value_list_t vl = VALUE_LIST_INIT;
+  value_t values[2];
+  value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
-       values[0].derive = value0;
-       values[1].derive = value1;
+  values[0].derive = value0;
+  values[1].derive = value1;
 
-       vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
-       sstrncpy (vl.type, type, sizeof (vl.type));
-       if (type_inst != NULL)
-               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+  vl.values = values;
+  vl.values_len = 2;
+  sstrncpy (vl.type, type, sizeof (vl.type));
+  if (type_inst != NULL)
+    sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (&vl);
-} /* void memcached_submit_cmd */
-/* }}} */
+  plugin_dispatch_values (&vl);
+}
 
 static void submit_gauge (const char *type, const char *type_inst,
-               gauge_t value) /* {{{ */
+    gauge_t value, memcached_t *st)
 {
-       value_t values[1];
-       value_list_t vl = VALUE_LIST_INIT;
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
-       values[0].gauge = value;
+  values[0].gauge = value;
 
-       vl.values = values;
-       vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
-       sstrncpy (vl.type, type, sizeof (vl.type));
-       if (type_inst != NULL)
-               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+  vl.values = values;
+  vl.values_len = 1;
+  sstrncpy (vl.type, type, sizeof (vl.type));
+  if (type_inst != NULL)
+    sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (&vl);
+  plugin_dispatch_values (&vl);
 }
-/* }}} */
 
 static void submit_gauge2 (const char *type, const char *type_inst,
-               gauge_t value0, gauge_t value1) /* {{{ */
+    gauge_t value0, gauge_t value1, memcached_t *st)
 {
-       value_t values[2];
-       value_list_t vl = VALUE_LIST_INIT;
+  value_t values[2];
+  value_list_t vl = VALUE_LIST_INIT;
+  memcached_init_vl (&vl, st);
 
-       values[0].gauge = value0;
-       values[1].gauge = value1;
+  values[0].gauge = value0;
+  values[1].gauge = value1;
 
-       vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
-       sstrncpy (vl.type, type, sizeof (vl.type));
-       if (type_inst != NULL)
-               sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+  vl.values = values;
+  vl.values_len = 2;
+  sstrncpy (vl.type, type, sizeof (vl.type));
+  if (type_inst != NULL)
+    sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
-       plugin_dispatch_values (&vl);
+  plugin_dispatch_values (&vl);
 }
-/* }}} */
 
-static int memcached_read (void) /* {{{ */
+static int memcached_read (user_data_t *user_data)
 {
-       char buf[4096];
-       char *fields[3];
-       char *ptr;
-       char *line;
-       char *saveptr;
-       int fields_num;
-
-       gauge_t bytes_used = NAN;
-       gauge_t bytes_total = NAN;
-       gauge_t hits = NAN;
-       gauge_t gets = NAN;
-       derive_t rusage_user = 0;
-       derive_t rusage_syst = 0;
-       derive_t octets_rx = 0;
-       derive_t octets_tx = 0;
-
-       /* get data from daemon */
-       if (memcached_query_daemon (buf, sizeof (buf)) < 0) {
-               return -1;
-       }
+  char buf[4096];
+  char *fields[3];
+  char *ptr;
+  char *line;
+  char *saveptr;
+  int fields_num;
+
+  gauge_t bytes_used = NAN;
+  gauge_t bytes_total = NAN;
+  gauge_t hits = NAN;
+  gauge_t gets = NAN;
+  derive_t rusage_user = 0;
+  derive_t rusage_syst = 0;
+  derive_t octets_rx = 0;
+  derive_t octets_tx = 0;
+
+  memcached_t *st;
+  st = user_data->data;
+
+  /* get data from daemon */
+  if (memcached_query_daemon (buf, sizeof (buf), st) < 0) {
+    return -1;
+  }
 
 #define FIELD_IS(cnst) \
-       (((sizeof(cnst) - 1) == name_len) && (strcmp (cnst, fields[1]) == 0))
-
-       ptr = buf;
-       saveptr = NULL;
-       while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
-       {
-               int name_len;
-
-               ptr = NULL;
-
-               fields_num = strsplit(line, fields, 3);
-               if (fields_num != 3)
-                       continue;
-
-               name_len = strlen(fields[1]);
-               if (name_len == 0)
-                       continue;
-
-               /*
-                * For an explanation on these fields please refer to
-                * <http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt>
-                */
-
-               /*
-                * CPU time consumed by the memcached process
-                */
-               if (FIELD_IS ("rusage_user"))
-               {
-                       rusage_user = atoll (fields[2]);
-               }
-               else if (FIELD_IS ("rusage_system"))
-               {
-                       rusage_syst = atoll(fields[2]);
-               }
-
-               /*
-                * Number of threads of this instance
-                */
-               else if (FIELD_IS ("threads"))
-               {
-                       submit_gauge2 ("ps_count", NULL, NAN, atof (fields[2]));
-               }
-
-               /*
-                * Number of items stored
-                */
-               else if (FIELD_IS ("curr_items"))
-               {
-                       submit_gauge ("memcached_items", "current", atof (fields[2]));
-               }
-
-               /*
-                * Number of bytes used and available (total - used)
-                */
-               else if (FIELD_IS ("bytes"))
-               {
-                       bytes_used = atof (fields[2]);
-               }
-               else if (FIELD_IS ("limit_maxbytes"))
-               {
-                       bytes_total = atof(fields[2]);
-               }
-
-               /*
-                * Connections
-                */
-               else if (FIELD_IS ("curr_connections"))
-               {
-                       submit_gauge ("memcached_connections", "current", atof (fields[2]));
-               }
-
-               /*
-                * Commands
-                */
-               else if ((name_len > 4) && (strncmp (fields[1], "cmd_", 4) == 0))
-               {
-                       const char *name = fields[1] + 4;
-                       submit_derive ("memcached_command", name, atoll (fields[2]));
-                       if (strcmp (name, "get") == 0)
-                               gets = atof (fields[2]);
-               }
-
-               /*
-                * Operations on the cache, i. e. cache hits, cache misses and evictions of items
-                */
-               else if (FIELD_IS ("get_hits"))
-               {
-                       submit_derive ("memcached_ops", "hits", atoll (fields[2]));
-                       hits = atof (fields[2]);
-               }
-               else if (FIELD_IS ("get_misses"))
-               {
-                       submit_derive ("memcached_ops", "misses", atoll (fields[2]));
-               }
-               else if (FIELD_IS ("evictions"))
-               {
-                       submit_derive ("memcached_ops", "evictions", atoll (fields[2]));
-               }
-
-               /*
-                * Network traffic
-                */
-               else if (FIELD_IS ("bytes_read"))
-               {
-                       octets_rx = atoll (fields[2]);
-               }
-               else if (FIELD_IS ("bytes_written"))
-               {
-                       octets_tx = atoll (fields[2]);
-               }
-       } /* while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL) */
-
-       if (!isnan (bytes_used) && !isnan (bytes_total) && (bytes_used <= bytes_total))
-               submit_gauge2 ("df", "cache", bytes_used, bytes_total - bytes_used);
-
-       if ((rusage_user != 0) || (rusage_syst != 0))
-               submit_derive2 ("ps_cputime", NULL, rusage_user, rusage_syst);
-
-       if ((octets_rx != 0) || (octets_tx != 0))
-               submit_derive2 ("memcached_octets", NULL, octets_rx, octets_tx);
-
-       if (!isnan (gets) && !isnan (hits))
-       {
-               gauge_t rate = NAN;
-
-               if (gets != 0.0)
-                       rate = 100.0 * hits / gets;
-
-               submit_gauge ("percent", "hitratio", rate);
-       }
-
-       return 0;
+  (((sizeof(cnst) - 1) == name_len) && (strcmp (cnst, fields[1]) == 0))
+
+  ptr = buf;
+  saveptr = NULL;
+  while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
+  {
+    int name_len;
+
+    ptr = NULL;
+
+    fields_num = strsplit(line, fields, 3);
+    if (fields_num != 3)
+      continue;
+
+    name_len = strlen(fields[1]);
+    if (name_len == 0)
+      continue;
+
+    /*
+     * For an explanation on these fields please refer to
+     * <http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt>
+     */
+
+    /*
+     * CPU time consumed by the memcached process
+     */
+    if (FIELD_IS ("rusage_user"))
+    {
+      rusage_user = atoll (fields[2]);
+    }
+    else if (FIELD_IS ("rusage_system"))
+    {
+      rusage_syst = atoll(fields[2]);
+    }
+
+    /*
+     * Number of threads of this instance
+     */
+    else if (FIELD_IS ("threads"))
+    {
+      submit_gauge2 ("ps_count", NULL, NAN, atof (fields[2]), st);
+    }
+
+    /*
+     * Number of items stored
+     */
+    else if (FIELD_IS ("curr_items"))
+    {
+      submit_gauge ("memcached_items", "current", atof (fields[2]), st);
+    }
+
+    /*
+     * Number of bytes used and available (total - used)
+     */
+    else if (FIELD_IS ("bytes"))
+    {
+      bytes_used = atof (fields[2]);
+    }
+    else if (FIELD_IS ("limit_maxbytes"))
+    {
+      bytes_total = atof(fields[2]);
+    }
+
+    /*
+     * Connections
+     */
+    else if (FIELD_IS ("curr_connections"))
+    {
+      submit_gauge ("memcached_connections", "current", atof (fields[2]), st);
+    }
+
+    /*
+     * Commands
+     */
+    else if ((name_len > 4) && (strncmp (fields[1], "cmd_", 4) == 0))
+    {
+      const char *name = fields[1] + 4;
+      submit_derive ("memcached_command", name, atoll (fields[2]), st);
+      if (strcmp (name, "get") == 0)
+        gets = atof (fields[2]);
+    }
+
+    /*
+     * Operations on the cache, i. e. cache hits, cache misses and evictions of items
+     */
+    else if (FIELD_IS ("get_hits"))
+    {
+      submit_derive ("memcached_ops", "hits", atoll (fields[2]), st);
+      hits = atof (fields[2]);
+    }
+    else if (FIELD_IS ("get_misses"))
+    {
+      submit_derive ("memcached_ops", "misses", atoll (fields[2]), st);
+    }
+    else if (FIELD_IS ("evictions"))
+    {
+      submit_derive ("memcached_ops", "evictions", atoll (fields[2]), st);
+    }
+
+    /*
+     * Network traffic
+     */
+    else if (FIELD_IS ("bytes_read"))
+    {
+      octets_rx = atoll (fields[2]);
+    }
+    else if (FIELD_IS ("bytes_written"))
+    {
+      octets_tx = atoll (fields[2]);
+    }
+  } /* while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL) */
+
+  if (!isnan (bytes_used) && !isnan (bytes_total) && (bytes_used <= bytes_total))
+    submit_gauge2 ("df", "cache", bytes_used, bytes_total - bytes_used, st);
+
+  if ((rusage_user != 0) || (rusage_syst != 0))
+    submit_derive2 ("ps_cputime", NULL, rusage_user, rusage_syst, st);
+
+  if ((octets_rx != 0) || (octets_tx != 0))
+    submit_derive2 ("memcached_octets", NULL, octets_rx, octets_tx, st);
+
+  if (!isnan (gets) && !isnan (hits))
+  {
+    gauge_t rate = NAN;
+
+    if (gets != 0.0)
+      rate = 100.0 * hits / gets;
+
+    submit_gauge ("percent", "hitratio", rate, st);
+  }
+
+  return 0;
+} /* int memcached_read */
+
+static int memcached_add_read_callback (memcached_t *st)
+{
+  user_data_t ud;
+  char callback_name[3*DATA_MAX_NAME_LEN];
+  int status;
+
+  memset (&ud, 0, sizeof (ud));
+  ud.data = st;
+  ud.free_func = (void *) memcached_free;
+
+  assert (st->name != NULL);
+  ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
+
+  status = plugin_register_complex_read (/* group = */ "memcached",
+      /* name      = */ callback_name,
+      /* callback  = */ memcached_read,
+      /* interval  = */ NULL,
+      /* user_data = */ &ud);
+  return (status);
+} /* int memcached_add_read_callback */
+
+/* Configuration handling functiions
+ * <Plugin memcached>
+ *   <Instance "instance_name">
+ *     Host foo.zomg.com
+ *     Port "1234"
+ *   </Instance>
+ * </Plugin>
+ */
+static int config_add_instance(oconfig_item_t *ci)
+{
+  memcached_t *st;
+  int i;
+  int status = 0;
+
+  /* Disable automatic generation of default instance in the init callback. */
+  memcached_have_instances = 1;
+
+  st = malloc (sizeof (*st));
+  if (st == NULL)
+  {
+    ERROR ("memcached plugin: malloc failed.");
+    return (-1);
+  }
+
+  memset (st, 0, sizeof (*st));
+  st->name = NULL;
+  st->socket = NULL;
+  st->host = NULL;
+  st->port = NULL;
+
+  if (strcasecmp (ci->key, "Plugin") == 0) /* default instance */
+    st->name = sstrdup ("__legacy__");
+  else /* <Instance /> block */
+    status = cf_util_get_string (ci, &st->name);
+  if (status != 0)
+  {
+    sfree (st);
+    return (status);
+  }
+  assert (st->name != NULL);
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("Socket", child->key) == 0)
+      status = cf_util_get_string (child, &st->socket);
+    else if (strcasecmp ("Host", child->key) == 0)
+      status = cf_util_get_string (child, &st->host);
+    else if (strcasecmp ("Port", child->key) == 0)
+      status = cf_util_get_service (child, &st->port);
+    else
+    {
+      WARNING ("memcached plugin: Option `%s' not allowed here.",
+          child->key);
+      status = -1;
+    }
+
+    if (status != 0)
+      break;
+  }
+
+  if (status == 0)
+    status = memcached_add_read_callback (st);
+
+  if (status != 0)
+  {
+    memcached_free(st);
+    return (-1);
+  }
+
+  return (0);
 }
-/* }}} */
 
-void module_register (void) /* {{{ */
+static int memcached_config (oconfig_item_t *ci)
 {
-       plugin_register_config ("memcached", memcached_config, config_keys, config_keys_num);
-       plugin_register_read ("memcached", memcached_read);
+  int status = 0;
+  _Bool have_instance_block = 0;
+  int i;
+
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp ("Instance", child->key) == 0)
+    {
+      config_add_instance (child);
+      have_instance_block = 1;
+    }
+    else if (!have_instance_block)
+    {
+      /* Non-instance option: Assume legacy configuration (without <Instance />
+       * blocks) and call config_add_instance() with the <Plugin /> block. */
+      return (config_add_instance (ci));
+    }
+    else
+      WARNING ("memcached plugin: The configuration option "
+          "\"%s\" is not allowed here. Did you "
+          "forget to add an <Instance /> block "
+          "around the configuration?",
+          child->key);
+  } /* for (ci->children) */
+
+  return (status);
 }
-/* }}} */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker noexpandtab
- * vim<600: sw=4 ts=4 noexpandtab
- */
 
+static int memcached_init (void)
+{
+  memcached_t *st;
+  int status;
+
+  if (memcached_have_instances)
+    return (0);
+
+  /* No instances were configured, lets start a default instance. */
+  st = malloc (sizeof (*st));
+  if (st == NULL)
+    return (ENOMEM);
+  memset (st, 0, sizeof (*st));
+  st->name = sstrdup ("__legacy__");
+  st->socket = NULL;
+  st->host = NULL;
+  st->port = NULL;
+
+  status = memcached_add_read_callback (st);
+  if (status == 0)
+    memcached_have_instances = 1;
+  else
+    memcached_free (st);
+
+  return (status);
+} /* int memcached_init */
+
+void module_register (void)
+{
+  plugin_register_complex_config ("memcached", memcached_config);
+  plugin_register_init ("memcached", memcached_init);
+}
index b502b377295141a8a095ba248d7e6de0ab285072..ea98ba94abf44670583ab47601e39ce6a0f68394 100644 (file)
@@ -250,6 +250,7 @@ void meta_data_destroy (meta_data_t *md) /* {{{ */
   if (md == NULL)
     return;
 
+  pthread_mutex_destroy(&md->lock);
   md_entry_free (md->head);
   pthread_mutex_destroy (&md->lock);
   free (md);
index 6b636787555b7e177a09abf20b71cd7cbbb7f9a7..32b352bbdd15919631a60ba78ef6233230dd407f 100644 (file)
@@ -192,9 +192,9 @@ static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
                ud.data = (void *) db;
                ud.free_func = mysql_database_free;
 
-               if (db->database != NULL)
+               if (db->instance != NULL)
                        ssnprintf (cb_name, sizeof (cb_name), "mysql-%s",
-                                       db->database);
+                                       db->instance);
                else
                        sstrncpy (cb_name, "mysql", sizeof (cb_name));
 
index d9bd1ae520597697fc96cb1f1a540d664c571ff2..f7bc04d3b1db35c54ab5a607316c9f1fc146209d 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/netapp.c
- * Copyright (C) 2009  Sven Trenkel
+ * Copyright (C) 2009,2010  Sven Trenkel
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -2497,7 +2497,7 @@ static int cna_init_host (host_config_t *host) /* {{{ */
        na_server_adminuser(host->srv, host->username, host->password);
        na_server_set_timeout(host->srv, 5 /* seconds */);
 
-       return 0;
+       return (0);
 } /* }}} int cna_init_host */
 
 static int cna_init (void) /* {{{ */
@@ -2514,6 +2514,32 @@ static int cna_init (void) /* {{{ */
        return (0);
 } /* }}} cna_init */
 
+static int cna_read_internal (host_config_t *host) { /* {{{ */
+       int status;
+
+       status = cna_query_wafl (host);
+       if (status != 0)
+               return (status);
+
+       status = cna_query_disk (host);
+       if (status != 0)
+               return (status);
+
+       status = cna_query_volume_perf (host);
+       if (status != 0)
+               return (status);
+
+       status = cna_query_volume_usage (host);
+       if (status != 0)
+               return (status);
+
+       status = cna_query_system (host);
+       if (status != 0)
+               return (status);
+
+       return 0;
+} /* }}} int cna_read_internal */
+
 static int cna_read (user_data_t *ud) { /* {{{ */
        host_config_t *host;
        int status;
@@ -2526,12 +2552,14 @@ static int cna_read (user_data_t *ud) { /* {{{ */
        status = cna_init_host (host);
        if (status != 0)
                return (status);
-       
-       cna_query_wafl (host);
-       cna_query_disk (host);
-       cna_query_volume_perf (host);
-       cna_query_volume_usage (host);
-       cna_query_system (host);
+
+       status = cna_read_internal (host);
+       if (status != 0)
+       {
+               if (host->srv != NULL)
+                       na_server_close (host->srv);
+               host->srv = NULL;
+       }
 
        return 0;
 } /* }}} int cna_read */
index ef851d354937a0069969b7822b5ce6de0879a739..7c4bef5a83f79f41796a473b6f6956e17a84e9fb 100644 (file)
@@ -570,8 +570,14 @@ static int ir_read (void)
     return (-1);
   }
 
+#ifdef RTNL_DUMP_FILTER_FIVE_ARGS
   if (rtnl_dump_filter (&rth, link_filter, /* arg1 = */ NULL,
        NULL, NULL) != 0)
+#elif defined(RTNL_DUMP_FILTER_THREE_ARGS)
+  if (rtnl_dump_filter (&rth, link_filter, /* arg = */ NULL) != 0)
+#else
+#error "Failed to determine the number of arguments to 'rtnl_dump_filter'!"
+#endif
   {
     ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
     return (-1);
@@ -608,8 +614,14 @@ static int ir_read (void)
        continue;
       }
 
+#ifdef RTNL_DUMP_FILTER_FIVE_ARGS
       if (rtnl_dump_filter (&rth, qos_filter, (void *) &ifindex,
            NULL, NULL) != 0)
+#elif defined(RTNL_DUMP_FILTER_THREE_ARGS)
+      if (rtnl_dump_filter (&rth, qos_filter, /* arg = */ &ifindex) != 0)
+#else
+#error "Failed to determine the number of arguments to 'rtnl_dump_filter'!"
+#endif
       {
        ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
        continue;
index 5fed1b196933a5bb00d39d8e9f3c9d828930bd84..3cf222744262796d4ce964cf3c76d4c690202d49 100644 (file)
 #endif
 
 #if HAVE_LIBGCRYPT
+# include <pthread.h>
+# if defined __APPLE__
+/* default xcode compiler throws warnings even when deprecated functionality
+ * is not used. -Werror breaks the build because of erroneous warnings.
+ * http://stackoverflow.com/questions/10556299/compiler-warnings-with-libgcrypt-v1-5-0/12830209#12830209
+ */
+#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# endif
 # include <gcrypt.h>
+# if defined __APPLE__
+/* Re enable deprecation warnings */
+#  pragma GCC diagnostic warning "-Wdeprecated-declarations"
+# endif
 GCRY_THREAD_OPTION_PTHREAD_IMPL;
 #endif
 
@@ -661,7 +673,7 @@ static int write_part_number (char **ret_buffer, int *ret_buffer_len,
 
        part_header_t pkg_head;
        uint64_t pkg_value;
-       
+
        int offset;
 
        packet_len = sizeof (pkg_head) + sizeof (pkg_value);
@@ -1665,7 +1677,7 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
                                        sizeof (network_config_ttl)) != 0)
                {
                        char errbuf[1024];
-                       ERROR ("setsockopt: %s",
+                       ERROR ("network plugin: setsockopt (ipv4-ttl): %s",
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                        return (-1);
                }
@@ -1686,7 +1698,7 @@ static int network_set_ttl (const sockent_t *se, const struct addrinfo *ai)
                                        sizeof (network_config_ttl)) != 0)
                {
                        char errbuf[1024];
-                       ERROR ("setsockopt: %s",
+                       ERROR ("network plugin: setsockopt(ipv6-ttl): %s",
                                        sstrerror (errno, errbuf,
                                                sizeof (errbuf)));
                        return (-1);
@@ -1733,7 +1745,7 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
                                                &mreq, sizeof (mreq)) != 0)
                        {
                                char errbuf[1024];
-                               ERROR ("setsockopt: %s",
+                               ERROR ("network plugin: setsockopt (ipv4-multicast-if): %s",
                                                sstrerror (errno, errbuf, sizeof (errbuf)));
                                return (-1);
                        }
@@ -1752,7 +1764,7 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
                                                sizeof (se->interface)) != 0)
                        {
                                char errbuf[1024];
-                               ERROR ("setsockopt: %s",
+                               ERROR ("network plugin: setsockopt (ipv6-multicast-if): %s",
                                                sstrerror (errno, errbuf,
                                                        sizeof (errbuf)));
                                return (-1);
@@ -1778,7 +1790,7 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
                                        sizeof(interface_name)) == -1 )
                {
                        char errbuf[1024];
-                       ERROR ("setsockopt: %s",
+                       ERROR ("network plugin: setsockopt (bind-if): %s",
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                        return (-1);
                }
@@ -1802,14 +1814,18 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
 
 static int network_bind_socket (int fd, const struct addrinfo *ai, const int interface_idx)
 {
+#if KERNEL_SOLARIS
+       char loop   = 0;
+#else
        int loop = 0;
+#endif
        int yes  = 1;
 
        /* allow multiple sockets to use the same PORT number */
        if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
                                &yes, sizeof(yes)) == -1) {
                 char errbuf[1024];
-                ERROR ("setsockopt: %s", 
+                ERROR ("network plugin: setsockopt (reuseaddr): %s",
                                 sstrerror (errno, errbuf, sizeof (errbuf)));
                return (-1);
        }
@@ -1852,7 +1868,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                                                &loop, sizeof (loop)) == -1)
                        {
                                char errbuf[1024];
-                               ERROR ("setsockopt: %s",
+                               ERROR ("network plugin: setsockopt (multicast-loop): %s",
                                                sstrerror (errno, errbuf,
                                                        sizeof (errbuf)));
                                return (-1);
@@ -1862,7 +1878,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                                                &mreq, sizeof (mreq)) == -1)
                        {
                                char errbuf[1024];
-                               ERROR ("setsockopt: %s",
+                               ERROR ("network plugin: setsockopt (add-membership): %s",
                                                sstrerror (errno, errbuf,
                                                        sizeof (errbuf)));
                                return (-1);
@@ -1900,7 +1916,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                                                &loop, sizeof (loop)) == -1)
                        {
                                char errbuf[1024];
-                               ERROR ("setsockopt: %s",
+                               ERROR ("network plugin: setsockopt (ipv6-multicast-loop): %s",
                                                sstrerror (errno, errbuf,
                                                        sizeof (errbuf)));
                                return (-1);
@@ -1910,7 +1926,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                                                &mreq, sizeof (mreq)) == -1)
                        {
                                char errbuf[1024];
-                               ERROR ("setsockopt: %s",
+                               ERROR ("network plugin: setsockopt (ipv6-add-membership): %s",
                                                sstrerror (errno, errbuf,
                                                        sizeof (errbuf)));
                                return (-1);
@@ -1938,7 +1954,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
                                        sizeof(interface_name)) == -1 )
                {
                        char errbuf[1024];
-                       ERROR ("setsockopt: %s",
+                       ERROR ("network plugin: setsockopt (bind-if): %s",
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                        return (-1);
                }
@@ -2713,7 +2729,7 @@ static int add_to_buffer (char *buffer, int buffer_size, /* {{{ */
                        return (-1);
                sstrncpy (vl_def->type_instance, vl->type_instance, sizeof (vl_def->type_instance));
        }
-       
+
        if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
                return (-1);
 
@@ -3426,7 +3442,7 @@ static int network_init (void)
        return (0);
 } /* int network_init */
 
-/* 
+/*
  * The flush option of the network plugin cannot flush individual identifiers.
  * All the values are added to a buffer and sent when the buffer is full, the
  * requested value may or may not be in there, it's not worth finding out. We
index 58f2e0d23b37316ae1e48be719aa37ac82fc692c..461e806f90ab76d0ed97747043ca1a1430a6f12c 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
@@ -332,10 +332,12 @@ static int nfs_read_kstat (kstat_t *ksp, int nfs_version, char *inst,
 
        kstat_read(kc, ksp, NULL);
        for (i = 0; i < proc_names_num; i++)
-               values[i].counter = (derive_t) get_kstat_value (ksp, proc_names[i]);
+               values[i].counter = (derive_t) get_kstat_value (ksp,
+                               (char *)proc_names[i]);
 
        nfs_procedures_submit (plugin_instance, proc_names, values,
                        proc_names_num);
+       return (0);
 }
 #endif
 
index 8bbf74d7d965b94ac0d21939fc3a4776116a7539..bbc455f6dd0603a1f6135c52ae1b199ff57f24f2 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/ntpd.c
- * Copyright (C) 2006-2007  Florian octo Forster
+ * Copyright (C) 2006-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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #define _BSD_SOURCE /* For NI_MAXHOST */
@@ -52,11 +52,17 @@ static const char *config_keys[] =
 {
        "Host",
        "Port",
-       "ReverseLookups"
+       "ReverseLookups",
+       "IncludeUnitID"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
-static int do_reverse_lookups = 1;
+static _Bool do_reverse_lookups = 1;
+
+/* This option only exists for backward compatibility. If it is false and two
+ * ntpd peers use the same refclock driver, the plugin will try to write
+ * simultaneous measurements from both to the same type instance. */
+static _Bool include_unit_id = 0;
 
 # define NTPD_DEFAULT_HOST "localhost"
 # define NTPD_DEFAULT_PORT "123"
@@ -283,6 +289,13 @@ static int ntpd_config (const char *key, const char *value)
                else
                        do_reverse_lookups = 0;
        }
+       else if (strcasecmp (key, "IncludeUnitID") == 0)
+       {
+               if (IS_TRUE (value))
+                       include_unit_id = 1;
+               else
+                       include_unit_id = 0;
+       }
        else
        {
                return (-1);
@@ -309,6 +322,18 @@ static void ntpd_submit (char *type, char *type_inst, double value)
        plugin_dispatch_values (&vl);
 }
 
+/* Each time a peer is polled, ntpd shifts the reach register to the left and
+ * sets the LSB based on whether the peer was reachable. If the LSB is zero,
+ * the values are out of date. */
+static void ntpd_submit_reach (char *type, char *type_inst, uint8_t reach,
+               double value)
+{
+       if (!(reach & 1))
+               value = NAN;
+
+       ntpd_submit (type, type_inst, value);
+}
+
 static int ntpd_connect (void)
 {
        char *host;
@@ -763,6 +788,108 @@ static double ntpd_read_fp (int32_t val_int)
        return (val_double);
 }
 
+static uint32_t ntpd_get_refclock_id (struct info_peer_summary const *peer_info)
+{
+       uint32_t addr = ntohl (peer_info->srcadr);
+       uint32_t refclock_id = (addr >> 8) & 0x00FF;
+
+       return (refclock_id);
+}
+
+static int ntpd_get_name_from_address (char *buffer, size_t buffer_size,
+               struct info_peer_summary const *peer_info, _Bool do_reverse_lookup)
+{
+       struct sockaddr_storage sa;
+       socklen_t sa_len;
+       int flags = 0;
+       int status;
+
+       memset (&sa, 0, sizeof (sa));
+
+       if (peer_info->v6_flag)
+       {
+               struct sockaddr_in6 sa6;
+
+               assert (sizeof (sa) >= sizeof (sa6));
+
+               memset (&sa6, 0, sizeof (sa6));
+               sa6.sin6_family = AF_INET6;
+               sa6.sin6_port = htons (123);
+               memcpy (&sa6.sin6_addr, &peer_info->srcadr6,
+                               sizeof (struct in6_addr));
+               sa_len = sizeof (sa6);
+
+               memcpy (&sa, &sa6, sizeof (sa6));
+       }
+       else
+       {
+               struct sockaddr_in sa4;
+
+               assert (sizeof (sa) >= sizeof (sa4));
+
+               memset (&sa4, 0, sizeof (sa4));
+               sa4.sin_family = AF_INET;
+               sa4.sin_port = htons (123);
+               memcpy (&sa4.sin_addr, &peer_info->srcadr,
+                               sizeof (struct in_addr));
+               sa_len = sizeof (sa4);
+
+               memcpy (&sa, &sa4, sizeof (sa4));
+       }
+
+       if (!do_reverse_lookup)
+               flags |= NI_NUMERICHOST;
+
+       status = getnameinfo ((struct sockaddr const *) &sa, sa_len,
+                       buffer, buffer_size,
+                       NULL, 0, /* No port name */
+                       flags);
+       if (status != 0)
+       {
+               char errbuf[1024];
+               ERROR ("ntpd plugin: getnameinfo failed: %s",
+                               (status == EAI_SYSTEM)
+                               ? sstrerror (errno, errbuf, sizeof (errbuf))
+                               : gai_strerror (status));
+               return (-1);
+       }
+
+       return (0);
+} /* ntpd_get_name_from_address */
+
+static int ntpd_get_name_refclock (char *buffer, size_t buffer_size,
+               struct info_peer_summary const *peer_info)
+{
+       uint32_t refclock_id = ntpd_get_refclock_id (peer_info);
+       uint32_t unit_id = ntohl (peer_info->srcadr) & 0x00FF;
+
+       if (refclock_id >= refclock_names_num)
+               return (ntpd_get_name_from_address (buffer, buffer_size,
+                                       peer_info,
+                                       /* do_reverse_lookup = */ 0));
+
+       if (include_unit_id)
+               ssnprintf (buffer, buffer_size, "%s-%"PRIu32,
+                               refclock_names[refclock_id], unit_id);
+       else
+               sstrncpy (buffer, refclock_names[refclock_id], buffer_size);
+
+       return (0);
+} /* int ntpd_get_name_refclock */
+
+static int ntpd_get_name (char *buffer, size_t buffer_size,
+               struct info_peer_summary const *peer_info)
+{
+       uint32_t addr = ntohl (peer_info->srcadr);
+
+       if (!peer_info->v6_flag && ((addr & REFCLOCK_MASK) == REFCLOCK_ADDR))
+               return (ntpd_get_name_refclock (buffer, buffer_size,
+                                       peer_info));
+       else
+               return (ntpd_get_name_from_address (buffer, buffer_size,
+                                       peer_info, do_reverse_lookups));
+} /* int ntpd_addr_to_name */
+
 static int ntpd_read (void)
 {
        struct info_kernel *ik;
@@ -837,99 +964,26 @@ static int ntpd_read (void)
                double offset;
 
                char peername[NI_MAXHOST];
-               int refclock_id;
-               
-               ptr = ps + i;
-               refclock_id = 0;
+               uint32_t refclock_id;
 
-               /* Convert the `long floating point' offset value to double */
-               M_LFPTOD (ntohl (ptr->offset_int), ntohl (ptr->offset_frc), offset);
+               ptr = ps + i;
 
-               /* Special IP addresses for hardware clocks and stuff.. */
-               if (!ptr->v6_flag
-                               && ((ntohl (ptr->srcadr) & REFCLOCK_MASK)
-                                       == REFCLOCK_ADDR))
+               status = ntpd_get_name (peername, sizeof (peername), ptr);
+               if (status != 0)
                {
-                       struct in_addr  addr_obj;
-                       char *addr_str;
-
-                       refclock_id = (ntohl (ptr->srcadr) >> 8) & 0x000000FF;
-
-                       if (refclock_id < refclock_names_num)
-                       {
-                               sstrncpy (peername, refclock_names[refclock_id],
-                                               sizeof (peername));
-                       }
-                       else
-                       {
-                               memset ((void *) &addr_obj, '\0', sizeof (addr_obj));
-                               addr_obj.s_addr = ptr->srcadr;
-                               addr_str = inet_ntoa (addr_obj);
-
-                               sstrncpy (peername, addr_str, sizeof (peername));
-                       }
+                       ERROR ("ntpd plugin: Determining name of peer failed.");
+                       continue;
                }
-               else /* Normal network host. */
-               {
-                       struct sockaddr_storage sa;
-                       socklen_t sa_len;
-                       int flags = 0;
-
-                       memset (&sa, '\0', sizeof (sa));
-
-                       if (ptr->v6_flag)
-                       {
-                               struct sockaddr_in6 sa6;
-
-                               assert (sizeof (sa) >= sizeof (sa6));
-
-                               memset (&sa6, 0, sizeof (sa6));
-                               sa6.sin6_family = AF_INET6;
-                               sa6.sin6_port = htons (123);
-                               memcpy (&sa6.sin6_addr, &ptr->srcadr6,
-                                               sizeof (struct in6_addr));
-                               sa_len = sizeof (sa6);
-
-                               memcpy (&sa, &sa6, sizeof (sa6));
-                       }
-                       else
-                       {
-                               struct sockaddr_in sa4;
-
-                               assert (sizeof (sa) >= sizeof (sa4));
 
-                               memset (&sa4, 0, sizeof (sa4));
-                               sa4.sin_family = AF_INET;
-                               sa4.sin_port = htons (123);
-                               memcpy (&sa4.sin_addr, &ptr->srcadr,
-                                               sizeof (struct in_addr));
-                               sa_len = sizeof (sa4);
+               refclock_id = ntpd_get_refclock_id (ptr);
 
-                               memcpy (&sa, &sa4, sizeof (sa4));
-                       }
-
-                       if (do_reverse_lookups == 0)
-                               flags |= NI_NUMERICHOST;
-
-                       status = getnameinfo ((const struct sockaddr *) &sa,
-                                       sa_len,
-                                       peername, sizeof (peername),
-                                       NULL, 0, /* No port name */
-                                       flags);
-                       if (status != 0)
-                       {
-                               char errbuf[1024];
-                               ERROR ("ntpd plugin: getnameinfo failed: %s",
-                                               (status == EAI_SYSTEM)
-                                               ? sstrerror (errno, errbuf, sizeof (errbuf))
-                                               : gai_strerror (status));
-                               continue;
-                       }
-               }
+               /* Convert the `long floating point' offset value to double */
+               M_LFPTOD (ntohl (ptr->offset_int), ntohl (ptr->offset_frc), offset);
 
                DEBUG ("peer %i:\n"
                                "  peername   = %s\n"
                                "  srcadr     = 0x%08x\n"
+                               "  reach      = 0%03o\n"
                                "  delay      = %f\n"
                                "  offset_int = %i\n"
                                "  offset_frc = %i\n"
@@ -938,6 +992,7 @@ static int ntpd_read (void)
                                i,
                                peername,
                                ntohl (ptr->srcadr),
+                               ptr->reach,
                                ntpd_read_fp (ptr->delay),
                                ntohl (ptr->offset_int),
                                ntohl (ptr->offset_frc),
@@ -945,10 +1000,13 @@ static int ntpd_read (void)
                                ntpd_read_fp (ptr->dispersion));
 
                if (refclock_id != 1) /* not the system clock (offset will always be zero.. */
-                       ntpd_submit ("time_offset", peername, offset);
-               ntpd_submit ("time_dispersion", peername, ntpd_read_fp (ptr->dispersion));
+                       ntpd_submit_reach ("time_offset", peername, ptr->reach,
+                                       offset);
+               ntpd_submit_reach ("time_dispersion", peername, ptr->reach,
+                               ntpd_read_fp (ptr->dispersion));
                if (refclock_id == 0) /* not a reference clock */
-                       ntpd_submit ("delay", peername, ntpd_read_fp (ptr->delay));
+                       ntpd_submit_reach ("delay", peername, ptr->reach,
+                                       ntpd_read_fp (ptr->delay));
        }
 
        free (ps);
index 86643ca3b09d608ca9272eec0b9d462c063d8f1f..ab0812b703ec441c745d4afbe2bcdaf2ca79025f 100644 (file)
@@ -87,6 +87,7 @@ OCIError *oci_error = NULL;
  * Functions
  */
 static void o_report_error (const char *where, /* {{{ */
+    const char *db_name, const char *query_name,
     const char *what, OCIError *eh)
 {
   char buffer[2048];
@@ -94,6 +95,11 @@ static void o_report_error (const char *where, /* {{{ */
   int status;
   unsigned int record_number;
 
+  if (db_name == NULL)
+    db_name = "(none)";
+  if (query_name == NULL)
+    query_name = "(none)";
+
   /* An operation may cause / return multiple errors. Loop until we have
    * handled all errors available (with a fail-save limit of 16). */
   for (record_number = 1; record_number <= 16; record_number++)
@@ -123,12 +129,14 @@ static void o_report_error (const char *where, /* {{{ */
         buffer[buffer_length] = 0;
       }
 
-      ERROR ("oracle plugin: %s: %s failed: %s", where, what, buffer);
+      ERROR ("oracle plugin: %s (db = %s, query = %s): %s failed: %s",
+          where, db_name, query_name, what, buffer);
     }
     else
     {
-      ERROR ("oracle plugin: %s: %s failed. Additionally, OCIErrorGet failed with status %i.",
-          where, what, status);
+      ERROR ("oracle plugin: %s (db = %s, query = %s): %s failed. "
+          "Additionally, OCIErrorGet failed with status %i.",
+          where, db_name, query_name, what, status);
       return;
     }
   }
@@ -408,7 +416,8 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
         OCI_HTYPE_STMT, /* user_data_size = */ 0, /* user_data = */ NULL);
     if (status != OCI_SUCCESS)
     {
-      o_report_error ("o_read_database_query", "OCIHandleAlloc", oci_error);
+      o_report_error ("o_read_database_query", db->name,
+          udb_query_get_name (q), "OCIHandleAlloc", oci_error);
       oci_statement = NULL;
       return (-1);
     }
@@ -419,7 +428,8 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
         /* mode     = */ OCI_DEFAULT);
     if (status != OCI_SUCCESS)
     {
-      o_report_error ("o_read_database_query", "OCIStmtPrepare", oci_error);
+      o_report_error ("o_read_database_query", db->name,
+          udb_query_get_name (q), "OCIStmtPrepare", oci_error);
       OCIHandleFree (oci_statement, OCI_HTYPE_STMT);
       oci_statement = NULL;
       return (-1);
@@ -443,10 +453,8 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
       /* mode = */ OCI_DEFAULT);
   if (status != OCI_SUCCESS)
   {
-    DEBUG ("oracle plugin: o_read_database_query: status = %i (%#x)", status, status);
-    o_report_error ("o_read_database_query", "OCIStmtExecute", oci_error);
-    ERROR ("oracle plugin: o_read_database_query: "
-        "Failing statement was: %s", udb_query_get_statement (q));
+    o_report_error ("o_read_database_query", db->name, udb_query_get_name (q),
+        "OCIStmtExecute", oci_error);
     return (-1);
   } /* }}} */
 
@@ -459,7 +467,8 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
         OCI_ATTR_PARAM_COUNT, oci_error);
     if (status != OCI_SUCCESS)
     {
-      o_report_error ("o_read_database_query", "OCIAttrGet", oci_error);
+      o_report_error ("o_read_database_query", db->name,
+          udb_query_get_name (q), "OCIAttrGet", oci_error);
       return (-1);
     } /* }}} */
 
@@ -537,8 +546,10 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
     if (status != OCI_SUCCESS)
     {
       /* This is probably alright */
-      DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);", status, status);
-      o_report_error ("o_read_database_query", "OCIParamGet", oci_error);
+      DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);",
+          status, status);
+      o_report_error ("o_read_database_query", db->name,
+          udb_query_get_name (q), "OCIParamGet", oci_error);
       status = OCI_SUCCESS;
       break;
     }
@@ -550,8 +561,8 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
     if (status != OCI_SUCCESS)
     {
       OCIDescriptorFree (oci_param, OCI_DTYPE_PARAM);
-      o_report_error ("o_read_database_query", "OCIAttrGet (OCI_ATTR_NAME)",
-          oci_error);
+      o_report_error ("o_read_database_query", db->name,
+          udb_query_get_name (q), "OCIAttrGet (OCI_ATTR_NAME)", oci_error);
       continue;
     }
 
@@ -576,7 +587,8 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
         NULL, NULL, NULL, OCI_DEFAULT);
     if (status != OCI_SUCCESS)
     {
-      o_report_error ("o_read_database_query", "OCIDefineByPos", oci_error);
+      o_report_error ("o_read_database_query", db->name,
+          udb_query_get_name (q), "OCIDefineByPos", oci_error);
       continue;
     }
   } /* for (j = 1; j <= param_counter; j++) */
@@ -608,7 +620,8 @@ static int o_read_database_query (o_database_t *db, /* {{{ */
     }
     else if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
     {
-      o_report_error ("o_read_database_query", "OCIStmtFetch2", oci_error);
+      o_report_error ("o_read_database_query", db->name,
+          udb_query_get_name (q), "OCIStmtFetch2", oci_error);
       break;
     }
 
@@ -645,7 +658,8 @@ static int o_read_database (o_database_t *db) /* {{{ */
         OCI_ATTR_SERVER, oci_error);
     if (status != OCI_SUCCESS)
     {
-      o_report_error ("o_read_database", "OCIAttrGet", oci_error);
+      o_report_error ("o_read_database", db->name, NULL, "OCIAttrGet",
+          oci_error);
       return (-1);
     }
 
@@ -661,7 +675,8 @@ static int o_read_database (o_database_t *db) /* {{{ */
           OCI_ATTR_SERVER_STATUS, oci_error);
       if (status != OCI_SUCCESS)
       {
-        o_report_error ("o_read_database", "OCIAttrGet", oci_error);
+        o_report_error ("o_read_database", db->name, NULL, "OCIAttrGet",
+            oci_error);
         return (-1);
       }
     }
@@ -684,7 +699,11 @@ static int o_read_database (o_database_t *db) /* {{{ */
         (OraText *) db->connect_id, (ub4) strlen (db->connect_id));
     if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
     {
-      o_report_error ("o_read_database", "OCILogon", oci_error);
+      char errfunc[256];
+
+      ssnprintf (errfunc, sizeof (errfunc), "OCILogon(\"%s\")", db->connect_id);
+
+      o_report_error ("o_read_database", db->name, NULL, errfunc, oci_error);
       DEBUG ("oracle plugin: OCILogon (%s): db->oci_service_context = %p;",
           db->connect_id, db->oci_service_context);
       db->oci_service_context = NULL;
index 0a5e66c25d934acd4de939cd049e6070a3121ca9..675505bb3576919d741a3c31bb86fac5e6acce08 100644 (file)
@@ -95,6 +95,7 @@ typedef enum {
        C_PSQL_PARAM_DB,
        C_PSQL_PARAM_USER,
        C_PSQL_PARAM_INTERVAL,
+       C_PSQL_PARAM_INSTANCE,
 } c_psql_param_t;
 
 /* Parameter configuration. Stored as `user data' in the query objects. */
@@ -125,6 +126,8 @@ typedef struct {
        char *user;
        char *password;
 
+       char *instance;
+
        char *sslmode;
 
        char *krbsrvname;
@@ -177,6 +180,8 @@ static c_psql_database_t *c_psql_database_new (const char *name)
        db->user       = NULL;
        db->password   = NULL;
 
+       db->instance   = sstrdup (name);
+
        db->sslmode    = NULL;
 
        db->krbsrvname = NULL;
@@ -208,6 +213,8 @@ static void c_psql_database_delete (void *data)
        sfree (db->user);
        sfree (db->password);
 
+       sfree (db->instance);
+
        sfree (db->sslmode);
 
        sfree (db->krbsrvname);
@@ -271,8 +278,9 @@ static int c_psql_check_connection (c_psql_database_t *db)
 
                if (CONNECTION_OK != PQstatus (db->conn)) {
                        c_complain (LOG_ERR, &db->conn_complaint,
-                                       "Failed to connect to database %s: %s",
-                                       db->database, PQerrorMessage (db->conn));
+                                       "Failed to connect to database %s (%s): %s",
+                                       db->database, db->instance,
+                                       PQerrorMessage (db->conn));
                        return -1;
                }
 
@@ -340,6 +348,9 @@ static PGresult *c_psql_exec_query_params (c_psql_database_t *db,
                                                ? CDTIME_T_TO_DOUBLE (db->interval) : interval_g);
                                params[i] = interval;
                                break;
+                       case C_PSQL_PARAM_INSTANCE:
+                               params[i] = db->instance;
+                               break;
                        default:
                                assert (0);
                }
@@ -377,9 +388,10 @@ static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q,
        else if ((NULL == data) || (0 == data->params_num))
                res = c_psql_exec_query_noparams (db, q);
        else {
-               log_err ("Connection to database \"%s\" does not support parameters "
-                               "(protocol version %d) - cannot execute query \"%s\".",
-                               db->database, db->proto_version,
+               log_err ("Connection to database \"%s\" (%s) does not support "
+                               "parameters (protocol version %d) - "
+                               "cannot execute query \"%s\".",
+                               db->database, db->instance, db->proto_version,
                                udb_query_get_name (q));
                return -1;
        }
@@ -436,7 +448,7 @@ static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q,
                host = db->host;
 
        status = udb_query_prepare_result (q, prep_area, host, "postgresql",
-                       db->database, column_names, (size_t) column_num, db->interval);
+                       db->instance, column_names, (size_t) column_num, db->interval);
        if (0 != status) {
                log_err ("udb_query_prepare_result failed with status %i.",
                                status);
@@ -487,6 +499,7 @@ static int c_psql_read (user_data_t *ud)
        db = ud->data;
 
        assert (NULL != db->database);
+       assert (NULL != db->instance);
 
        if (0 != c_psql_check_connection (db))
                return -1;
@@ -558,6 +571,8 @@ static int config_query_param_add (udb_query_t *q, oconfig_item_t *ci)
                data->params[data->params_num] = C_PSQL_PARAM_USER;
        else if (0 == strcasecmp (param_str, "interval"))
                data->params[data->params_num] = C_PSQL_PARAM_INTERVAL;
+       else if (0 == strcasecmp (param_str, "instance"))
+               data->params[data->params_num] = C_PSQL_PARAM_INSTANCE;
        else {
                log_err ("Invalid parameter \"%s\".", param_str);
                return 1;
@@ -612,6 +627,8 @@ static int c_psql_config_database (oconfig_item_t *ci)
                        cf_util_get_string (c, &db->user);
                else if (0 == strcasecmp (c->key, "Password"))
                        cf_util_get_string (c, &db->password);
+               else if (0 == strcasecmp (c->key, "Instance"))
+                       cf_util_get_string (c, &db->instance);
                else if (0 == strcasecmp (c->key, "SSLMode"))
                        cf_util_get_string (c, &db->sslmode);
                else if (0 == strcasecmp (c->key, "KRBSrvName"))
@@ -665,7 +682,7 @@ static int c_psql_config_database (oconfig_item_t *ci)
        ud.data = db;
        ud.free_func = c_psql_database_delete;
 
-       ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->database);
+       ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->instance);
 
        CDTIME_T_TO_TIMESPEC (db->interval, &cb_interval);
 
index 66237dc376be56414b29d62000d8a39c6fd70e1b..c77859d9e7d9f6953abe3fb87c3e16aebdd44357 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright (C) 2009       Andrés J. Díaz
  * Copyright (C) 2009       Manuel Sanmartin
  * Copyright (C) 2010       Clément Stenac
+ * Copyright (C) 2012       Cosmin Ioiart
  *
  * 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
@@ -30,6 +31,7 @@
  *   Andrés J. Díaz <ajdiaz at connectical.com>
  *   Manuel Sanmartin
  *   Clément Stenac <clement.stenac at diwi.org>
+ *   Cosmin Ioiart <cioiart at gmail.com>
  **/
 
 #include "collectd.h"
 #define MAXARGLN 1024
 /* #endif HAVE_PROCINFO_H */
 
+#elif KERNEL_SOLARIS
+# include <procfs.h>
+# include <dirent.h>
+/* #endif KERNEL_SOLARIS */
+
 #else
 # error "No applicable input method."
 #endif
 # include <regex.h>
 #endif
 
+#if HAVE_KSTAT_H
+# include <kstat.h>
+#endif
+
 #ifndef ARG_MAX
 #  define ARG_MAX 4096
 #endif
@@ -216,8 +227,8 @@ int getargs (struct procentry64 *processBuffer, int bufferLen, char *argsBuffer,
 #endif /* HAVE_PROCINFO_H */
 
 /* put name of process from config to list_head_g tree
  list_head_g is a list of 'procstat_t' structs with
  processes names we want to watch */
* list_head_g is a list of 'procstat_t' structs with
* processes names we want to watch */
 static void ps_list_register (const char *name, const char *regexp)
 {
        procstat_t *new;
@@ -712,7 +723,7 @@ static void ps_submit_proc_list (procstat_t *ps)
        }
 
        DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; "
-                        "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
+                       "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
                        "vmem_code = %lu; "
                        "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
                        "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
@@ -726,6 +737,26 @@ static void ps_submit_proc_list (procstat_t *ps)
                        ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw);
 } /* void ps_submit_proc_list */
 
+#if KERNEL_LINUX || KERNEL_SOLARIS
+static void ps_submit_fork_rate (derive_t value)
+{
+       value_t values[1];
+       value_list_t vl = VALUE_LIST_INIT;
+
+       values[0].derive = value;
+
+       vl.values = values;
+       vl.values_len = 1;
+       sstrncpy(vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy(vl.plugin, "processes", sizeof (vl.plugin));
+       sstrncpy(vl.plugin_instance, "", sizeof (vl.plugin_instance));
+       sstrncpy(vl.type, "fork_rate", sizeof (vl.type));
+       sstrncpy(vl.type_instance, "", sizeof (vl.type_instance));
+
+       plugin_dispatch_values(&vl);
+}
+#endif /* KERNEL_LINUX || KERNEL_SOLARIS*/
+
 /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 #if KERNEL_LINUX
 static int ps_read_tasks (int pid)
@@ -780,7 +811,7 @@ static procstat_t *ps_read_vmem (int pid, procstat_t *ps)
                        continue;
 
                numfields = strsplit (buffer, fields,
-                                      STATIC_ARRAY_SIZE (fields));
+                               STATIC_ARRAY_SIZE (fields));
 
                if (numfields < 2)
                        continue;
@@ -1117,70 +1148,226 @@ static char *ps_get_cmdline (pid_t pid, char *name, char *buf, size_t buf_len)
        return buf;
 } /* char *ps_get_cmdline (...) */
 
-static unsigned long read_fork_rate ()
+static int read_fork_rate ()
 {
        FILE *proc_stat;
-       char buf[1024];
-       unsigned long result = 0;
-       int numfields;
-       char *fields[3];
+       char buffer[1024];
+       value_t value;
+       _Bool value_valid = 0;
 
-       proc_stat = fopen("/proc/stat", "r");
-       if (proc_stat == NULL) {
+       proc_stat = fopen ("/proc/stat", "r");
+       if (proc_stat == NULL)
+       {
                char errbuf[1024];
                ERROR ("processes plugin: fopen (/proc/stat) failed: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
-               return ULONG_MAX;
+               return (-1);
        }
 
-       while (fgets (buf, sizeof(buf), proc_stat) != NULL)
+       while (fgets (buffer, sizeof (buffer), proc_stat) != NULL)
        {
-               char *endptr;
+               int status;
+               char *fields[3];
+               int fields_num;
 
-               numfields = strsplit(buf, fields, STATIC_ARRAY_SIZE (fields));
-               if (numfields != 2)
+               fields_num = strsplit (buffer, fields,
+                               STATIC_ARRAY_SIZE (fields));
+               if (fields_num != 2)
                        continue;
 
                if (strcmp ("processes", fields[0]) != 0)
                        continue;
 
-               errno = 0;
-               endptr = NULL;
-               result = strtoul(fields[1], &endptr, /* base = */ 10);
-               if ((endptr == fields[1]) || (errno != 0)) {
-                       ERROR ("processes plugin: Cannot parse fork rate: %s",
-                                       fields[1]);
-                       result = ULONG_MAX;
-                       break;
-               }
+               status = parse_value (fields[1], &value, DS_TYPE_DERIVE);
+               if (status == 0)
+                       value_valid = 1;
 
                break;
        }
-
        fclose(proc_stat);
 
-       return result;
+       if (!value_valid)
+               return (-1);
+
+       ps_submit_fork_rate (value.derive);
+       return (0);
 }
+#endif /*KERNEL_LINUX */
 
-static void ps_submit_fork_rate (unsigned long value)
+#if KERNEL_SOLARIS
+static const char *ps_get_cmdline (pid_t pid, /* {{{ */
+               char *buffer, size_t buffer_size)
 {
-       value_t values[1];
-       value_list_t vl = VALUE_LIST_INIT;
+       char path[PATH_MAX];
+       psinfo_t info;
+       int status;
 
-       values[0].derive = (derive_t) value;
+       snprintf(path, sizeof (path), "/proc/%i/psinfo", pid);
 
-       vl.values = values;
-       vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
-       sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
-       sstrncpy (vl.type, "fork_rate", sizeof (vl.type));
-       sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
+       status = read_file_contents (path, (void *) &info, sizeof (info));
+       if (status != ((int) buffer_size))
+       {
+               ERROR ("processes plugin: Unexpected return value "
+                               "while reading \"%s\": "
+                               "Returned %i but expected %zu.",
+                               path, status, buffer_size);
+               return (NULL);
+       }
 
-       plugin_dispatch_values (&vl);
+       info.pr_psargs[sizeof (info.pr_psargs) - 1] = 0;
+       sstrncpy (buffer, info.pr_psargs, buffer_size);
+
+       return (buffer);
+} /* }}} int ps_get_cmdline */
+
+/*
+ * Reads process information on the Solaris OS. The information comes mainly from
+ * /proc/PID/status, /proc/PID/psinfo and /proc/PID/usage
+ * The values for input and ouput chars are calculated "by hand"
+ * Added a few "solaris" specific process states as well
+ */
+static int ps_read_process(int pid, procstat_t *ps, char *state)
+{
+       char filename[64];
+       char f_psinfo[64], f_usage[64];
+       char *buffer;
+
+       pstatus_t *myStatus;
+       psinfo_t *myInfo;
+       prusage_t *myUsage;
+
+       snprintf(filename, sizeof (filename), "/proc/%i/status", pid);
+       snprintf(f_psinfo, sizeof (f_psinfo), "/proc/%i/psinfo", pid);
+       snprintf(f_usage, sizeof (f_usage), "/proc/%i/usage", pid);
+
+
+       buffer = malloc(sizeof (pstatus_t));
+       memset(buffer, 0, sizeof (pstatus_t));
+       read_file_contents(filename, buffer, sizeof (pstatus_t));
+       myStatus = (pstatus_t *) buffer;
+
+       buffer = malloc(sizeof (psinfo_t));
+       memset(buffer, 0, sizeof(psinfo_t));
+       read_file_contents(f_psinfo, buffer, sizeof (psinfo_t));
+       myInfo = (psinfo_t *) buffer;
+
+       buffer = malloc(sizeof (prusage_t));
+       memset(buffer, 0, sizeof(prusage_t));
+       read_file_contents(f_usage, buffer, sizeof (prusage_t));
+       myUsage = (prusage_t *) buffer;
+
+       sstrncpy(ps->name, myInfo->pr_fname, sizeof (myInfo->pr_fname));
+       ps->num_lwp = myStatus->pr_nlwp;
+       if (myInfo->pr_wstat != 0) {
+               ps->num_proc = 0;
+               ps->num_lwp = 0;
+               *state = (char) 'Z';
+               return (0);
+       } else {
+               ps->num_proc = 1;
+               ps->num_lwp = myInfo->pr_nlwp;
+       }
+
+       /*
+        * Convert system time and user time from nanoseconds to microseconds
+        * for compatibility with the linux module
+        */
+       ps->cpu_system_counter = myStatus -> pr_stime.tv_nsec / 1000;
+       ps->cpu_user_counter = myStatus -> pr_utime.tv_nsec / 1000;
+
+       /*
+        * Convert rssize from KB to bytes to be consistent w/ the linux module
+        */
+       ps->vmem_rss = myInfo->pr_rssize * 1024;
+       ps->vmem_size = myInfo->pr_size * 1024;
+       ps->vmem_minflt_counter = myUsage->pr_minf;
+       ps->vmem_majflt_counter = myUsage->pr_majf;
+
+       /*
+        * TODO: Data and code segment calculations for Solaris
+        */
+
+       ps->vmem_data = -1;
+       ps->vmem_code = -1;
+       ps->stack_size = myStatus->pr_stksize;
+
+       /*
+        * Calculating input/ouput chars
+        * Formula used is total chars / total blocks => chars/block
+        * then convert input/output blocks to chars
+        */
+       ulong_t tot_chars = myUsage->pr_ioch;
+       ulong_t tot_blocks = myUsage->pr_inblk + myUsage->pr_oublk;
+       ulong_t chars_per_block = 1;
+       if (tot_blocks != 0)
+               chars_per_block = tot_chars / tot_blocks;
+       ps->io_rchar = myUsage->pr_inblk * chars_per_block;
+       ps->io_wchar = myUsage->pr_oublk * chars_per_block;
+       ps->io_syscr = myUsage->pr_sysc;
+       ps->io_syscw = myUsage->pr_sysc;
+
+
+       /*
+        * TODO: Find way of setting BLOCKED and PAGING status
+        */
+
+       *state = (char) 'R';
+       if (myStatus->pr_flags & PR_ASLEEP)
+               *state = (char) 'S';
+       else if (myStatus->pr_flags & PR_STOPPED)
+               *state = (char) 'T';
+       else if (myStatus->pr_flags & PR_DETACH)
+               *state = (char) 'E';
+       else if (myStatus->pr_flags & PR_DAEMON)
+               *state = (char) 'A';
+       else if (myStatus->pr_flags & PR_ISSYS)
+               *state = (char) 'Y';
+       else if (myStatus->pr_flags & PR_ORPHAN)
+               *state = (char) 'O';
+
+       sfree(myStatus);
+       sfree(myInfo);
+       sfree(myUsage);
+
+       return (0);
 }
 
-#endif /* KERNEL_LINUX */
+/*
+ * Reads the number of threads created since the last reboot. On Solaris these
+ * are retrieved from kstat (module cpu, name sys, class misc, stat nthreads).
+ * The result is the sum for all the threads created on each cpu
+ */
+static int read_fork_rate()
+{
+       extern kstat_ctl_t *kc;
+       kstat_t *ksp_chain = NULL;
+       derive_t result = 0;
+
+       if (kc == NULL)
+               return (-1);
+
+       for (ksp_chain = kc->kc_chain;
+                       ksp_chain != NULL;
+                       ksp_chain = ksp_chain->ks_next)
+       {
+               if ((strcmp (ksp_chain->ks_module, "cpu") == 0)
+                               && (strcmp (ksp_chain->ks_name, "sys") == 0)
+                               && (strcmp (ksp_chain->ks_class, "misc") == 0))
+               {
+                       long long tmp;
+
+                       kstat_read (kc, ksp_chain, NULL);
+
+                       tmp = get_kstat_value(ksp_chain, "nthreads");
+                       if (tmp != -1LL)
+                               result += tmp;
+               }
+       }
+
+       ps_submit_fork_rate (result);
+       return (0);
+}
+#endif /* KERNEL_SOLARIS */
 
 #if HAVE_THREAD_INFO
 static int mach_get_task_name (task_t t, int *pid, char *name, size_t name_max_len)
@@ -1506,8 +1693,6 @@ static int ps_read (void)
        procstat_entry_t pse;
        char       state;
 
-       unsigned long fork_rate;
-
        procstat_t *ps_ptr;
 
        running = sleeping = zombies = stopped = paging = blocked = 0;
@@ -1589,9 +1774,7 @@ static int ps_read (void)
        for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
                ps_submit_proc_list (ps_ptr);
 
-       fork_rate = read_fork_rate();
-       if (fork_rate != ULONG_MAX)
-               ps_submit_fork_rate(fork_rate);
+       read_fork_rate();
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
@@ -1605,9 +1788,9 @@ static int ps_read (void)
 
        kvm_t *kd;
        char errbuf[1024];
-       struct kinfo_proc *procs;          /* array of processes */
+       struct kinfo_proc *procs;          /* array of processes */
        struct kinfo_proc *proc_ptr = NULL;
-       int count;                         /* returns number of processes */
+       int count;                         /* returns number of processes */
        int i;
 
        procstat_t *ps_ptr;
@@ -1778,7 +1961,7 @@ static int ps_read (void)
                                if (procentry[i].pi_pid == 0)
                                        cmdline = "swapper";
                                cargs = cmdline;
-                       }
+                       }
                        else
                        {
                                if (getargs(&procentry[i], sizeof(struct procentry64), arglist, MAXARGLN) >= 0)
@@ -1870,7 +2053,118 @@ static int ps_read (void)
 
        for (ps = list_head_g; ps != NULL; ps = ps->next)
                ps_submit_proc_list (ps);
-#endif /* HAVE_PROCINFO_H */
+/* #endif HAVE_PROCINFO_H */
+
+#elif KERNEL_SOLARIS
+       /*
+        * The Solaris section adds a few more process states and removes some
+        * process states compared to linux. Most notably there is no "PAGING"
+        * and "BLOCKED" state for a process.  The rest is similar to the linux
+        * code.
+        */
+       int running = 0;
+       int sleeping = 0;
+       int zombies = 0;
+       int stopped = 0;
+       int detached = 0;
+       int daemon = 0;
+       int system = 0;
+       int orphan = 0;
+
+       struct dirent *ent;
+       DIR *proc;
+
+       int status;
+       procstat_t *ps_ptr;
+       char state;
+
+       char cmdline[PRARGSZ];
+
+       ps_list_reset ();
+
+       proc = opendir ("/proc");
+       if (proc == NULL)
+               return (-1);
+
+       while ((ent = readdir(proc)) != NULL)
+       {
+               int pid;
+               struct procstat ps;
+               procstat_entry_t pse;
+
+               if (!isdigit ((int) ent->d_name[0]))
+                       continue;
+
+               if ((pid = atoi (ent->d_name)) < 1)
+                       continue;
+
+               status = ps_read_process (pid, &ps, &state);
+               if (status != 0)
+               {
+                       DEBUG("ps_read_process failed: %i", status);
+                       continue;
+               }
+
+               pse.id = pid;
+               pse.age = 0;
+
+               pse.num_proc   = ps.num_proc;
+               pse.num_lwp    = ps.num_lwp;
+               pse.vmem_size  = ps.vmem_size;
+               pse.vmem_rss   = ps.vmem_rss;
+               pse.vmem_data  = ps.vmem_data;
+               pse.vmem_code  = ps.vmem_code;
+               pse.stack_size = ps.stack_size;
+
+               pse.vmem_minflt = 0;
+               pse.vmem_minflt_counter = ps.vmem_minflt_counter;
+               pse.vmem_majflt = 0;
+               pse.vmem_majflt_counter = ps.vmem_majflt_counter;
+
+               pse.cpu_user = 0;
+               pse.cpu_user_counter = ps.cpu_user_counter;
+               pse.cpu_system = 0;
+               pse.cpu_system_counter = ps.cpu_system_counter;
+
+               pse.io_rchar = ps.io_rchar;
+               pse.io_wchar = ps.io_wchar;
+               pse.io_syscr = ps.io_syscr;
+               pse.io_syscw = ps.io_syscw;
+
+               switch (state)
+               {
+                       case 'R': running++;  break;
+                       case 'S': sleeping++; break;
+                       case 'E': detached++; break;
+                       case 'Z': zombies++;  break;
+                       case 'T': stopped++;  break;
+                       case 'A': daemon++;   break;
+                       case 'Y': system++;   break;
+                       case 'O': orphan++;   break;
+               }
+
+
+               ps_list_add (ps.name,
+                               ps_get_cmdline ((pid_t) pid,
+                                       cmdline, sizeof (cmdline)),
+                               &pse);
+       } /* while(readdir) */
+       closedir (proc);
+
+       ps_submit_state ("running",  running);
+       ps_submit_state ("sleeping", sleeping);
+       ps_submit_state ("zombies",  zombies);
+       ps_submit_state ("stopped",  stopped);
+       ps_submit_state ("detached", detached);
+       ps_submit_state ("daemon",   daemon);
+       ps_submit_state ("system",   system);
+       ps_submit_state ("orphan",   orphan);
+
+       for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
+               ps_submit_proc_list (ps_ptr);
+
+       read_fork_rate();
+#endif /* KERNEL_SOLARIS */
 
        return (0);
 } /* int ps_read */
index b694e09db8f84a6be6767b20cacd50d37791b074..439cf4b8158501e2bd215228b0a369e9dcb32f52 100644 (file)
 #include <pthread.h>
 #include <credis.h>
 
+#ifndef HOST_NAME_MAX
+# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+#endif
+
 #define REDIS_DEF_HOST   "localhost"
 #define REDIS_DEF_PORT    6379
 #define REDIS_DEF_TIMEOUT 2000
@@ -50,6 +54,7 @@ struct redis_node_s
 {
   char name[MAX_REDIS_NODE_NAME];
   char host[HOST_NAME_MAX];
+  char passwd[HOST_NAME_MAX];
   int port;
   int timeout;
 
@@ -132,6 +137,8 @@ static int redis_config_node (oconfig_item_t *ci) /* {{{ */
     }
     else if (strcasecmp ("Timeout", option->key) == 0)
       status = cf_util_get_int (option, &rn.timeout);
+    else if (strcasecmp ("Password", option->key) == 0)
+      status = cf_util_get_string_buffer (option, rn.passwd, sizeof (rn.passwd));
     else
       WARNING ("redis plugin: Option `%s' not allowed inside a `Node' "
           "block. I'll ignore this option.", option->key);
@@ -251,6 +258,18 @@ static int redis_read (void) /* {{{ */
       continue;
     }
 
+    if (strlen (rn->passwd) > 0)
+    {
+      DEBUG ("redis plugin: authenticanting node `%s' passwd(%s).", rn->name, rn->passwd);
+      status = credis_auth(rh, rn->passwd);
+      if (status != 0)
+      {
+        WARNING ("redis plugin: unable to authenticate on node `%s'.", rn->name);
+        credis_close (rh);
+        continue;
+      }
+    }
+
     memset (&info, 0, sizeof (info));
     status = credis_info (rh, &info);
     if (status != 0)
index 11c1c6a7f85c3e96c2380602094c81f09e4bb97f..45553b7f250ee708ec620f8058a6f18691711f34 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/rrdcached.c
- * Copyright (C) 2008  Florian octo Forster
+ * Copyright (C) 2008-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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
@@ -33,8 +33,8 @@
  */
 static char *datadir = NULL;
 static char *daemon_address = NULL;
-static int config_create_files = 1;
-static int config_collect_stats = 1;
+static _Bool config_create_files = 1;
+static _Bool config_collect_stats = 1;
 static rrdcreate_config_t rrdcreate_config =
 {
        /* stepsize = */ 0,
@@ -161,89 +161,130 @@ static int value_list_to_filename (char *buffer, int buffer_len,
   return (0);
 } /* int value_list_to_filename */
 
-static const char *config_get_string (oconfig_item_t *ci)
+static int rc_config_get_int_positive (oconfig_item_t const *ci, int *ret)
 {
-  if ((ci->children_num != 0) || (ci->values_num != 1)
-      || ((ci->values[0].type != OCONFIG_TYPE_STRING)
-        && (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)))
+  int status;
+  int tmp = 0;
+
+  status = cf_util_get_int (ci, &tmp);
+  if (status != 0)
+    return (status);
+  if (tmp < 0)
+    return (EINVAL);
+
+  *ret = tmp;
+  return (0);
+} /* int rc_config_get_int_positive */
+
+static int rc_config_get_xff (oconfig_item_t const *ci, double *ret)
+{
+  double value;
+
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
   {
-    ERROR ("rrdcached plugin: %s expects a single string argument.",
-        ci->key);
-    return (NULL);
+    ERROR ("rrdcached plugin: The \"%s\" needs exactly one numeric argument "
+        "in the range [0.0, 1.0)", ci->key);
+    return (EINVAL);
   }
 
-  if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN) {
-    if (ci->values[0].value.boolean)
-      return "true";
-    else
-      return "false";
+  value = ci->values[0].value.number;
+  if ((value >= 0.0) && (value < 1.0))
+  {
+    *ret = value;
+    return (0);
   }
-  return (ci->values[0].value.string);
-} /* const char *config_get_string */
+
+  ERROR ("rrdcached plugin: The \"%s\" needs exactly one numeric argument "
+      "in the range [0.0, 1.0)", ci->key);
+  return (EINVAL);
+} /* int rc_config_get_xff */
+
+static int rc_config_add_timespan (int timespan)
+{
+  int *tmp;
+
+  if (timespan <= 0)
+    return (EINVAL);
+
+  tmp = realloc (rrdcreate_config.timespans,
+      sizeof (*rrdcreate_config.timespans)
+      * (rrdcreate_config.timespans_num + 1));
+  if (tmp == NULL)
+    return (ENOMEM);
+  rrdcreate_config.timespans = tmp;
+
+  rrdcreate_config.timespans[rrdcreate_config.timespans_num] = timespan;
+  rrdcreate_config.timespans_num++;
+
+  return (0);
+} /* int rc_config_add_timespan */
 
 static int rc_config (oconfig_item_t *ci)
 {
   int i;
 
-  for (i = 0; i < ci->children_num; ++i) {
-    const char *key = ci->children[i].key;
-    const char *value = config_get_string (ci->children + i);
-
-    if (value == NULL) /* config_get_strings prints error message */
-      continue;
+  for (i = 0; i < ci->children_num; i++)
+  {
+    oconfig_item_t const *child = ci->children + i;
+    const char *key = child->key;
+    int status = 0;
 
     if (strcasecmp ("DataDir", key) == 0)
     {
-      if (datadir != NULL)
-        free (datadir);
-      datadir = strdup (value);
-      if (datadir != NULL)
+      status = cf_util_get_string (child, &datadir);
+      if (status == 0)
       {
         int len = strlen (datadir);
+
         while ((len > 0) && (datadir[len - 1] == '/'))
         {
           len--;
-          datadir[len] = '\0';
+          datadir[len] = 0;
         }
+
         if (len <= 0)
-        {
-          free (datadir);
-          datadir = NULL;
-        }
+          sfree (datadir);
       }
     }
     else if (strcasecmp ("DaemonAddress", key) == 0)
-    {
-      sfree (daemon_address);
-      daemon_address = strdup (value);
-      if (daemon_address == NULL)
-      {
-        ERROR ("rrdcached plugin: strdup failed.");
-        continue;
-      }
-    }
+      status = cf_util_get_string (child, &daemon_address);
     else if (strcasecmp ("CreateFiles", key) == 0)
+      status = cf_util_get_boolean (child, &config_create_files);
+    else if (strcasecmp ("CollectStatistics", key) == 0)
+      status = cf_util_get_boolean (child, &config_collect_stats);
+    else if (strcasecmp ("StepSize", key) == 0)
     {
-      if (IS_FALSE (value))
-        config_create_files = 0;
-      else
-        config_create_files = 1;
+      int tmp = -1;
+
+      status = rc_config_get_int_positive (child, &tmp);
+      if (status == 0)
+        rrdcreate_config.stepsize = (unsigned long) tmp;
     }
-    else if (strcasecmp ("CollectStatistics", key) == 0)
+    else if (strcasecmp ("HeartBeat", key) == 0)
+      status = rc_config_get_int_positive (child, &rrdcreate_config.heartbeat);
+    else if (strcasecmp ("RRARows", key) == 0)
+      status = rc_config_get_int_positive (child, &rrdcreate_config.rrarows);
+    else if (strcasecmp ("RRATimespan", key) == 0)
     {
-      if (IS_FALSE (value))
-        config_collect_stats = 0;
-      else
-        config_collect_stats = 1;
+      int tmp = -1;
+      status = rc_config_get_int_positive (child, &tmp);
+      if (status == 0)
+        status = rc_config_add_timespan (tmp);
     }
+    else if (strcasecmp ("XFF", key) == 0)
+      status = rc_config_get_xff (child, &rrdcreate_config.xff);
     else
     {
       WARNING ("rrdcached plugin: Ignoring invalid option %s.", key);
       continue;
     }
+
+    if (status != 0)
+      WARNING ("rrdcached plugin: Handling the \"%s\" option failed.", key);
   }
 
-  if (daemon_address != NULL) {
+  if (daemon_address != NULL)
+  {
     plugin_register_write ("rrdcached", rc_write, /* user_data = */ NULL);
     plugin_register_flush ("rrdcached", rc_flush, /* user_data = */ NULL);
   }
@@ -262,7 +303,7 @@ static int rc_read (void)
   if (daemon_address == NULL)
     return (-1);
 
-  if (config_collect_stats == 0)
+  if (!config_collect_stats)
     return (-1);
 
   vl.values = values;
@@ -354,7 +395,7 @@ static int rc_read (void)
 
 static int rc_init (void)
 {
-  if (config_collect_stats != 0)
+  if (config_collect_stats)
     plugin_register_read ("rrdcached", rc_read);
 
   return (0);
@@ -396,7 +437,7 @@ static int rc_write (const data_set_t *ds, const value_list_t *vl,
   values_array[0] = values;
   values_array[1] = NULL;
 
-  if (config_create_files != 0)
+  if (config_create_files)
   {
     struct stat statbuf;
 
index 56a82d0321b8a875fdc1a8b5c93e312550388b77..e5f964e5bdc4fe01084267ee0b821e298fd42650 100644 (file)
@@ -185,7 +185,7 @@ static int srrd_update (char *filename, char *template,
        if (status != 0)
        {
                WARNING ("rrdtool plugin: rrd_update_r failed: %s: %s",
-                               argv[1], rrd_get_error ());
+                               filename, rrd_get_error ());
        }
 
        sfree (new_argv);
index 160687f0ab56aad17116f5a198155f3f03e3652b..f4966694222e7a600c2ac2866eeea478aaf6edc5 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/snmp.c
- * Copyright (C) 2007  Florian octo Forster
+ * 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
@@ -16,7 +16,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
@@ -79,7 +79,7 @@ typedef struct host_definition_s host_definition_t;
  * gaps in tables. */
 struct csnmp_list_instances_s
 {
-  oid subid;
+  oid_t suffix;
   char instance[DATA_MAX_NAME_LEN];
   struct csnmp_list_instances_s *next;
 };
@@ -87,7 +87,7 @@ typedef struct csnmp_list_instances_s csnmp_list_instances_t;
 
 struct csnmp_table_values_s
 {
-  oid subid;
+  oid_t suffix;
   value_t value;
   struct csnmp_table_values_s *next;
 };
@@ -106,6 +106,54 @@ static int csnmp_read_host (user_data_t *ud);
 /*
  * Private functions
  */
+static void csnmp_oid_init (oid_t *dst, oid const *src, size_t n)
+{
+  assert (n <= STATIC_ARRAY_LEN (dst->oid));
+  memcpy (dst->oid, src, sizeof (*src) * n);
+  dst->oid_len = n;
+}
+
+static int csnmp_oid_compare (oid_t const *left, oid_t const *right)
+{
+  return (snmp_oid_compare (left->oid, left->oid_len,
+        right->oid, right->oid_len));
+}
+
+static int csnmp_oid_suffix (oid_t *dst, oid_t const *src,
+    oid_t const *root)
+{
+  /* Make sure "src" is in "root"s subtree. */
+  if (src->oid_len <= root->oid_len)
+    return (EINVAL);
+  if (snmp_oid_ncompare (root->oid, root->oid_len,
+        src->oid, src->oid_len,
+        /* n = */ root->oid_len) != 0)
+    return (EINVAL);
+
+  memset (dst, 0, sizeof (*dst));
+  dst->oid_len = src->oid_len - root->oid_len;
+  memcpy (dst->oid, &src->oid[root->oid_len],
+      dst->oid_len * sizeof (dst->oid[0]));
+  return (0);
+}
+
+static int csnmp_oid_to_string (char *buffer, size_t buffer_size,
+    oid_t const *o)
+{
+  char oid_str[MAX_OID_LEN][16];
+  char *oid_str_ptr[MAX_OID_LEN];
+  size_t i;
+
+  for (i = 0; i < o->oid_len; i++)
+  {
+    ssnprintf (oid_str[i], sizeof (oid_str[i]), "%lu", (unsigned long) o->oid[i]);
+    oid_str_ptr[i] = oid_str[i];
+  }
+
+  return (strjoin (buffer, buffer_size,
+        oid_str_ptr, o->oid_len, /* separator = */ "."));
+}
+
 static void csnmp_host_close_session (host_definition_t *host) /* {{{ */
 {
   if (host->sess_handle == NULL)
@@ -127,7 +175,7 @@ static void csnmp_host_definition_destroy (void *arg) /* {{{ */
   if (hd->name != NULL)
   {
     DEBUG ("snmp plugin: Destroying host definition for host `%s'.",
-       hd->name);
+        hd->name);
   }
 
   csnmp_host_close_session (hd);
@@ -212,10 +260,10 @@ static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t
     dd->instance.oid.oid_len = MAX_OID_LEN;
 
     if (!read_objid (ci->values[0].value.string,
-         dd->instance.oid.oid, &dd->instance.oid.oid_len))
+          dd->instance.oid.oid, &dd->instance.oid.oid_len))
     {
       ERROR ("snmp plugin: read_objid (%s) failed.",
-         ci->values[0].value.string);
+          ci->values[0].value.string);
       return (-1);
     }
   }
@@ -223,7 +271,7 @@ static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t
   {
     /* Instance is a simple string */
     sstrncpy (dd->instance.string, ci->values[0].value.string,
-       sizeof (dd->instance.string));
+        sizeof (dd->instance.string));
   }
 
   return (0);
@@ -241,7 +289,7 @@ static int csnmp_config_add_data_instance_prefix (data_definition_t *dd,
   if (!dd->is_table)
   {
     WARNING ("snmp plugin: data %s: InstancePrefix is ignored when `Table' "
-       "is set to `false'.", dd->name);
+        "is set to `false'.", dd->name);
     return (-1);
   }
 
@@ -282,10 +330,10 @@ static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *
     dd->values[i].oid_len = MAX_OID_LEN;
 
     if (NULL == snmp_parse_oid (ci->values[i].value.string,
-         dd->values[i].oid, &dd->values[i].oid_len))
+          dd->values[i].oid, &dd->values[i].oid_len))
     {
       ERROR ("snmp plugin: snmp_parse_oid (%s) failed.",
-         ci->values[i].value.string);
+          ci->values[i].value.string);
       free (dd->values);
       dd->values = NULL;
       dd->values_len = 0;
@@ -301,7 +349,7 @@ static int csnmp_config_add_data_shift (data_definition_t *dd, oconfig_item_t *c
   if ((ci->values_num != 1)
       || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
   {
-    WARNING ("snmp plugin: The `Scale' config option needs exactly one number argument.");
+    WARNING ("snmp plugin: The `Shift' config option needs exactly one number argument.");
     return (-1);
   }
 
@@ -523,17 +571,17 @@ static int csnmp_config_add_host_collect (host_definition_t *host,
   {
     for (data = data_head; data != NULL; data = data->next)
       if (strcasecmp (ci->values[i].value.string, data->name) == 0)
-       break;
+        break;
 
     if (data == NULL)
     {
       WARNING ("snmp plugin: No such data configured: `%s'",
-         ci->values[i].value.string);
+          ci->values[i].value.string);
       continue;
     }
 
     DEBUG ("snmp plugin: Collect: host = %s, data[%i] = %s;",
-       host->name, host->data_list_len, data->name);
+        host->name, host->data_list_len, data->name);
 
     host->data_list[host->data_list_len] = data;
     host->data_list_len++;
@@ -696,7 +744,7 @@ static void csnmp_host_open_session (host_definition_t *host)
     snmp_error (&sess, NULL, NULL, &errstr);
 
     ERROR ("snmp plugin: host %s: snmp_sess_open failed: %s",
-       host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+        host->name, (errstr == NULL) ? "Unknown problem" : errstr);
     sfree (errstr);
   }
 } /* void csnmp_host_open_session */
@@ -748,12 +796,12 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
 
     memset (oid_buffer, 0, sizeof (oid_buffer));
     snprint_objid (oid_buffer, sizeof (oid_buffer) - 1,
-       vl->name, vl->name_length);
+        vl->name, vl->name_length);
 
 #ifdef ASN_NULL
     if (vl->type == ASN_NULL)
       INFO ("snmp plugin: OID \"%s\" is undefined (type ASN_NULL)",
-         oid_buffer);
+          oid_buffer);
     else
 #endif
       WARNING ("snmp plugin: I don't know the ASN type #%i "
@@ -776,7 +824,7 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
 
       string_length = sizeof (string) - 1;
       if (vl->val_len < string_length)
-       string_length = vl->val_len;
+        string_length = vl->val_len;
 
       /* The strings we get from the Net-SNMP library may not be null
        * terminated. That is why we're using `memcpy' here and not `strcpy'.
@@ -788,8 +836,8 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
       status = parse_value (string, &ret, type);
       if (status != 0)
       {
-       ERROR ("snmp plugin: csnmp_value_list_to_value: Parsing string as %s failed: %s",
-           DS_TYPE_TO_STRING (type), string);
+        ERROR ("snmp plugin: csnmp_value_list_to_value: Parsing string as %s failed: %s",
+            DS_TYPE_TO_STRING (type), string);
       }
     }
 
@@ -797,20 +845,20 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
     {
       switch (type)
       {
-       case DS_TYPE_COUNTER:
-       case DS_TYPE_DERIVE:
-       case DS_TYPE_ABSOLUTE:
-         memset (&ret, 0, sizeof (ret));
-         break;
-
-       case DS_TYPE_GAUGE:
-         ret.gauge = NAN;
-         break;
-
-       default:
-         ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown "
-             "data source type: %i.", type);
-         ret.gauge = NAN;
+        case DS_TYPE_COUNTER:
+        case DS_TYPE_DERIVE:
+        case DS_TYPE_ABSOLUTE:
+          memset (&ret, 0, sizeof (ret));
+          break;
+
+        case DS_TYPE_GAUGE:
+          ret.gauge = NAN;
+          break;
+
+        default:
+          ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown "
+              "data source type: %i.", type);
+          ret.gauge = NAN;
       }
     }
   } /* if (vl->type == ASN_OCTET_STR) */
@@ -841,7 +889,7 @@ static value_t csnmp_value_list_to_value (struct variable_list *vl, int type,
   else
   {
     ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown data source "
-       "type: %i.", type);
+        "type: %i.", type);
     ret.gauge = NAN;
   }
 
@@ -871,10 +919,12 @@ static int csnmp_check_res_left_subtree (const host_definition_t *host,
       vb = vb->next_variable, i++)
   {
     num_checked++;
-    if (snmp_oid_ncompare (data->values[i].oid,
-         data->values[i].oid_len,
-         vb->name, vb->name_length,
-         data->values[i].oid_len) != 0)
+
+    if ((vb->type == SNMP_ENDOFMIBVIEW)
+        || (snmp_oid_ncompare (data->values[i].oid,
+            data->values[i].oid_len,
+            vb->name, vb->name_length,
+            data->values[i].oid_len) != 0))
       num_left_subtree++;
   }
 
@@ -882,7 +932,7 @@ static int csnmp_check_res_left_subtree (const host_definition_t *host,
   if (i < data->values_len)
   {
     ERROR ("snmp plugin: host %s: Expected %i variables, but got only %i",
-       host->name, data->values_len, i);
+        host->name, data->values_len, i);
     return (-1);
   }
 
@@ -891,15 +941,15 @@ static int csnmp_check_res_left_subtree (const host_definition_t *host,
     if (vb == NULL)
     {
       ERROR ("snmp plugin: host %s: Expected one more variable for "
-         "the instance..", host->name);
+          "the instance..", host->name);
       return (-1);
     }
 
     num_checked++;
     if (snmp_oid_ncompare (data->instance.oid.oid,
-         data->instance.oid.oid_len,
-         vb->name, vb->name_length,
-         data->instance.oid.oid_len) != 0)
+          data->instance.oid.oid_len,
+          vb->name, vb->name_length,
+          data->instance.oid.oid_len) != 0)
       num_left_subtree++;
   }
 
@@ -926,7 +976,7 @@ static int csnmp_strvbcopy_hexstring (char *dst, /* {{{ */
     int status;
 
     status = snprintf (buffer_ptr, buffer_free,
-       (i == 0) ? "%02x" : ":%02x", (unsigned int) vb->val.bitstring[i]);
+        (i == 0) ? "%02x" : ":%02x", (unsigned int) vb->val.bitstring[i]);
 
     if (status >= buffer_free)
     {
@@ -984,6 +1034,8 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
 {
   csnmp_list_instances_t *il;
   struct variable_list *vb;
+  oid_t vb_name;
+  int status;
 
   /* Set vb on the last variable */
   for (vb = res->variables;
@@ -993,15 +1045,24 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
   if (vb == NULL)
     return (-1);
 
-  il = (csnmp_list_instances_t *) malloc (sizeof (csnmp_list_instances_t));
+  csnmp_oid_init (&vb_name, vb->name, vb->name_length);
+
+  il = malloc (sizeof (*il));
   if (il == NULL)
   {
     ERROR ("snmp plugin: malloc failed.");
     return (-1);
   }
-  il->subid = vb->name[vb->name_length - 1];
+  memset (il, 0, sizeof (*il));
   il->next = NULL;
 
+  status = csnmp_oid_suffix (&il->suffix, &vb_name, &dd->instance.oid);
+  if (status != 0)
+  {
+    sfree (il);
+    return (status);
+  }
+
   /* Get instance name */
   if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
   {
@@ -1012,9 +1073,9 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
     for (ptr = il->instance; *ptr != '\0'; ptr++)
     {
       if ((*ptr > 0) && (*ptr < 32))
-       *ptr = ' ';
+        *ptr = ' ';
       else if (*ptr == '/')
-       *ptr = '_';
+        *ptr = '_';
     }
     DEBUG ("snmp plugin: il->instance = `%s';", il->instance);
   }
@@ -1023,7 +1084,7 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
     value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER,
         /* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
     ssnprintf (il->instance, sizeof (il->instance),
-       "%llu", val.counter);
+        "%llu", val.counter);
   }
 
   /* TODO: Debugging output */
@@ -1048,8 +1109,8 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
   csnmp_table_values_t **value_table_ptr;
 
   int i;
-  oid subid;
-  int have_more;
+  _Bool have_more;
+  oid_t current_suffix;
 
   ds = plugin_get_ds (data->type);
   if (!ds)
@@ -1061,15 +1122,14 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
 
   instance_list_ptr = instance_list;
 
-  value_table_ptr = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
-      * data->values_len);
+  value_table_ptr = malloc (sizeof (*value_table_ptr) * data->values_len);
   if (value_table_ptr == NULL)
     return (-1);
   for (i = 0; i < data->values_len; i++)
     value_table_ptr[i] = value_table[i];
 
   vl.values_len = ds->ds_num;
-  vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+  vl.values = malloc (sizeof (*vl.values) * vl.values_len);
   if (vl.values == NULL)
   {
     ERROR ("snmp plugin: malloc failed.");
@@ -1082,50 +1142,70 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
 
   vl.interval = host->interval;
 
-  subid = 0;
   have_more = 1;
-
-  while (have_more != 0)
+  memset (&current_suffix, 0, sizeof (current_suffix));
+  while (have_more)
   {
+    _Bool suffix_skipped = 0;
+
+    /* Determine next suffix to handle. */
     if (instance_list != NULL)
     {
-      while ((instance_list_ptr != NULL)
-         && (instance_list_ptr->subid < subid))
-       instance_list_ptr = instance_list_ptr->next;
-
       if (instance_list_ptr == NULL)
       {
-       have_more = 0;
-       continue;
+        have_more = 0;
+        continue;
       }
-      else if (instance_list_ptr->subid > subid)
+
+      memcpy (&current_suffix, &instance_list_ptr->suffix, sizeof (current_suffix));
+    }
+    else /* no instance configured */
+    {
+      csnmp_table_values_t *ptr = value_table_ptr[0];
+      if (ptr == NULL)
       {
-       subid = instance_list_ptr->subid;
-       continue;
+        have_more = 0;
+        continue;
       }
-    } /* if (instance_list != NULL) */
 
+      memcpy (&current_suffix, &ptr->suffix, sizeof (current_suffix));
+    }
+
+    /* Update all the value_table_ptr to point at the entry with the same
+     * trailing partial OID */
     for (i = 0; i < data->values_len; i++)
     {
       while ((value_table_ptr[i] != NULL)
-         && (value_table_ptr[i]->subid < subid))
-       value_table_ptr[i] = value_table_ptr[i]->next;
+          && (csnmp_oid_compare (&value_table_ptr[i]->suffix, &current_suffix) < 0))
+        value_table_ptr[i] = value_table_ptr[i]->next;
 
       if (value_table_ptr[i] == NULL)
       {
-       have_more = 0;
-       break;
+        have_more = 0;
+        break;
       }
-      else if (value_table_ptr[i]->subid > subid)
+      else if (csnmp_oid_compare (&value_table_ptr[i]->suffix, &current_suffix) > 0)
       {
-       subid = value_table_ptr[i]->subid;
-       break;
+        /* This suffix is missing in the subtree. Indicate this with the
+         * "suffix_skipped" flag and try the next instance / suffix. */
+        suffix_skipped = 1;
+        break;
       }
     } /* for (i = 0; i < columns; i++) */
-    /* The subid has been increased - start scanning from the beginning
-     * again.. */
-    if (i < data->values_len)
+
+    if (!have_more)
+      break;
+
+    /* Matching the values failed. Start from the beginning again. */
+    if (suffix_skipped)
+    {
+      if (instance_list != NULL)
+        instance_list_ptr = instance_list_ptr->next;
+      else
+        value_table_ptr[0] = value_table_ptr[0]->next;
+
       continue;
+    }
 
     /* if we reach this line, all value_table_ptr[i] are non-NULL and are set
      * to the same subid. instance_list_ptr is either NULL or points to the
@@ -1134,10 +1214,12 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
     for (i = 1; i < data->values_len; i++)
     {
       assert (value_table_ptr[i] != NULL);
-      assert (value_table_ptr[i-1]->subid == value_table_ptr[i]->subid);
+      assert (csnmp_oid_compare (&value_table_ptr[i-1]->suffix,
+            &value_table_ptr[i]->suffix) == 0);
     }
     assert ((instance_list_ptr == NULL)
-       || (instance_list_ptr->subid == value_table_ptr[0]->subid));
+        || (csnmp_oid_compare (&instance_list_ptr->suffix,
+            &value_table_ptr[0]->suffix) == 0));
 #endif
 
     sstrncpy (vl.type, data->type, sizeof (vl.type));
@@ -1146,15 +1228,15 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
       char temp[DATA_MAX_NAME_LEN];
 
       if (instance_list_ptr == NULL)
-       ssnprintf (temp, sizeof (temp), "%"PRIu32, (uint32_t) subid);
+        csnmp_oid_to_string (temp, sizeof (temp), &current_suffix);
       else
-       sstrncpy (temp, instance_list_ptr->instance, sizeof (temp));
+        sstrncpy (temp, instance_list_ptr->instance, sizeof (temp));
 
       if (data->instance_prefix == NULL)
-       sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance));
+        sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance));
       else
-       ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
-           data->instance_prefix, temp);
+        ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
+            data->instance_prefix, temp);
     }
 
     for (i = 0; i < data->values_len; i++)
@@ -1163,8 +1245,11 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
     /* If we get here `vl.type_instance' and all `vl.values' have been set */
     plugin_dispatch_values (&vl);
 
-    subid++;
-  } /* while (have_more != 0) */
+    if (instance_list != NULL)
+      instance_list_ptr = instance_list_ptr->next;
+    else
+      value_table_ptr[0] = value_table_ptr[0]->next;
+  } /* while (have_more) */
 
   sfree (vl.values);
   sfree (value_table_ptr);
@@ -1185,13 +1270,13 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
   int status;
   int i;
 
-  /* `value_table' and `value_table_ptr' implement a linked list for each
-   * value. `instance_list' and `instance_list_ptr' implement a linked list of
+  /* `value_list_head' and `value_list_tail' implement a linked list for each
+   * value. `instance_list_head' and `instance_list_tail' implement a linked list of
    * instance names. This is used to jump gaps in the table. */
-  csnmp_list_instances_t *instance_list;
-  csnmp_list_instances_t *instance_list_ptr;
-  csnmp_table_values_t **value_table;
-  csnmp_table_values_t **value_table_ptr;
+  csnmp_list_instances_t *instance_list_head;
+  csnmp_list_instances_t *instance_list_tail;
+  csnmp_table_values_t **value_list_head;
+  csnmp_table_values_t **value_list_tail;
 
   DEBUG ("snmp plugin: csnmp_read_table (host = %s, data = %s)",
       host->name, data->name);
@@ -1212,7 +1297,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
   if (ds->ds_num != data->values_len)
   {
     ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
-       data->type, ds->ds_num, data->values_len);
+        data->type, ds->ds_num, data->values_len);
     return (-1);
   }
 
@@ -1230,20 +1315,22 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
   else
     oid_list_len--;
 
-  /* Allocate the `value_table' */
-  value_table = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
-      * 2 * data->values_len);
-  if (value_table == NULL)
+  /* We're going to construct n linked lists, one for each "value".
+   * value_list_head will contain pointers to the heads of these linked lists,
+   * value_list_tail will contain pointers to the tail of the lists. */
+  value_list_head = calloc (data->values_len, sizeof (*value_list_head));
+  value_list_tail = calloc (data->values_len, sizeof (*value_list_tail));
+  if ((value_list_head == NULL) || (value_list_tail == NULL))
   {
-    ERROR ("snmp plugin: csnmp_read_table: malloc failed.");
+    ERROR ("snmp plugin: csnmp_read_table: calloc failed.");
     sfree (oid_list);
+    sfree (value_list_head);
+    sfree (value_list_tail);
     return (-1);
   }
-  memset (value_table, '\0', sizeof (csnmp_table_values_t *) * 2 * data->values_len);
-  value_table_ptr = value_table + data->values_len;
-  
-  instance_list = NULL;
-  instance_list_ptr = NULL;
+
+  instance_list_head = NULL;
+  instance_list_tail = NULL;
 
   status = 0;
   while (status == 0)
@@ -1269,11 +1356,11 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
       snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
 
       c_complain (LOG_ERR, &host->complaint,
-         "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
-         host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+          "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
+          host->name, (errstr == NULL) ? "Unknown problem" : errstr);
 
       if (res != NULL)
-       snmp_free_pdu (res);
+        snmp_free_pdu (res);
       res = NULL;
 
       sfree (errstr);
@@ -1285,8 +1372,8 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
     status = 0;
     assert (res != NULL);
     c_release (LOG_INFO, &host->complaint,
-       "snmp plugin: host %s: snmp_sess_synch_response successful.",
-       host->name);
+        "snmp plugin: host %s: snmp_sess_synch_response successful.",
+        host->name);
 
     vb = res->variables;
     if (vb == NULL)
@@ -1303,76 +1390,90 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
       break;
     }
 
-    /* if an instance-OID is configured.. */
+    /* Copy the OID of the value used as instance to oid_list, if an instance
+     * is configured. */
     if (data->instance.oid.oid_len > 0)
     {
       /* Allocate a new `csnmp_list_instances_t', insert the instance name and
        * add it to the list */
-      if (csnmp_instance_list_add (&instance_list, &instance_list_ptr,
+      if (csnmp_instance_list_add (&instance_list_head, &instance_list_tail,
            res, host, data) != 0)
       {
-       ERROR ("snmp plugin: csnmp_instance_list_add failed.");
-       status = -1;
-       break;
+        ERROR ("snmp plugin: csnmp_instance_list_add failed.");
+        status = -1;
+        break;
       }
 
-      /* Set vb on the last variable */
+      /* The instance OID is added to the list of OIDs to GET from the
+       * snmp agent last, so set vb on the last variable returned and copy
+       * that OID. */
       for (vb = res->variables;
-         (vb != NULL) && (vb->next_variable != NULL);
-         vb = vb->next_variable)
-       /* do nothing */;
+          (vb != NULL) && (vb->next_variable != NULL);
+          vb = vb->next_variable)
+        /* do nothing */;
       assert (vb != NULL);
 
-      /* Copy OID to oid_list[data->values_len] */
+      /* Copy the OID of the instance value to oid_list[data->values_len].
+       * "oid_list" is used for the next GETNEXT request. */
       memcpy (oid_list[data->values_len].oid, vb->name,
-         sizeof (oid) * vb->name_length);
+          sizeof (oid) * vb->name_length);
       oid_list[data->values_len].oid_len = vb->name_length;
     }
 
+    /* Iterate over all the (non-instance) values returned by the agent. The
+     * (i < value_len) check will make sure we're not handling the instance OID
+     * twice. */
     for (vb = res->variables, i = 0;
-       (vb != NULL) && (i < data->values_len);
-       vb = vb->next_variable, i++)
+        (vb != NULL) && (i < data->values_len);
+        vb = vb->next_variable, i++)
     {
       csnmp_table_values_t *vt;
+      oid_t vb_name;
+      oid_t suffix;
 
-      /* Check if we left the subtree */
-      if (snmp_oid_ncompare (data->values[i].oid,
-           data->values[i].oid_len,
-           vb->name, vb->name_length,
-           data->values[i].oid_len) != 0)
+      csnmp_oid_init (&vb_name, vb->name, vb->name_length);
+
+      /* Calculate the current suffix. This is later used to check that the
+       * suffix is increasing. This also checks if we left the subtree */
+      status = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
+      if (status != 0)
       {
-       DEBUG ("snmp plugin: host = %s; data = %s; Value %i left its subtree.",
-           host->name, data->name, i);
-       continue;
+        DEBUG ("snmp plugin: host = %s; data = %s; Value %i failed. "
+            "It probably left its subtree.",
+            host->name, data->name, i);
+        continue;
       }
 
-      if ((value_table_ptr[i] != NULL)
-         && (vb->name[vb->name_length - 1] <= value_table_ptr[i]->subid))
+      /* Make sure the OIDs returned by the agent are increasing. Otherwise our
+       * table matching algorithm will get confused. */
+      if ((value_list_tail[i] != NULL)
+          && (csnmp_oid_compare (&suffix, &value_list_tail[i]->suffix) <= 0))
       {
-       DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
-           "SUBID is not increasing.",
-           host->name, data->name, i);
-       continue;
+        DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
+            "Suffix is not increasing.",
+            host->name, data->name, i);
+        continue;
       }
 
-      vt = (csnmp_table_values_t *) malloc (sizeof (csnmp_table_values_t));
+      vt = malloc (sizeof (*vt));
       if (vt == NULL)
       {
-       ERROR ("snmp plugin: malloc failed.");
-       status = -1;
-       break;
+        ERROR ("snmp plugin: malloc failed.");
+        status = -1;
+        break;
       }
+      memset (vt, 0, sizeof (*vt));
 
-      vt->subid = vb->name[vb->name_length - 1];
       vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type,
           data->scale, data->shift, host->name, data->name);
+      memcpy (&vt->suffix, &suffix, sizeof (vt->suffix));
       vt->next = NULL;
 
-      if (value_table_ptr[i] == NULL)
-       value_table[i] = vt;
+      if (value_list_tail[i] == NULL)
+        value_list_head[i] = vt;
       else
-       value_table_ptr[i]->next = vt;
-      value_table_ptr[i] = vt;
+        value_list_tail[i]->next = vt;
+      value_list_tail[i] = vt;
 
       /* Copy OID to oid_list[i + 1] */
       memcpy (oid_list[i].oid, vb->name, sizeof (oid) * vb->name_length);
@@ -1389,28 +1490,28 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
   res = NULL;
 
   if (status == 0)
-    csnmp_dispatch_table (host, data, instance_list, value_table);
+    csnmp_dispatch_table (host, data, instance_list_head, value_list_head);
 
   /* Free all allocated variables here */
-  while (instance_list != NULL)
+  while (instance_list_head != NULL)
   {
-    instance_list_ptr = instance_list->next;
-    sfree (instance_list);
-    instance_list = instance_list_ptr;
+    csnmp_list_instances_t *next = instance_list_head->next;
+    sfree (instance_list_head);
+    instance_list_head = next;
   }
 
   for (i = 0; i < data->values_len; i++)
   {
-    csnmp_table_values_t *tmp;
-    while (value_table[i] != NULL)
+    while (value_list_head[i] != NULL)
     {
-      tmp = value_table[i]->next;
-      sfree (value_table[i]);
-      value_table[i] = tmp;
+      csnmp_table_values_t *next = value_list_head[i]->next;
+      sfree (value_list_head[i]);
+      value_list_head[i] = next;
     }
   }
 
-  sfree (value_table);
+  sfree (value_list_head);
+  sfree (value_list_tail);
   sfree (oid_list);
 
   return (0);
@@ -1447,7 +1548,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
   if (ds->ds_num != data->values_len)
   {
     ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
-       data->type, ds->ds_num, data->values_len);
+        data->type, ds->ds_num, data->values_len);
     return (-1);
   }
 
@@ -1490,7 +1591,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
 
     snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
     ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
-       host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+        host->name, (errstr == NULL) ? "Unknown problem" : errstr);
 
     if (res != NULL)
       snmp_free_pdu (res);
@@ -1508,13 +1609,13 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
 #if COLLECT_DEBUG
     char buffer[1024];
     snprint_variable (buffer, sizeof (buffer),
-       vb->name, vb->name_length, vb);
+        vb->name, vb->name_length, vb);
     DEBUG ("snmp plugin: Got this variable: %s", buffer);
 #endif /* COLLECT_DEBUG */
 
     for (i = 0; i < data->values_len; i++)
       if (snmp_oid_compare (data->values[i].oid, data->values[i].oid_len,
-           vb->name, vb->name_length) == 0)
+            vb->name, vb->name_length) == 0)
         vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type,
             data->scale, data->shift, host->name, data->name);
   } /* for (res->variables) */
index 397969eff0ce0ea7a4eb48762bdef9d0e019bbd6..46d3534fcae818cd6fc286cd448d824ad22ccad8 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/swap.c
- * Copyright (C) 2005-2010  Florian octo Forster
+ * Copyright (C) 2005-2012  Florian octo Forster
  * Copyright (C) 2009       Stefan Völkel
  * Copyright (C) 2009       Manuel Sanmartin
  * Copyright (C) 2010       Aurélien Reynaud
 #define MAX(x,y) ((x) > (y) ? (x) : (y))
 
 #if KERNEL_LINUX
-# define SWAP_HAVE_CONFIG 1
-/* No global variables */
+# define SWAP_HAVE_REPORT_BY_DEVICE 1
+static derive_t pagesize;
+static _Bool report_bytes = 0;
+static _Bool report_by_device = 0;
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
-# define SWAP_HAVE_CONFIG 1
+# define SWAP_HAVE_REPORT_BY_DEVICE 1
 static derive_t pagesize;
+static _Bool report_by_device = 0;
 /* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS */
 
 #elif defined(VM_SWAPUSAGE)
@@ -101,23 +104,37 @@ static perfstat_memory_total_t pmemory;
 # error "No applicable input method."
 #endif /* HAVE_LIBSTATGRAB */
 
-#if SWAP_HAVE_CONFIG
 static const char *config_keys[] =
 {
+       "ReportBytes",
        "ReportByDevice"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
-static _Bool report_by_device = 0;
-
 static int swap_config (const char *key, const char *value) /* {{{ */
 {
-       if (strcasecmp ("ReportByDevice", key) == 0)
+       if (strcasecmp ("ReportBytes", key) == 0)
+       {
+#if KERNEL_LINUX
+               report_bytes = IS_TRUE (value) ? 1 : 0;
+#else
+               WARNING ("swap plugin: The \"ReportBytes\" option is only "
+                               "valid under Linux. "
+                               "The option is going to be ignored.");
+#endif
+       }
+       else if (strcasecmp ("ReportByDevice", key) == 0)
        {
+#if SWAP_HAVE_REPORT_BY_DEVICE
                if (IS_TRUE (value))
                        report_by_device = 1;
                else
                        report_by_device = 0;
+#else
+               WARNING ("swap plugin: The \"ReportByDevice\" option is not "
+                               "supported on this platform. "
+                               "The option is going to be ignored.");
+#endif /* SWAP_HAVE_REPORT_BY_DEVICE */
        }
        else
        {
@@ -126,12 +143,11 @@ static int swap_config (const char *key, const char *value) /* {{{ */
 
        return (0);
 } /* }}} int swap_config */
-#endif /* SWAP_HAVE_CONFIG */
 
 static int swap_init (void) /* {{{ */
 {
 #if KERNEL_LINUX
-       /* No init stuff */
+       pagesize = (derive_t) sysconf (_SC_PAGESIZE);
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
@@ -205,7 +221,7 @@ static void swap_submit_gauge (const char *plugin_instance, /* {{{ */
        swap_submit (plugin_instance, "swap", type_instance, v);
 } /* }}} void swap_submit_gauge */
 
-#if KERNEL_LINUX
+#if KERNEL_LINUX || HAVE_PERFSTAT
 static void swap_submit_derive (const char *plugin_instance, /* {{{ */
                const char *type_instance, derive_t value)
 {
@@ -214,7 +230,9 @@ static void swap_submit_derive (const char *plugin_instance, /* {{{ */
        v.derive = value;
        swap_submit (plugin_instance, "swap_io", type_instance, v);
 } /* }}} void swap_submit_derive */
+#endif
 
+#if KERNEL_LINUX
 static int swap_read_separate (void) /* {{{ */
 {
        FILE *fh;
@@ -406,6 +424,12 @@ static int swap_read_io (void) /* {{{ */
        if (have_data != 0x03)
                return (ENOENT);
 
+       if (report_bytes)
+       {
+               swap_in = swap_in * pagesize;
+               swap_out = swap_out * pagesize;
+       }
+
        swap_submit_derive (NULL, "in",  swap_in);
        swap_submit_derive (NULL, "out", swap_out);
 
@@ -764,8 +788,12 @@ static int swap_read (void) /* {{{ */
                         sstrerror (errno, errbuf, sizeof (errbuf)));
                 return (-1);
         }
+
        swap_submit_gauge (NULL, "used", (gauge_t) (pmemory.pgsp_total - pmemory.pgsp_free) * pagesize);
        swap_submit_gauge (NULL, "free", (gauge_t) pmemory.pgsp_free * pagesize );
+       swap_submit_gauge (NULL, "reserved", (gauge_t) pmemory.pgsp_rsvd * pagesize);
+       swap_submit_derive (NULL, "in",  (derive_t) pmemory.pgspins * pagesize);
+       swap_submit_derive (NULL, "out", (derive_t) pmemory.pgspouts * pagesize);
 
        return (0);
 } /* }}} int swap_read */
@@ -773,9 +801,8 @@ static int swap_read (void) /* {{{ */
 
 void module_register (void)
 {
-#if SWAP_HAVE_CONFIG
-       plugin_register_config ("swap", swap_config, config_keys, config_keys_num);
-#endif
+       plugin_register_config ("swap", swap_config,
+                       config_keys, config_keys_num);
        plugin_register_init ("swap", swap_init);
        plugin_register_read ("swap", swap_read);
 } /* void module_register */
index 3c8fc7285e2621c57fa5f3779d08df70e8ed7179..765b892e265498e0299fb4f7c4f2265eef93290c 100644 (file)
 #endif
 
 #if KERNEL_LINUX
+# include <asm/types.h>
+/* sys/socket.h is necessary to compile when using netlink on older systems. */
+# include <sys/socket.h>
+# include <linux/netlink.h>
+# include <linux/inet_diag.h>
+# include <sys/socket.h>
+# include <arpa/inet.h>
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_SYSCTLBYNAME
 #endif /* KERNEL_AIX */
 
 #if KERNEL_LINUX
+struct nlreq {
+  struct nlmsghdr nlh;
+  struct inet_diag_req r;
+};
+
 static const char *tcp_state[] =
 {
   "", /* 0 */
@@ -263,6 +275,17 @@ static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 static int port_collect_listening = 0;
 static port_entry_t *port_list_head = NULL;
 
+#if KERNEL_LINUX
+static uint32_t sequence_number = 0;
+
+enum
+{
+  SRC_DUNNO,
+  SRC_NETLINK,
+  SRC_PROC
+} linux_source = SRC_DUNNO;
+#endif
+
 static void conn_submit_port_entry (port_entry_t *pe)
 {
   value_t values[1];
@@ -419,6 +442,140 @@ static int conn_handle_ports (uint16_t port_local, uint16_t port_remote, uint8_t
 } /* int conn_handle_ports */
 
 #if KERNEL_LINUX
+/* Returns zero on success, less than zero on socket error and greater than
+ * zero on other errors. */
+static int conn_read_netlink (void)
+{
+  int fd;
+  struct sockaddr_nl nladdr;
+  struct nlreq req;
+  struct msghdr msg;
+  struct iovec iov;
+  struct inet_diag_msg *r;
+  char buf[8192];
+
+  /* If this fails, it's likely a permission problem. We'll fall back to
+   * reading this information from files below. */
+  fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG);
+  if (fd < 0)
+  {
+    ERROR ("tcpconns plugin: conn_read_netlink: socket(AF_NETLINK, SOCK_RAW, "
+       "NETLINK_INET_DIAG) failed: %s",
+       sstrerror (errno, buf, sizeof (buf)));
+    return (-1);
+  }
+
+  memset(&nladdr, 0, sizeof(nladdr));
+  nladdr.nl_family = AF_NETLINK;
+
+  memset(&req, 0, sizeof(req));
+  req.nlh.nlmsg_len = sizeof(req);
+  req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
+  /* NLM_F_ROOT: return the complete table instead of a single entry.
+   * NLM_F_MATCH: return all entries matching criteria (not implemented)
+   * NLM_F_REQUEST: must be set on all request messages */
+  req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+  req.nlh.nlmsg_pid = 0;
+  /* The sequence_number is used to track our messages. Since netlink is not
+   * reliable, we don't want to end up with a corrupt or incomplete old
+   * message in case the system is/was out of memory. */
+  req.nlh.nlmsg_seq = ++sequence_number;
+  req.r.idiag_family = AF_INET;
+  req.r.idiag_states = 0xfff;
+  req.r.idiag_ext = 0;
+
+  memset(&iov, 0, sizeof(iov));
+  iov.iov_base = &req;
+  iov.iov_len = sizeof(req);
+
+  memset(&msg, 0, sizeof(msg));
+  msg.msg_name = (void*)&nladdr;
+  msg.msg_namelen = sizeof(nladdr);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  if (sendmsg (fd, &msg, 0) < 0)
+  {
+    ERROR ("tcpconns plugin: conn_read_netlink: sendmsg(2) failed: %s",
+       sstrerror (errno, buf, sizeof (buf)));
+    close (fd);
+    return (-1);
+  }
+
+  iov.iov_base = buf;
+  iov.iov_len = sizeof(buf);
+
+  while (1)
+  {
+    int status;
+    struct nlmsghdr *h;
+
+    memset(&msg, 0, sizeof(msg));
+    msg.msg_name = (void*)&nladdr;
+    msg.msg_namelen = sizeof(nladdr);
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+
+    status = recvmsg(fd, (void *) &msg, /* flags = */ 0);
+    if (status < 0)
+    {
+      if ((errno == EINTR) || (errno == EAGAIN))
+        continue;
+
+      ERROR ("tcpconns plugin: conn_read_netlink: recvmsg(2) failed: %s",
+         sstrerror (errno, buf, sizeof (buf)));
+      close (fd);
+      return (-1);
+    }
+    else if (status == 0)
+    {
+      close (fd);
+      DEBUG ("tcpconns plugin: conn_read_netlink: Unexpected zero-sized "
+         "reply from netlink socket.");
+      return (0);
+    }
+
+    h = (struct nlmsghdr*)buf;
+    while (NLMSG_OK(h, status))
+    {
+      if (h->nlmsg_seq != sequence_number)
+      {
+       h = NLMSG_NEXT(h, status);
+       continue;
+      }
+
+      if (h->nlmsg_type == NLMSG_DONE)
+      {
+       close (fd);
+       return (0);
+      }
+      else if (h->nlmsg_type == NLMSG_ERROR)
+      {
+       struct nlmsgerr *msg_error;
+
+       msg_error = NLMSG_DATA(h);
+       WARNING ("tcpconns plugin: conn_read_netlink: Received error %i.",
+           msg_error->error);
+
+       close (fd);
+       return (1);
+      }
+
+      r = NLMSG_DATA(h);
+
+      /* This code does not (need to) distinguish between IPv4 and IPv6. */
+      conn_handle_ports (ntohs(r->id.idiag_sport),
+         ntohs(r->id.idiag_dport),
+         r->idiag_state);
+
+      h = NLMSG_NEXT(h, status);
+    } /* while (NLMSG_OK) */
+  } /* while (1) */
+
+  /* Not reached because the while() loop above handles the exit condition. */
+  return (0);
+} /* int conn_read_netlink */
+
 static int conn_handle_line (char *buffer)
 {
   char *fields[32];
@@ -553,26 +710,55 @@ static int conn_init (void)
 
 static int conn_read (void)
 {
-  int errors_num = 0;
+  int status;
 
   conn_reset_port_entry ();
 
-  if (conn_read_file ("/proc/net/tcp") != 0)
-    errors_num++;
-  if (conn_read_file ("/proc/net/tcp6") != 0)
-    errors_num++;
-
-  if (errors_num < 2)
+  if (linux_source == SRC_NETLINK)
   {
-    conn_submit_all ();
+    status = conn_read_netlink ();
   }
-  else
+  else if (linux_source == SRC_PROC)
   {
-    ERROR ("tcpconns plugin: Neither /proc/net/tcp nor /proc/net/tcp6 "
-       "coult be read.");
-    return (-1);
+    int errors_num = 0;
+
+    if (conn_read_file ("/proc/net/tcp") != 0)
+      errors_num++;
+    if (conn_read_file ("/proc/net/tcp6") != 0)
+      errors_num++;
+
+    if (errors_num < 2)
+      status = 0;
+    else
+      status = ENOENT;
+  }
+  else /* if (linux_source == SRC_DUNNO) */
+  {
+    /* Try to use netlink for getting this data, it is _much_ faster on systems
+     * with a large amount of connections. */
+    status = conn_read_netlink ();
+    if (status == 0)
+    {
+      INFO ("tcpconns plugin: Reading from netlink succeeded. "
+         "Will use the netlink method from now on.");
+      linux_source = SRC_NETLINK;
+    }
+    else
+    {
+      INFO ("tcpconns plugin: Reading from netlink failed. "
+         "Will read from /proc from now on.");
+      linux_source = SRC_PROC;
+
+      /* return success here to avoid the "plugin failed" message. */
+      return (0);
+    }
   }
 
+  if (status == 0)
+    conn_submit_all ();
+  else
+    return (status);
+
   return (0);
 } /* int conn_read */
 /* #endif KERNEL_LINUX */
index d729477bbc54db999322dedfe581834dc9725c21..0dc7d659400193a8bf29fc0ab3f78a9556826a90 100644 (file)
@@ -205,6 +205,7 @@ static void *us_handle_client (void *arg)
                close (fdin);
                close (fdout);
                pthread_exit ((void *) 1);
+               return ((void *) 1);
        }
 
        fhout = fdopen (fdout, "w");
@@ -216,6 +217,7 @@ static void *us_handle_client (void *arg)
                fclose (fhin); /* this closes fdin as well */
                close (fdout);
                pthread_exit ((void *) 1);
+               return ((void *) 1);
        }
 
        /* change output buffer to line buffered mode */
@@ -227,6 +229,7 @@ static void *us_handle_client (void *arg)
                fclose (fhin);
                fclose (fhout);
                pthread_exit ((void *) 1);
+               return ((void *) 0);
        }
 
        while (42)
@@ -240,6 +243,9 @@ static void *us_handle_client (void *arg)
                errno = 0;
                if (fgets (buffer, sizeof (buffer), fhin) == NULL)
                {
+                       if ((errno == EINTR) || (errno == EAGAIN))
+                               continue;
+
                        if (errno != 0)
                        {
                                char errbuf[1024];
@@ -268,6 +274,7 @@ static void *us_handle_client (void *arg)
                        fclose (fhin);
                        fclose (fhout);
                        pthread_exit ((void *) 1);
+                       return ((void *) 1);
                }
 
                if (strcasecmp (fields[0], "getval") == 0)
@@ -318,6 +325,9 @@ static void *us_server_thread (void __attribute__((unused)) *arg)
        pthread_t th;
        pthread_attr_t th_attr;
 
+       pthread_attr_init (&th_attr);
+       pthread_attr_setdetachstate (&th_attr, PTHREAD_CREATE_DETACHED);
+
        if (us_open_socket () != 0)
                pthread_exit ((void *) 1);
 
@@ -336,6 +346,7 @@ static void *us_server_thread (void __attribute__((unused)) *arg)
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                        close (sock_fd);
                        sock_fd = -1;
+                       pthread_attr_destroy (&th_attr);
                        pthread_exit ((void *) 1);
                }
 
@@ -352,9 +363,6 @@ static void *us_server_thread (void __attribute__((unused)) *arg)
 
                DEBUG ("Spawning child to handle connection on fd #%i", *remote_fd);
 
-               pthread_attr_init (&th_attr);
-               pthread_attr_setdetachstate (&th_attr, PTHREAD_CREATE_DETACHED);
-
                status = pthread_create (&th, &th_attr, us_handle_client, (void *) remote_fd);
                if (status != 0)
                {
@@ -369,6 +377,7 @@ static void *us_server_thread (void __attribute__((unused)) *arg)
 
        close (sock_fd);
        sock_fd = -1;
+       pthread_attr_destroy (&th_attr);
 
        status = unlink ((sock_file != NULL) ? sock_file : US_DEFAULT_PATH);
        if (status != 0)
index d2ba9633db290aeb17ac0a064874b3c652742b3a..064c3ceed4752a359c7ec2e5b9d84afa27068543 100644 (file)
 /* Using sysctl interface to retrieve the boot time on *BSD / Darwin / OS X systems */
 /* #endif HAVE_SYS_SYSCTL_H */
 
+#elif HAVE_PERFSTAT
+# include <sys/protosw.h>
+# include <libperfstat.h>
+/* Using perfstat_cpu_total to retrive the boot time in AIX */
+/* #endif HAVE_PERFSTAT */
+
 #else
 # error "No applicable input method."
 #endif
@@ -203,7 +209,29 @@ static int uptime_init (void) /* {{{ */
                                "but `boottime' is zero!");
                return (-1);
        }
-#endif /* HAVE_SYS_SYSCTL_H */
+/* #endif HAVE_SYS_SYSCTL_H */
+
+#elif HAVE_PERFSTAT
+       int status;
+       perfstat_cpu_total_t cputotal;
+       int hertz;
+
+       status = perfstat_cpu_total(NULL, &cputotal,
+               sizeof(perfstat_cpu_total_t), 1);
+       if (status < 0)
+       {
+               char errbuf[1024];
+               ERROR ("uptime plugin: perfstat_cpu_total: %s",
+                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       hertz = sysconf(_SC_CLK_TCK);
+       if (hertz <= 0)
+               hertz = HZ;
+
+       boottime = time(NULL) - cputotal.lbolt / hertz;
+#endif /* HAVE_PERFSTAT */
 
        return (0);
 } /* }}} int uptime_init */
index 0436d8fe077eceeaffdeff607bc8f9e44ebe5aca..f71b1fd6913bbc9676bb0e494d26bba1f829e7c2 100644 (file)
@@ -487,6 +487,8 @@ c_avl_tree_t *c_avl_create (int (*compare) (const void *, const void *))
 
 void c_avl_destroy (c_avl_tree_t *t)
 {
+       if (t == NULL)
+               return;
        free_node (t->root);
        free (t);
 }
@@ -510,6 +512,7 @@ int c_avl_insert (c_avl_tree_t *t, void *key, void *value)
        {
                new->parent = NULL;
                t->root = new;
+               t->size = 1;
                return (0);
        }
 
index dd5bcb59ffc9833b2a92341a085e32d526e9e812..fa6e6603ec3e10eedcdc6ea7d56ab64a0b04db6e 100644 (file)
@@ -572,6 +572,7 @@ int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
   char **names = NULL;
   cdtime_t *times = NULL;
   size_t number = 0;
+  size_t size_arrays = 0;
 
   int status = 0;
 
@@ -580,42 +581,47 @@ int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
 
   pthread_mutex_lock (&cache_lock);
 
+  size_arrays = (size_t) c_avl_size (cache_tree);
+  if (size_arrays < 1)
+  {
+    /* Handle the "no values" case here, to avoid the error message when
+     * calloc() returns NULL. */
+    pthread_mutex_unlock (&cache_lock);
+    return (0);
+  }
+
+  names = calloc (size_arrays, sizeof (*names));
+  times = calloc (size_arrays, sizeof (*times));
+  if ((names == NULL) || (times == NULL))
+  {
+    ERROR ("uc_get_names: calloc failed.");
+    sfree (names);
+    sfree (times);
+    pthread_mutex_unlock (&cache_lock);
+    return (ENOMEM);
+  }
+
   iter = c_avl_get_iterator (cache_tree);
   while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
   {
-    char **temp;
-
     /* remove missing values when list values */
     if (value->state == STATE_MISSING)
       continue;
 
-    if (ret_times != NULL)
-    {
-      cdtime_t *tmp_times;
+    /* c_avl_size does not return a number smaller than the number of elements
+     * returned by c_avl_iterator_next. */
+    assert (number < size_arrays);
 
-      tmp_times = (cdtime_t *) realloc (times, sizeof (cdtime_t) * (number + 1));
-      if (tmp_times == NULL)
-      {
-       status = -1;
-       break;
-      }
-      times = tmp_times;
+    if (ret_times != NULL)
       times[number] = value->last_time;
-    }
 
-    temp = (char **) realloc (names, sizeof (char *) * (number + 1));
-    if (temp == NULL)
-    {
-      status = -1;
-      break;
-    }
-    names = temp;
     names[number] = strdup (key);
     if (names[number] == NULL)
     {
       status = -1;
       break;
     }
+
     number++;
   } /* while (c_avl_iterator_next) */
 
index dcac80764c665ca1dd98a456feea0cb2386692c4..aadf9c5ec1d7f6a4879a5701ebe19f2a25d23633 100644 (file)
@@ -184,7 +184,7 @@ static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */
  */
 static int udb_result_submit (udb_result_t *r, /* {{{ */
     udb_result_preparation_area_t *r_area,
-    const udb_query_t const *q, udb_query_preparation_area_t *q_area)
+    udb_query_t const *q, udb_query_preparation_area_t *q_area)
 {
   value_list_t vl = VALUE_LIST_INIT;
   size_t i;
@@ -219,7 +219,7 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
 
   sstrncpy (vl.host, q_area->host, sizeof (vl.host));
   sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
-  sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.type_instance));
+  sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, r->type, sizeof (vl.type));
 
   /* Set vl.type_instance {{{ */
@@ -259,7 +259,7 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
   return (0);
 } /* }}} void udb_result_submit */
 
-static void udb_result_finish_result (const udb_result_t const *r, /* {{{ */
+static void udb_result_finish_result (udb_result_t const *r, /* {{{ */
     udb_result_preparation_area_t *prep_area)
 {
   if ((r == NULL) || (prep_area == NULL))
@@ -275,7 +275,7 @@ static void udb_result_finish_result (const udb_result_t const *r, /* {{{ */
 static int udb_result_handle_result (udb_result_t *r, /* {{{ */
     udb_query_preparation_area_t *q_area,
     udb_result_preparation_area_t *r_area,
-    const udb_query_t const *q, char **column_values)
+    udb_query_t const *q, char **column_values)
 {
   size_t i;
 
@@ -290,7 +290,7 @@ static int udb_result_handle_result (udb_result_t *r, /* {{{ */
   return udb_result_submit (r, r_area, q, q_area);
 } /* }}} int udb_result_handle_result */
 
-static int udb_result_prepare_result (const udb_result_t const *r, /* {{{ */
+static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     udb_result_preparation_area_t *prep_area,
     char **column_names, size_t column_num)
 {
@@ -825,7 +825,7 @@ int udb_query_check_version (udb_query_t *q, unsigned int version) /* {{{ */
   return (1);
 } /* }}} int udb_query_check_version */
 
-void udb_query_finish_result (const udb_query_t const *q, /* {{{ */
+void udb_query_finish_result (udb_query_t const *q, /* {{{ */
     udb_query_preparation_area_t *prep_area)
 {
   udb_result_preparation_area_t *r_area;
@@ -851,7 +851,7 @@ void udb_query_finish_result (const udb_query_t const *q, /* {{{ */
   }
 } /* }}} void udb_query_finish_result */
 
-int udb_query_handle_result (const udb_query_t const *q, /* {{{ */
+int udb_query_handle_result (udb_query_t const *q, /* {{{ */
     udb_query_preparation_area_t *prep_area, char **column_values)
 {
   udb_result_preparation_area_t *r_area;
@@ -904,7 +904,7 @@ int udb_query_handle_result (const udb_query_t const *q, /* {{{ */
   return (0);
 } /* }}} int udb_query_handle_result */
 
-int udb_query_prepare_result (const udb_query_t const *q, /* {{{ */
+int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
     udb_query_preparation_area_t *prep_area,
     const char *host, const char *plugin, const char *db_name,
     char **column_names, size_t column_num, cdtime_t interval)
index 727be03647714e8bc76f6b4d5403508eeca74616..b6f4cea00d6351c8c0edcf97ab44d0a45cfc7e86 100644 (file)
@@ -65,13 +65,13 @@ void *udb_query_get_user_data (udb_query_t *q);
  */
 int udb_query_check_version (udb_query_t *q, unsigned int version);
 
-int udb_query_prepare_result (const udb_query_t const *q,
+int udb_query_prepare_result (udb_query_t const *q,
     udb_query_preparation_area_t *prep_area,
     const char *host, const char *plugin, const char *db_name,
     char **column_names, size_t column_num, cdtime_t interval);
-int udb_query_handle_result (const udb_query_t const *q,
+int udb_query_handle_result (udb_query_t const *q,
     udb_query_preparation_area_t *prep_area, char **column_values);
-void udb_query_finish_result (const udb_query_t const *q,
+void udb_query_finish_result (udb_query_t const *q,
     udb_query_preparation_area_t *prep_area);
 
 udb_query_preparation_area_t *
index cfa4a5cbefff989c28e4a46accb89e00f1a93f59..80a2ee577f7213c4182a57b70e5f220d6d4d92fa 100644 (file)
 #if HAVE_NETINET_IN_H
 # include <netinet/in.h>
 #endif
+#if HAVE_NETINET_IP6_H
+# include <netinet/ip6.h>
+#endif
+#if HAVE_NETINET_IP_COMPAT_H
+# include <netinet/ip_compat.h>
+#endif
 #if HAVE_ARPA_INET_H
 # include <arpa/inet.h>
 #endif
 
 #if HAVE_STRUCT_UDPHDR_UH_DPORT && HAVE_STRUCT_UDPHDR_UH_SPORT
 # define UDP_DEST uh_dport
-# define UDP_SRC  uh_dport
+# define UDP_SRC  uh_sport
 #elif HAVE_STRUCT_UDPHDR_DEST && HAVE_STRUCT_UDPHDR_SOURCE
 # define UDP_DEST dest
 # define UDP_SRC  source
@@ -449,7 +455,7 @@ handle_ipv6 (struct ip6_hdr *ipv6, int len)
     unsigned int offset;
     int nexthdr;
 
-    struct in6_addr s_addr;
+    struct in6_addr c_src_addr;
     uint16_t payload_len;
 
     if (0 > len)
@@ -457,10 +463,10 @@ handle_ipv6 (struct ip6_hdr *ipv6, int len)
 
     offset = sizeof (struct ip6_hdr);
     nexthdr = ipv6->ip6_nxt;
-    s_addr = ipv6->ip6_src;
+    c_src_addr = ipv6->ip6_src;
     payload_len = ntohs (ipv6->ip6_plen);
 
-    if (ignore_list_match (&s_addr))
+    if (ignore_list_match (&c_src_addr))
            return (0);
 
     /* Parse extension headers. This only handles the standard headers, as
@@ -469,7 +475,6 @@ handle_ipv6 (struct ip6_hdr *ipv6, int len)
            || (IPPROTO_HOPOPTS == nexthdr) /* Hop-by-Hop options. */
            || (IPPROTO_FRAGMENT == nexthdr) /* fragmentation header. */
            || (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
-           || (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
            || (IPPROTO_AH == nexthdr) /* destination options. */
            || (IPPROTO_ESP == nexthdr)) /* encapsulating security payload. */
     {
@@ -527,15 +532,15 @@ handle_ip(const struct ip *ip, int len)
 {
     char buf[PCAP_SNAPLEN];
     int offset = ip->ip_hl << 2;
-    struct in6_addr s_addr;
-    struct in6_addr d_addr;
+    struct in6_addr c_src_addr;
+    struct in6_addr c_dst_addr;
 
     if (ip->ip_v == 6)
        return (handle_ipv6 ((void *) ip, len));
 
-    in6_addr_from_buffer (&s_addr, &ip->ip_src.s_addr, sizeof (ip->ip_src.s_addr), AF_INET);
-    in6_addr_from_buffer (&d_addr, &ip->ip_dst.s_addr, sizeof (ip->ip_dst.s_addr), AF_INET);
-    if (ignore_list_match (&s_addr))
+    in6_addr_from_buffer (&c_src_addr, &ip->ip_src.s_addr, sizeof (ip->ip_src.s_addr), AF_INET);
+    in6_addr_from_buffer (&c_dst_addr, &ip->ip_dst.s_addr, sizeof (ip->ip_dst.s_addr), AF_INET);
+    if (ignore_list_match (&c_src_addr))
            return (0);
     if (IPPROTO_UDP != ip->ip_p)
        return 0;
index d20b7e39bdd453de1bdec5c4564ed30e994647a6..97f21a1f78317ebc4cc5d8ccce7f61dcd322b0ae 100644 (file)
@@ -234,6 +234,7 @@ void fbh_destroy (fbhash_t *h) /* {{{ */
   if (h == NULL)
     return;
 
+  pthread_mutex_destroy (&h->lock);
   free (h->filename);
   fbh_free_tree (h->tree);
 } /* }}} void fbh_destroy */
diff --git a/src/utils_format_graphite.c b/src/utils_format_graphite.c
new file mode 100644 (file)
index 0000000..b9b906f
--- /dev/null
@@ -0,0 +1,240 @@
+/**
+ * collectd - src/utils_format_graphite.c
+ * Copyright (C) 2012  Thomas Meson
+ * Copyright (C) 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Thomas Meson <zllak at hycik.org>
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+
+#include "utils_cache.h"
+#include "utils_format_json.h"
+#include "utils_parse_option.h"
+
+/* Utils functions to format data sets in graphite format.
+ * Largely taken from write_graphite.c as it remains the same formatting */
+
+static int gr_format_values (char *ret, size_t ret_len,
+        int ds_num, const data_set_t *ds, const value_list_t *vl,
+        gauge_t const *rates)
+{
+    size_t offset = 0;
+    int status;
+
+    assert (0 == strcmp (ds->type, vl->type));
+
+    memset (ret, 0, ret_len);
+
+#define BUFFER_ADD(...) do { \
+    status = ssnprintf (ret + offset, ret_len - offset, \
+            __VA_ARGS__); \
+    if (status < 1) \
+    { \
+        return (-1); \
+    } \
+    else if (((size_t) status) >= (ret_len - offset)) \
+    { \
+        return (-1); \
+    } \
+    else \
+    offset += ((size_t) status); \
+} while (0)
+
+    if (ds->ds[ds_num].type == DS_TYPE_GAUGE)
+        BUFFER_ADD ("%f", vl->values[ds_num].gauge);
+    else if (rates != NULL)
+        BUFFER_ADD ("%f", rates[ds_num]);
+    else if (ds->ds[ds_num].type == DS_TYPE_COUNTER)
+        BUFFER_ADD ("%llu", vl->values[ds_num].counter);
+    else if (ds->ds[ds_num].type == DS_TYPE_DERIVE)
+        BUFFER_ADD ("%"PRIi64, vl->values[ds_num].derive);
+    else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
+        BUFFER_ADD ("%"PRIu64, vl->values[ds_num].absolute);
+    else
+    {
+        ERROR ("gr_format_values plugin: Unknown data source type: %i",
+                ds->ds[ds_num].type);
+        return (-1);
+    }
+
+#undef BUFFER_ADD
+
+    return (0);
+}
+
+static void gr_copy_escape_part (char *dst, const char *src, size_t dst_len,
+    char escape_char)
+{
+    size_t i;
+
+    memset (dst, 0, dst_len);
+
+    if (src == NULL)
+        return;
+
+    for (i = 0; i < dst_len; i++)
+    {
+        if (src[i] == 0)
+        {
+            dst[i] = 0;
+            break;
+        }
+
+        if ((src[i] == '.')
+                || isspace ((int) src[i])
+                || iscntrl ((int) src[i]))
+            dst[i] = escape_char;
+        else
+            dst[i] = src[i];
+    }
+}
+
+static int gr_format_name (char *ret, int ret_len,
+        const value_list_t *vl,
+        const char *ds_name,
+        char *prefix,
+        char *postfix,
+        char escape_char)
+{
+    char n_host[DATA_MAX_NAME_LEN];
+    char n_plugin[DATA_MAX_NAME_LEN];
+    char n_plugin_instance[DATA_MAX_NAME_LEN];
+    char n_type[DATA_MAX_NAME_LEN];
+    char n_type_instance[DATA_MAX_NAME_LEN];
+
+    char tmp_plugin[2 * DATA_MAX_NAME_LEN + 1];
+    char tmp_type[2 * DATA_MAX_NAME_LEN + 1];
+
+    if (prefix == NULL)
+        prefix = "";
+
+    if (postfix == NULL)
+        postfix = "";
+
+    gr_copy_escape_part (n_host, vl->host,
+            sizeof (n_host), escape_char);
+    gr_copy_escape_part (n_plugin, vl->plugin,
+            sizeof (n_plugin), escape_char);
+    gr_copy_escape_part (n_plugin_instance, vl->plugin_instance,
+            sizeof (n_plugin_instance), escape_char);
+    gr_copy_escape_part (n_type, vl->type,
+            sizeof (n_type), escape_char);
+    gr_copy_escape_part (n_type_instance, vl->type_instance,
+            sizeof (n_type_instance), escape_char);
+
+    if (n_plugin_instance[0] != '\0')
+        ssnprintf (tmp_plugin, sizeof (tmp_plugin), "%s%c%s",
+            n_plugin,
+            '-',
+            n_plugin_instance);
+    else
+        sstrncpy (tmp_plugin, n_plugin, sizeof (tmp_plugin));
+
+    if (n_type_instance[0] != '\0')
+        ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
+            n_type,
+            '-',
+            n_type_instance);
+    else
+        sstrncpy (tmp_type, n_type, sizeof (tmp_type));
+
+    if (ds_name != NULL)
+        ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
+            prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
+    else
+        ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
+            prefix, n_host, postfix, tmp_plugin, tmp_type);
+
+    return (0);
+}
+
+int format_graphite (char *buffer, size_t buffer_size,
+    const data_set_t *ds, const value_list_t *vl, char *prefix,
+    char *postfix, char escape_char,
+    _Bool store_rates)
+{
+    int status = 0;
+    int i;
+    int buffer_pos = 0;
+
+    gauge_t *rates = NULL;
+    if (store_rates)
+      rates = uc_get_rate (ds, vl);
+
+    for (i = 0; i < ds->ds_num; i++)
+    {
+        const char *ds_name = NULL;
+        char        key[10*DATA_MAX_NAME_LEN];
+        char        values[512];
+        size_t      message_len;
+        char        message[1024];
+
+        ds_name = ds->ds[i].name;
+
+        /* Copy the identifier to `key' and escape it. */
+        status = gr_format_name (key, sizeof (key), vl, ds_name,
+                    prefix, postfix, escape_char);
+        if (status != 0)
+        {
+            ERROR ("format_graphite: error with gr_format_name");
+            sfree (rates);
+            return (status);
+        }
+
+        escape_string (key, sizeof (key));
+        /* Convert the values to an ASCII representation and put that into
+         * `values'. */
+        status = gr_format_values (values, sizeof (values), i, ds, vl, rates);
+        if (status != 0)
+        {
+            ERROR ("format_graphite: error with gr_format_values");
+            sfree (rates);
+            return (status);
+        }
+
+        /* Compute the graphite command */
+        message_len = (size_t) ssnprintf (message, sizeof (message),
+                "%s %s %u\r\n",
+                key,
+                values,
+                (unsigned int) CDTIME_T_TO_TIME_T (vl->time));
+        if (message_len >= sizeof (message)) {
+            ERROR ("format_graphite: message buffer too small: "
+                    "Need %zu bytes.", message_len + 1);
+            sfree (rates);
+            return (-ENOMEM);
+        }
+
+        /* Append it in case we got multiple data set */
+        if ((buffer_pos + message_len) >= buffer_size)
+        {
+            ERROR ("format_graphite: target buffer too small");
+            sfree (rates);
+            return (-ENOMEM);
+        }
+        memcpy((void *) (buffer + buffer_pos), message, message_len);
+        buffer_pos += message_len;
+    }
+    sfree (rates);
+    return (status);
+} /* int format_graphite */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_format_graphite.h b/src/utils_format_graphite.h
new file mode 100644 (file)
index 0000000..a7a05bb
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * collectd - src/utils_format_graphite.h
+ * Copyright (C) 2012  Thomas Meson
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Author:
+ *   Thomas Meson <zllak at hycik.org>
+ **/
+
+#ifndef UTILS_FORMAT_GRAPHITE_H
+#define UTILS_FORMAT_GRAPHITE_H 1
+
+#include "collectd.h"
+#include "plugin.h"
+
+int format_graphite (char *buffer,
+    size_t buffer_size, const data_set_t *ds,
+    const value_list_t *vl, const char *prefix,
+    const char *postfix, const char escape_char,
+    _Bool store_rates);
+
+#endif /* UTILS_FORMAT_GRAPHITE_H */
index 2a5526b29d2f77833c1d455a1b3fd10103b9aeb7..bbc3dfdb4efc9b21be341e2e1ff2845c67e5ed33 100644 (file)
@@ -70,7 +70,7 @@ static int escape_string (char *buffer, size_t buffer_size, /* {{{ */
 #undef BUFFER_ADD
 
   return (0);
-} /* }}} int buffer_add_string */
+} /* }}} int escape_string */
 
 static int values_to_json (char *buffer, size_t buffer_size, /* {{{ */
                 const data_set_t *ds, const value_list_t *vl, int store_rates)
@@ -152,7 +152,7 @@ static int values_to_json (char *buffer, size_t buffer_size, /* {{{ */
 } /* }}} int values_to_json */
 
 static int dstypes_to_json (char *buffer, size_t buffer_size, /* {{{ */
-                const data_set_t *ds, const value_list_t *vl)
+                const data_set_t *ds)
 {
   size_t offset = 0;
   int i;
@@ -189,7 +189,7 @@ static int dstypes_to_json (char *buffer, size_t buffer_size, /* {{{ */
 } /* }}} int dstypes_to_json */
 
 static int dsnames_to_json (char *buffer, size_t buffer_size, /* {{{ */
-                const data_set_t *ds, const value_list_t *vl)
+                const data_set_t *ds)
 {
   size_t offset = 0;
   int i;
@@ -225,6 +225,86 @@ static int dsnames_to_json (char *buffer, size_t buffer_size, /* {{{ */
   return (0);
 } /* }}} int dsnames_to_json */
 
+static int meta_data_to_json (char *buffer, size_t buffer_size, /* {{{ */
+    meta_data_t *meta)
+{
+  size_t offset = 0;
+  char **keys = NULL;
+  int keys_num;
+  int status;
+  int i;
+
+  memset (buffer, 0, buffer_size);
+
+#define BUFFER_ADD(...) do { \
+  status = ssnprintf (buffer + offset, buffer_size - offset, \
+      __VA_ARGS__); \
+  if (status < 1) \
+    return (-1); \
+  else if (((size_t) status) >= (buffer_size - offset)) \
+    return (-ENOMEM); \
+  else \
+    offset += ((size_t) status); \
+} while (0)
+
+  keys_num = meta_data_toc (meta, &keys);
+  for (i = 0; i < keys_num; ++i)
+  {
+    int type;
+    char *key = keys[i];
+
+    type = meta_data_type (meta, key);
+    if (type == MD_TYPE_STRING)
+    {
+      char *value = NULL;
+      if (meta_data_get_string (meta, key, &value) == 0)
+      {
+        char temp[512] = "";
+        escape_string (temp, sizeof (temp), value);
+        sfree (value);
+        BUFFER_ADD (",\"%s\":%s", key, temp);
+      }
+    }
+    else if (type == MD_TYPE_SIGNED_INT)
+    {
+      int64_t value = 0;
+      if (meta_data_get_signed_int (meta, key, &value) == 0)
+        BUFFER_ADD (",\"%s\":%"PRIi64, key, value);
+    }
+    else if (type == MD_TYPE_UNSIGNED_INT)
+    {
+      uint64_t value = 0;
+      if (meta_data_get_unsigned_int (meta, key, &value) == 0)
+        BUFFER_ADD (",\"%s\":%"PRIu64, key, value);
+    }
+    else if (type == MD_TYPE_DOUBLE)
+    {
+      double value = 0.0;
+      if (meta_data_get_double (meta, key, &value) == 0)
+        BUFFER_ADD (",\"%s\":%f", key, value);
+    }
+    else if (type == MD_TYPE_BOOLEAN)
+    {
+      _Bool value = 0;
+      if (meta_data_get_boolean (meta, key, &value) == 0)
+        BUFFER_ADD (",\"%s\":%s", key, value ? "true" : "false");
+    }
+
+    free (key);
+  } /* for (keys) */
+  free (keys);
+
+  if (offset <= 0)
+    return (ENOENT);
+
+  buffer[0] = '{'; /* replace leading ',' */
+  BUFFER_ADD ("}");
+
+#undef BUFFER_ADD
+
+  return (0);
+} /* int meta_data_to_json */
+
 static int value_list_to_json (char *buffer, size_t buffer_size, /* {{{ */
                 const data_set_t *ds, const value_list_t *vl, int store_rates)
 {
@@ -254,12 +334,12 @@ static int value_list_to_json (char *buffer, size_t buffer_size, /* {{{ */
     return (status);
   BUFFER_ADD ("\"values\":%s", temp);
 
-  status = dstypes_to_json (temp, sizeof (temp), ds, vl);
+  status = dstypes_to_json (temp, sizeof (temp), ds);
   if (status != 0)
     return (status);
   BUFFER_ADD (",\"dstypes\":%s", temp);
 
-  status = dsnames_to_json (temp, sizeof (temp), ds, vl);
+  status = dsnames_to_json (temp, sizeof (temp), ds);
   if (status != 0)
     return (status);
   BUFFER_ADD (",\"dsnames\":%s", temp);
@@ -280,6 +360,17 @@ static int value_list_to_json (char *buffer, size_t buffer_size, /* {{{ */
   BUFFER_ADD_KEYVAL ("type", vl->type);
   BUFFER_ADD_KEYVAL ("type_instance", vl->type_instance);
 
+  if (vl->meta != NULL)
+  {
+    char meta_buffer[buffer_size];
+    memset (meta_buffer, 0, sizeof (meta_buffer));
+    status = meta_data_to_json (meta_buffer, sizeof (meta_buffer), vl->meta);
+    if (status != 0)
+      return (status);
+
+    BUFFER_ADD (",\"meta\":%s", meta_buffer);
+  } /* if (vl->meta != NULL) */
+
   BUFFER_ADD ("}");
 
 #undef BUFFER_ADD_KEYVAL
index 91ac6ce548e878b4078e17d89cc7ce609995ee51..091b5fa6dce1d2cc3bc48bb093298f39e5d0af46 100644 (file)
@@ -406,9 +406,9 @@ int cu_rrd_create_file (const char *filename, /* {{{ */
   argv[ds_num + rra_num] = NULL;
 
   last_up = CDTIME_T_TO_TIME_T (vl->time);
-  if (last_up <= 10)
+  if (last_up <= 0)
     last_up = time (NULL);
-  last_up -= 10;
+  last_up -= 1;
 
   if (cfg->stepsize > 0)
     stepsize = cfg->stepsize;
index 357b5f11d0033d7f7efd1384e7ce666ba2bf3a70..de60e39c7b21759f0fdefb062d3d74475df90fed 100644 (file)
@@ -412,6 +412,11 @@ static int varnish_read (user_data_t *ud) /* {{{ */
 
        vd = VSM_New();
        VSC_Setup(vd);
+       if (VSM_n_Arg(vd, conf->instance) == -1)
+       {
+               ERROR ("Varnish plugin : unable to load statistics from instance");
+               return (-1);
+       }
        if (VSC_Open (vd, /* diag = */ 1))
        {
                ERROR ("varnish plugin: Unable to load statistics.");
index d6583a75f04ebb63901649a6f6f763ae3a9aa473..2ae30efe2ca179b0fd13cfafe5914f5a031b14ff 100644 (file)
@@ -47,6 +47,7 @@
 
 #include "utils_cache.h"
 #include "utils_parse_option.h"
+#include "utils_format_graphite.h"
 
 /* Folks without pthread will need to disable this plugin. */
 #include <pthread.h>
@@ -284,175 +285,12 @@ static int wg_flush (cdtime_t timeout,
     return (status);
 }
 
-static int wg_format_values (char *ret, size_t ret_len,
-        int ds_num, const data_set_t *ds, const value_list_t *vl,
-        _Bool store_rates)
-{
-    size_t offset = 0;
-    int status;
-    gauge_t *rates = NULL;
-
-    assert (0 == strcmp (ds->type, vl->type));
-
-    memset (ret, 0, ret_len);
-
-#define BUFFER_ADD(...) do { \
-    status = ssnprintf (ret + offset, ret_len - offset, \
-            __VA_ARGS__); \
-    if (status < 1) \
-    { \
-        sfree (rates); \
-        return (-1); \
-    } \
-    else if (((size_t) status) >= (ret_len - offset)) \
-    { \
-        sfree (rates); \
-        return (-1); \
-    } \
-    else \
-    offset += ((size_t) status); \
-} while (0)
-
-    if (ds->ds[ds_num].type == DS_TYPE_GAUGE)
-        BUFFER_ADD ("%f", vl->values[ds_num].gauge);
-    else if (store_rates)
-    {
-        if (rates == NULL)
-            rates = uc_get_rate (ds, vl);
-        if (rates == NULL)
-        {
-            WARNING ("format_values: "
-                    "uc_get_rate failed.");
-            return (-1);
-        }
-        BUFFER_ADD ("%g", rates[ds_num]);
-    }
-    else if (ds->ds[ds_num].type == DS_TYPE_COUNTER)
-        BUFFER_ADD ("%llu", vl->values[ds_num].counter);
-    else if (ds->ds[ds_num].type == DS_TYPE_DERIVE)
-        BUFFER_ADD ("%"PRIi64, vl->values[ds_num].derive);
-    else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
-        BUFFER_ADD ("%"PRIu64, vl->values[ds_num].absolute);
-    else
-    {
-        ERROR ("format_values plugin: Unknown data source type: %i",
-                ds->ds[ds_num].type);
-        sfree (rates);
-        return (-1);
-    }
-
-#undef BUFFER_ADD
-
-    sfree (rates);
-    return (0);
-}
-
-static void wg_copy_escape_part (char *dst, const char *src, size_t dst_len,
-    char escape_char)
-{
-    size_t i;
-
-    memset (dst, 0, dst_len);
-
-    if (src == NULL)
-        return;
-
-    for (i = 0; i < dst_len; i++)
-    {
-        if (src[i] == 0)
-        {
-            dst[i] = 0;
-            break;
-        }
-
-        if ((src[i] == '.')
-                || isspace ((int) src[i])
-                || iscntrl ((int) src[i]))
-            dst[i] = escape_char;
-        else
-            dst[i] = src[i];
-    }
-}
-
-static int wg_format_name (char *ret, int ret_len,
-        const value_list_t *vl,
-        const struct wg_callback *cb,
-        const char *ds_name)
-{
-    char n_host[DATA_MAX_NAME_LEN];
-    char n_plugin[DATA_MAX_NAME_LEN];
-    char n_plugin_instance[DATA_MAX_NAME_LEN];
-    char n_type[DATA_MAX_NAME_LEN];
-    char n_type_instance[DATA_MAX_NAME_LEN];
-
-    char *prefix;
-    char *postfix;
-
-    char tmp_plugin[2 * DATA_MAX_NAME_LEN + 1];
-    char tmp_type[2 * DATA_MAX_NAME_LEN + 1];
-
-    prefix = cb->prefix;
-    if (prefix == NULL)
-        prefix = "";
-
-    postfix = cb->postfix;
-    if (postfix == NULL)
-        postfix = "";
-
-    wg_copy_escape_part (n_host, vl->host,
-            sizeof (n_host), cb->escape_char);
-    wg_copy_escape_part (n_plugin, vl->plugin,
-            sizeof (n_plugin), cb->escape_char);
-    wg_copy_escape_part (n_plugin_instance, vl->plugin_instance,
-            sizeof (n_plugin_instance), cb->escape_char);
-    wg_copy_escape_part (n_type, vl->type,
-            sizeof (n_type), cb->escape_char);
-    wg_copy_escape_part (n_type_instance, vl->type_instance,
-            sizeof (n_type_instance), cb->escape_char);
-
-    if (n_plugin_instance[0] != '\0')
-        ssnprintf (tmp_plugin, sizeof (tmp_plugin), "%s%c%s",
-            n_plugin,
-            cb->separate_instances ? '.' : '-',
-            n_plugin_instance);
-    else
-        sstrncpy (tmp_plugin, n_plugin, sizeof (tmp_plugin));
-
-    if (n_type_instance[0] != '\0')
-        ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
-            n_type,
-            cb->separate_instances ? '.' : '-',
-            n_type_instance);
-    else
-        sstrncpy (tmp_type, n_type, sizeof (tmp_type));
-
-    if (ds_name != NULL)
-        ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
-            prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
-    else
-        ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
-            prefix, n_host, postfix, tmp_plugin, tmp_type);
-
-    return (0);
-}
-
-static int wg_send_message (const char* key, const char* value,
-        cdtime_t time, struct wg_callback *cb)
+static int wg_send_message (char const *message, struct wg_callback *cb)
 {
     int status;
     size_t message_len;
-    char message[1024];
-
-    message_len = (size_t) ssnprintf (message, sizeof (message),
-            "%s %s %u\r\n",
-            key,
-            value,
-            (unsigned int) CDTIME_T_TO_TIME_T (time));
-    if (message_len >= sizeof (message)) {
-        ERROR ("write_graphite plugin: message buffer too small: "
-                "Need %zu bytes.", message_len + 1);
-        return (-1);
-    }
+
+    message_len = strlen (message);
 
     pthread_mutex_lock (&cb->send_lock);
 
@@ -502,10 +340,8 @@ static int wg_send_message (const char* key, const char* value,
 static int wg_write_messages (const data_set_t *ds, const value_list_t *vl,
         struct wg_callback *cb)
 {
-    char key[10*DATA_MAX_NAME_LEN];
-    char values[512];
-
-    int status, i;
+    char buffer[4096];
+    int status;
 
     if (0 != strcmp (ds->type, vl->type))
     {
@@ -514,45 +350,22 @@ static int wg_write_messages (const data_set_t *ds, const value_list_t *vl,
         return -1;
     }
 
-    for (i = 0; i < ds->ds_num; i++)
-    {
-        const char *ds_name = NULL;
-
-        if (cb->always_append_ds || (ds->ds_num > 1))
-            ds_name = ds->ds[i].name;
-
-        /* Copy the identifier to `key' and escape it. */
-        status = wg_format_name (key, sizeof (key), vl, cb, ds_name);
-        if (status != 0)
-        {
-            ERROR ("write_graphite plugin: error with format_name");
-            return (status);
-        }
-
-        escape_string (key, sizeof (key));
-        /* Convert the values to an ASCII representation and put that into
-         * `values'. */
-        status = wg_format_values (values, sizeof (values), i, ds, vl,
-                    cb->store_rates);
-        if (status != 0)
-        {
-            ERROR ("write_graphite plugin: error with "
-                    "wg_format_values");
-            return (status);
-        }
+    memset (buffer, 0, sizeof (buffer));
+    status = format_graphite (buffer, sizeof (buffer), ds, vl,
+            cb->prefix, cb->postfix, cb->escape_char, cb->store_rates);
+    if (status != 0) /* error message has been printed already. */
+        return (status);
 
-        /* Send the message to graphite */
-        status = wg_send_message (key, values, vl->time, cb);
-        if (status != 0)
-        {
-            ERROR ("write_graphite plugin: error with "
-                    "wg_send_message");
-            return (status);
-        }
+    wg_send_message (buffer, cb);
+    if (status != 0)
+    {
+        ERROR ("write_graphite plugin: wg_send_message failed "
+                "with status %i.", status);
+        return (status);
     }
 
     return (0);
-}
+} /* int wg_write_messages */
 
 static int wg_write (const data_set_t *ds, const value_list_t *vl,
         user_data_t *user_data)
index 8d76b608affa4c58d1a3c23cfbeda4f16cc8f5bc..c7b768205cdf2ca59e0938b8b5a955d3deb0e78a 100644 (file)
@@ -195,7 +195,14 @@ static int wm_write (const data_set_t *ds, /* {{{ */
   /* Assert if the connection has been established */
   assert (mongo_is_connected (node->conn));
 
-  status = mongo_insert (node->conn, collection_name, bson_record);
+  #if MONGO_MINOR >= 6
+    /* There was an API change in 0.6.0 as linked below */
+    /* https://github.com/mongodb/mongo-c-driver/blob/master/HISTORY.md */
+    status = mongo_insert (node->conn, collection_name, bson_record, NULL);
+  #else
+    status = mongo_insert (node->conn, collection_name, bson_record);
+  #endif
+
   if(status != MONGO_OK)
   {
     ERROR ( "write_mongodb plugin: error inserting record: %d", node->conn->err);
index e77569f5d0996c6e7f94b53eac51ece91d02805a..046b7b02120953c65d66de9c27dd2ff5ac482e8c 100644 (file)
@@ -28,7 +28,7 @@
 /*
  * Global variables
  */
-static kstat_t *ksp;
+
 extern kstat_ctl_t *kc;
 
 static void za_submit (const char* type, const char* type_instance, value_t* values, int values_len)
@@ -60,7 +60,7 @@ static int za_read_derive (kstat_t *ksp, const char *kstat_value,
   long long tmp;
   value_t v;
 
-  tmp = get_kstat_value (ksp, kstat_value);
+  tmp = get_kstat_value (ksp, (char *)kstat_value);
   if (tmp == -1LL)
   {
     ERROR ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
@@ -69,6 +69,7 @@ static int za_read_derive (kstat_t *ksp, const char *kstat_value,
 
   v.derive = (derive_t) tmp;
   za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
+  return (0);
 }
 
 static int za_read_gauge (kstat_t *ksp, const char *kstat_value,
@@ -77,7 +78,7 @@ static int za_read_gauge (kstat_t *ksp, const char *kstat_value,
   long long tmp;
   value_t v;
 
-  tmp = get_kstat_value (ksp, kstat_value);
+  tmp = get_kstat_value (ksp, (char *)kstat_value);
   if (tmp == -1LL)
   {
     ERROR ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
@@ -86,6 +87,7 @@ static int za_read_gauge (kstat_t *ksp, const char *kstat_value,
 
   v.gauge = (gauge_t) tmp;
   za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
+  return (0);
 }
 
 static void za_submit_ratio (const char* type_instance, gauge_t hits, gauge_t misses)
@@ -107,6 +109,7 @@ static int za_read (void)
 {
        gauge_t  arc_hits, arc_misses, l2_hits, l2_misses;
        value_t  l2_io[2];
+       kstat_t  *ksp   = NULL;
 
        get_kstat (&ksp, "zfs", 0, "arcstats");
        if (ksp == NULL)
@@ -163,8 +166,6 @@ static int za_read (void)
 
 static int za_init (void) /* {{{ */
 {
-       ksp = NULL;
-
        /* kstats chain already opened by update_kstat (using *kc), verify everything went fine. */
        if (kc == NULL)
        {
index 97a27a0d75f6bf3adb19cafe27622503eda72c21..d6d7bb202ba41f39a806fa6ca22ec9cb22b70961 100755 (executable)
@@ -10,8 +10,4 @@ fi
 
 VERSION="`echo \"$VERSION\" | sed -e 's/-/./g'`"
 
-if test "x`uname -s`" = "xAIX" ; then
-       echo "$VERSION\c"
-else 
-       echo -n "$VERSION"
-fi
+echo -n "$VERSION"