Code

Merge branch 'collectd-5.6'
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Wed, 26 Oct 2016 17:33:44 +0000 (19:33 +0200)
committerRuben Kerkhof <ruben@rubenkerkhof.com>
Wed, 26 Oct 2016 17:33:44 +0000 (19:33 +0200)
177 files changed:
AUTHORS
CONTRIBUTING.md
NEWS [deleted file]
README
TODO [deleted file]
bindings/perl/lib/Collectd.pm
configure.ac
contrib/SpamAssassin/Collectd.pm
contrib/examples/myplugin.c
contrib/redhat/collectd.spec
docs/BUILD.dpdkstat.md [new file with mode: 0644]
docs/BUILD.java.md [new file with mode: 0644]
proto/collectd.proto
src/Makefile.am
src/aggregation.c
src/amqp.c
src/apache.c
src/apcups.c
src/apple_sensors.c
src/aquaero.c
src/ascent.c
src/barometer.c
src/battery.c
src/battery_statefs.c [new file with mode: 0644]
src/bind.c
src/ceph.c
src/cgroups.c
src/chrony.c
src/collectd-perl.pod
src/collectd.conf.in
src/collectd.conf.pod
src/conntrack.c
src/contextswitch.c
src/cpu.c
src/cpufreq.c
src/cpusleep.c
src/curl.c
src/curl_json.c
src/curl_xml.c
src/daemon/collectd.c
src/daemon/common.c
src/daemon/common.h
src/daemon/common_test.c
src/daemon/meta_data.c
src/daemon/meta_data.h
src/daemon/plugin.c
src/daemon/plugin.h
src/daemon/plugin_mock.c
src/daemon/utils_cache.h
src/daemon/utils_cache_mock.c
src/daemon/utils_tail_match.c
src/daemon/utils_time.c
src/daemon/utils_time.h
src/dbi.c
src/df.c
src/disk.c
src/dns.c
src/dpdkstat.c [new file with mode: 0644]
src/drbd.c
src/email.c
src/entropy.c
src/ethstat.c
src/exec.c
src/fhcount.c
src/filecount.c
src/fscache.c
src/gps.c
src/grpc.cc
src/hddtemp.c
src/hugepages.c [new file with mode: 0644]
src/intel_rdt.c [new file with mode: 0644]
src/interface.c
src/ipc.c
src/ipmi.c
src/iptables.c
src/ipvs.c
src/irq.c
src/java.c
src/load.c
src/lpar.c
src/lua.c
src/lvm.c
src/madwifi.c
src/match_regex.c
src/mbmon.c
src/md.c
src/memcachec.c
src/memcached.c
src/memory.c
src/mic.c
src/modbus.c
src/mqtt.c
src/multimeter.c
src/mysql.c
src/netapp.c
src/netlink.c
src/network.c
src/nfs.c
src/nginx.c
src/ntpd.c
src/numa.c
src/nut.c
src/olsrd.c
src/onewire.c
src/openldap.c
src/openvpn.c
src/perl.c
src/pf.c
src/pinba.c
src/ping.c
src/postgresql.c
src/powerdns.c
src/processes.c
src/protocols.c
src/python.c
src/redis.c
src/routeros.c
src/rrdcached.c
src/sensors.c
src/serial.c
src/sigrok.c
src/smart.c
src/snmp.c
src/statsd.c
src/swap.c
src/table.c
src/tail.c
src/tail_csv.c
src/tape.c
src/target_replace.c
src/target_set.c
src/target_v5upgrade.c
src/tcpconns.c
src/teamspeak2.c
src/ted.c
src/testing.h
src/thermal.c
src/tokyotyrant.c
src/turbostat.c
src/types.db
src/unixsock.c
src/uptime.c
src/users.c
src/utils_cmd_flush.c
src/utils_cmd_flush.h
src/utils_cmd_getthreshold.c
src/utils_cmd_getval.c
src/utils_cmd_getval.h
src/utils_cmd_listval.c
src/utils_cmd_listval.h
src/utils_cmd_putval.c
src/utils_cmd_putval.h
src/utils_cmds.c [new file with mode: 0644]
src/utils_cmds.h [new file with mode: 0644]
src/utils_cmds_test.c [new file with mode: 0644]
src/utils_format_graphite.c
src/utils_format_graphite.h
src/utils_vl_lookup.c
src/utils_vl_lookup.h
src/utils_vl_lookup_test.c
src/valgrind.FreeBSD.suppress
src/varnish.c
src/virt.c
src/vmem.c
src/vserver.c
src/wireless.c
src/write_graphite.c
src/write_http.c
src/write_kafka.c
src/write_log.c
src/write_mongodb.c
src/write_redis.c
src/xencpu.c
src/xmms.c
src/zfs_arc.c
src/zone.c
src/zookeeper.c

diff --git a/AUTHORS b/AUTHORS
index 28220e79a6e7e6c723f7dfddcc29bb64990094ed..8962e775b5e2b78f134ccb60b1c19c7e5c445494 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -72,7 +72,7 @@ Aurélien Reynaud <collectd at wattapower.net>
  - LPAR plugin.
  - Various fixes for AIX, HP-UX and Solaris.
 
-Benjamin Gilbert <bgilbert at cs.cmu.edu>
+Benjamin Gilbert <bgilbert at backtick.net>
  - Improvements to the LVM plugin.
 
 Bert Vermeulen <bert at biot.com>
index eeb174ba2989f27fe02369542f9b464c9867c10b..791446a0a7b38af4a1b7a897aed3e4dc184ca7ac 100644 (file)
@@ -2,7 +2,7 @@
 
 Thanks for taking the time to contribute to the [collectd
 project](https://collectd.org/)! This document tries to give some guidance to
-make the process of contributing to *collectd* as pleasant and possible.
+make the process of contributing to *collectd* as pleasant as possible.
 
 ## Bug reports
 
@@ -19,7 +19,7 @@ following questions:
     [stack trace](https://collectd.org/wiki/index.php/Core_file).
 
 Please monitor your issue for a couple of days and reply to questions. To keep
-the project manageable have to do some housekeeping, meaning we will close
+the project manageable, we have to do some housekeeping; meaning we will close
 issues that have become stale.
 
 ## Code contributions
@@ -35,7 +35,7 @@ the mailing list have a tendency to fall through the cracks.
     coding style of the code around your changes.
 *   *Documentation:* New config options need to be documented in two places: the
     manpage (`src/collectd.conf.pod`) and the example config
-    (`src/collectd.conf.in`).
+    (`src/collectd.conf.in`). New plugins need to be added to the `README` file.
 *   *Continuous integration:* Once your PR is created, our continuous
     integration environment will try to build it on a number of platforms. If
     this reports a failure, please investigate and fix the problem. We will at
diff --git a/NEWS b/NEWS
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/README b/README
index ee909d640c328868f37a9ea04d9414443343ecc8..0989312f413f640a9dc5be0d80b1ee44efcab824 100644 (file)
--- a/README
+++ b/README
@@ -96,6 +96,10 @@ Features
       DNS traffic: Query types, response codes, opcodes and traffic/octets
       transferred.
 
+    - dpdkstat
+      Collect DPDK interface statistics.
+      See docs/BUILD.dpdkstat.md for detailed build instructions.
+
     - drbd
       Collect individual drbd resource statistics.
 
@@ -128,12 +132,23 @@ Features
     - gps
       Monitor gps related data through gpsd.
 
-    - grpc
-      Receive values over the network using the gRPC framework.
-
     - hddtemp
       Hard disk temperatures using hddtempd.
 
+    - hugepages
+      Report the number of used and free hugepages. More info on
+      hugepages can be found here:
+      https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt.
+
+    - intel_rdt
+      The intel_rdt plugin collects information provided by monitoring features
+      of Intel Resource Director Technology (Intel(R) RDT) like Cache Monitoring
+      Technology (CMT), Memory Bandwidth Monitoring (MBM). These features
+      provide information about utilization of shared resources like last level
+      cache occupancy, local memory bandwidth usage, remote memory bandwidth
+      usage, instructions per clock.
+      <https://01.org/packet-processing/cache-monitoring-technology-memory-bandwidth-monitoring-cache-allocation-technology-code-and-data>
+
     - interface
       Interface traffic: Number of octets, packets and errors for each
       interface.
@@ -159,7 +174,8 @@ Features
 
     - java
       Integrates a `Java Virtual Machine' (JVM) to execute plugins in Java
-      bytecode. See “Configuring with libjvm” below.
+      bytecode.
+      See docs/BUILD.java.md for detailed build instructions.
 
     - load
       System load average over the last 1, 5 and 15 minutes.
@@ -182,14 +198,14 @@ Features
       Queries very detailed usage statistics from wireless LAN adapters and
       interfaces that use the Atheros chipset and the MadWifi driver.
 
-    - mbmon
-      Motherboard sensors: temperature, fan speed and voltage information,
-      using mbmon(1).
-
     - md
       Linux software-RAID device information (number of active, failed, spare
       and missing disks).
 
+    - mbmon
+      Motherboard sensors: temperature, fan speed and voltage information,
+      using mbmon(1).
+
     - memcachec
       Query and parse data from a memcache daemon (memcached).
 
@@ -209,9 +225,6 @@ Features
       Reads values from Modbus/TCP enabled devices. Supports reading values
       from multiple "slaves" so gateway devices can be used.
 
-    - mqtt
-      Publishes and subscribes to MQTT topics.
-
     - multimeter
       Information provided by serial multimeters, such as the `Metex
       M-4650CR'.
@@ -390,7 +403,7 @@ Features
       CPU, memory, disk and network I/O statistics from virtual machines.
 
     - vmem
-      Virtual memory statistics, e. g. the number of page-ins/-outs or the
+      Virtual memory statistics, e.g. the number of page-ins/-outs or the
       number of pagefaults.
 
     - vserver
@@ -428,10 +441,16 @@ Features
       diskspace but is extremely portable and can be analysed with almost
       every program that can analyse anything. Even Microsoft's Excel..
 
+    - grpc
+      Send and receive values over the network using the gRPC framework.
+
     - lua
       It's possible to implement write plugins in Lua using the Lua
       plugin. See collectd-lua(5) for details.
 
+    - mqtt
+      Publishes and subscribes to MQTT topics.
+
     - network
       Send the data to a remote host to save the data somehow. This is useful
       for large setups where the data should be saved by a dedicated machine.
@@ -651,12 +670,22 @@ Prerequisites
 
   * Usual suspects: C compiler, linker, preprocessor, make, ...
 
+    collectd makes use of some common C99 features, e.g. compound literals and
+    mixed declarations, and therefore requires a C99 compatible compiler.
+
+    On Debian and Ubuntu, the "build-essential" package should pull in
+    everything that's necessary.
+
   * A POSIX-threads (pthread) implementation.
     Since gathering some statistics is slow (network connections, slow devices,
     etc) collectd is parallelized. The POSIX threads interface is being
     used and should be found in various implementations for hopefully all
     platforms.
 
+  * When building from the Git repository, flex (tokenizer) and bison (parser
+    generator) are required. Release tarballs include the generated files – you
+    don't need these packages in that case.
+
   * aerotools-ng (optional)
     Used by the `aquaero' plugin. Currently, the `libaquaero5' library, which
     is used by the `aerotools-ng' toolkit, is not compiled as a shared object
@@ -731,8 +760,8 @@ Prerequisites
 
   * libjvm (optional)
     Library that encapsulates the `Java Virtual Machine' (JVM). This library is
-    used by the `java' plugin to execute Java bytecode. See “Configuring with
-    libjvm” below.
+    used by the `java' plugin to execute Java bytecode.
+    See docs/BUILD.java.md for detailed build instructions.
     <http://openjdk.java.net/> (and others)
 
   * libldap (optional)
@@ -806,6 +835,11 @@ Prerequisites
     The PostgreSQL C client library used by the `postgresql' plugin.
     <http://www.postgresql.org/>
 
+  * libpqos (optional)
+    The PQoS library for Intel(R) Resource Director Technology used by the
+    `intel_rdt' plugin.
+    <https://github.com/01org/intel-cmt-cat>
+
   * libprotobuf, protoc 3.0+ (optional)
     Used by the `grpc' plugin to generate service stubs and code to handle
     network packets of collectd's protobuf-based network protocol.
@@ -926,44 +960,6 @@ Configuring / Compiling / Installing
   prefixed to all installation directories. This might be useful when creating
   packages for collectd.
 
-Configuring with libjvm
------------------------
-
-  To determine the location of the required files of a Java installation is not
-  an easy task, because the locations vary with your kernel (Linux, SunOS, …)
-  and with your architecture (x86, SPARC, …) and there is no ‘java-config’
-  script we could use. Configuration of the JVM library is therefore a bit
-  tricky.
-
-  The easiest way to use the `--with-java=$JAVA_HOME' option, where
-  `$JAVA_HOME' is usually something like:
-    /usr/lib/jvm/java-1.5.0-sun-1.5.0.14
-
-  The configure script will then use find(1) to look for the following files:
-
-    - jni.h
-    - jni_md.h
-    - libjvm.so
-
-  If found, appropriate CPP-flags and LD-flags are set and the following
-  library checks succeed.
-
-  If this doesn't work for you, you have the possibility to specify CPP-flags,
-  C-flags, LD-flags and LIBS for the ‘Java’ plugin by hand, using the
-  following environment variables:
-
-    - JAVA_CPPFLAGS
-    - JAVA_CFLAGS
-    - JAVA_LDFLAGS
-    - JAVA_LIBS
-
-  For example (shortened for demonstration purposes):
-
-    ./configure JAVA_CPPFLAGS="-I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
-
-  Adding "-ljvm" to JAVA_LIBS is done automatically, you don't have to
-  do that.
-
 Generating the configure script
 -------------------------------
 
@@ -982,6 +978,7 @@ To generate the `configure` script, you'll need the following dependencies:
 
 The `build.sh' script takes no arguments.
 
+
 Crosscompiling
 --------------
 
@@ -1016,8 +1013,12 @@ Crosscompiling
 Contact
 -------
 
-  For questions, bug reports, development information and basically all other
-  concerns please send an email to collectd's mailing list at
+  Please use GitHub to report bugs and submit pull requests:
+  <https://github.com/collectd/collectd/>.
+  See CONTRIBUTING.md for details.
+
+  For questions, development information and basically all other concerns please
+  send an email to collectd's mailing list at
   <list at collectd.org>.
 
   For live discussion and more personal contact visit us in IRC, we're in
@@ -1031,5 +1032,3 @@ Author
   Sebastian tokkee Harl <sh at tokkee.org>,
   and many contributors (see `AUTHORS').
 
-  Please use GitHub reporting bugs and submitting pull requests.
-  See CONTRIBUTING.md for details.
diff --git a/TODO b/TODO
deleted file mode 100644 (file)
index 009eb7f..0000000
--- a/TODO
+++ /dev/null
@@ -1,21 +0,0 @@
-* Finalize the onewire plugin.
-* Custom notification messages?
-* Implement moving-average calculation for the threshold stuff.
-
-src/battery.c: commend not working code.
-
-Wishlist:
-* Port nfs module to solaris
-* Port tape module to Linux
-* Port the apple_sensors plugin to Linux/PPC.
-* Maybe look into porting the serial module
-* Build Darwin package
-* Maybe let the network plugin configure whether or not notifications should be
-  sent/received.
-* Maybe find a way for processes connected to the unixsock plugin to receive
-  notifications, too.
-
-http://developer.apple.com/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_IOKitLib_API/chapter_5_section_1.html
-http://developer.apple.com/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/index.html#//apple_ref/doc/uid/TP0000011
-http://www.gauchosoft.com/Software/X%20Resource%20Graph/
-http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification/
index c1adf4426212f3c6da5800853be49611a899730c..7e89e45f5d05c60c4de44275757dbe9884c52332 100644 (file)
@@ -172,7 +172,6 @@ sub plugin_call_all {
        my $type = shift;
 
        my %plugins;
-       my $interval;
 
        our $cb_name = undef;
 
@@ -181,13 +180,13 @@ sub plugin_call_all {
        }
 
        if (TYPE_LOG != $type) {
-               DEBUG ("Collectd::plugin_call: type = \"$type\" ("
+               DEBUG ("Collectd::plugin_call_all: type = \"$type\" ("
                        . $types{$type} . "), args=\""
                        . join(', ', map { defined($_) ? $_ : '<undef>' } @_) . "\"");
        }
 
        if (! defined $plugins[$type]) {
-               ERROR ("Collectd::plugin_call: unknown type \"$type\"");
+               ERROR ("Collectd::plugin_call_all: unknown type \"$type\"");
                return;
        }
 
@@ -196,21 +195,9 @@ sub plugin_call_all {
                %plugins = %{$plugins[$type]};
        }
 
-       $interval = plugin_get_interval ();
-
        foreach my $plugin (keys %plugins) {
-               my $p = $plugins{$plugin};
-
-               my $status = 0;
-
-               if ($p->{'wait_left'} > 0) {
-                       $p->{'wait_left'} -= $interval;
-               }
-
-               next if ($p->{'wait_left'} > 0);
-
-               $cb_name = $p->{'cb_name'};
-               $status = call_by_name (@_);
+               $cb_name = $plugins{$plugin};
+               my $status = call_by_name (@_);
 
                if (! $status) {
                        my $err = undef;
@@ -230,23 +217,7 @@ sub plugin_call_all {
                }
 
                if ($status) {
-                       $p->{'wait_left'} = 0;
-                       $p->{'wait_time'} = $interval;
-               }
-               elsif (TYPE_READ == $type) {
-                       if ($p->{'wait_time'} < $interval) {
-                               $p->{'wait_time'} = $interval;
-                       }
-
-                       $p->{'wait_left'} = $p->{'wait_time'};
-                       $p->{'wait_time'} *= 2;
-
-                       if ($p->{'wait_time'} > 86400) {
-                               $p->{'wait_time'} = 86400;
-                       }
-
-                       WARNING ("${plugin}->read() failed with status $status. "
-                               . "Will suspend it for $p->{'wait_left'} seconds.");
+                       #NOOP
                }
                elsif (TYPE_INIT == $type) {
                        ERROR ("${plugin}->init() failed with status $status. "
@@ -309,21 +280,29 @@ sub plugin_register {
        }
        elsif ((TYPE_DATASET != $type) && (! ref $data)) {
                my $pkg = scalar caller;
-
-               my %p : shared;
-
                if ($data !~ m/^$pkg\:\:/) {
                        $data = $pkg . "::" . $data;
                }
-
-               %p = (
-                       wait_time => plugin_get_interval (),
-                       wait_left => 0,
-                       cb_name   => $data,
-               );
-
+               if (TYPE_READ == $type) {
+                       return plugin_register_read($name, $data);
+               }
+               if (TYPE_WRITE == $type) {
+                       return plugin_register_write($name, $data);
+               }
+               if (TYPE_LOG == $type) {
+                       return plugin_register_log($name, $data);
+               }
+               if (TYPE_NOTIF == $type) {
+                       return plugin_register_notification($name, $data);
+               }
+               if (TYPE_FLUSH == $type) {
+                       #For collectd-5.6 only
+                       lock %{$plugins[$type]};
+                       $plugins[$type]->{$name} = $data;
+                       return plugin_register_flush($name, $data);
+               }
                lock %{$plugins[$type]};
-               $plugins[$type]->{$name} = \%p;
+               $plugins[$type]->{$name} = $data;
        }
        else {
                ERROR ("Collectd::plugin_register: Invalid data.");
@@ -351,6 +330,21 @@ sub plugin_unregister {
                lock %cf_callbacks;
                delete $cf_callbacks{$name};
        }
+       elsif (TYPE_READ == $type) {
+               return plugin_unregister_read ($name);
+       }
+       elsif (TYPE_WRITE == $type) {
+               return plugin_unregister_write($name);
+       }
+       elsif (TYPE_LOG == $type) {
+               return plugin_unregister_log ($name);
+       }
+       elsif (TYPE_NOTIF == $type) {
+               return plugin_unregister_notification($name);
+       }
+       elsif (TYPE_FLUSH == $type) {
+               return plugin_unregister_flush($name);
+       }
        elsif (defined $plugins[$type]) {
                lock %{$plugins[$type]};
                delete $plugins[$type]->{$name};
index 9a6da11dc7ce9c6c8772dfceb4f7c360c889c079..07f93922034ac0ab9cc768ccf7ea92acf59a1dc7 100644 (file)
@@ -2531,6 +2531,81 @@ then
 fi
 # }}}
 
+# --with-libdpdk {{{
+AC_ARG_WITH(libdpdk, [AS_HELP_STRING([--with-libdpdk@<:@=PREFIX@:>@], [Path to the DPDK build directory.])],
+[
+       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       then
+               RTE_BUILD="$withval"
+               with_libdpdk="yes"
+       else
+               RTE_BUILD="/usr"
+               with_libdpdk="$withval"
+       fi
+       DPDK_INCLUDE="$RTE_BUILD/include"
+       DPDK_LIB_DIR="$RTE_BUILD/lib"
+       FOUND_DPDK=yes
+], [with_libdpdk="no"])
+
+if test "x$with_libdpdk" = "xyes"
+then
+       LOCAL_DPDK_INSTALL="no"
+       AC_CHECK_HEADER([$DPDK_INCLUDE/rte_config.h], [LOCAL_DPDK_INSTALL=yes],
+               [AC_CHECK_HEADER([$DPDK_INCLUDE/dpdk/rte_config.h],
+               [],
+               [FOUND_DPDK=no], [])], [])
+
+       if test "x$LOCAL_DPDK_INSTALL" = "xno"
+       then
+               DPDK_INCLUDE=$DPDK_INCLUDE/dpdk
+       fi
+
+       if test "x$FOUND_DPDK" = "xno"
+       then
+               AC_MSG_ERROR([libdpdk error: rte_config.h not found])
+       fi
+fi
+
+if test "x$with_libdpdk" = "xyes"
+then
+       SAVE_LDFLAGS="$LDFLAGS"
+
+       if test "x$LOCAL_DPDK_INSTALL" != "xyes"
+       then
+               LDFLAGS="$LDFLAGS -L$DPDK_LIB_DIR"
+        fi
+
+       AC_CHECK_LIB(dpdk, rte_eal_init,
+                     [BUILD_WITH_DPDK_LIBS="-Wl,-ldpdk"],
+                     [FOUND_DPDK=no])
+
+       LDFLAGS="$SAVE_LDFLAGS"
+       if test "x$FOUND_DPDK" = "xno"
+       then
+               AC_MSG_ERROR([libdpdk error: cannot link with dpdk in $DPDK_LIB_DIR])
+       fi
+fi
+
+#
+# Note: An issue on Ubuntu 14.04 necessitates the use of -Wl,--no-as-needed:
+# If you try compile with the older linker, the dpdk symbols will be undefined.
+# This workaround should be removed when no longer necessary.
+#
+if test "x$with_libdpdk" = "xyes"
+then
+       BUILD_WITH_DPDK_CFLAGS+="-I$DPDK_INCLUDE"
+       if test "x$LOCAL_DPDK_INSTALL" != "xyes"
+       then
+               BUILD_WITH_DPDK_LDFLAGS="-Wl,--no-as-needed"
+       else
+               BUILD_WITH_DPDK_LDFLAGS="-L$DPDK_LIB_DIR -Wl,--no-as-needed"
+        fi
+       AC_SUBST(BUILD_WITH_DPDK_CFLAGS)
+       AC_SUBST(BUILD_WITH_DPDK_LDFLAGS)
+       AC_SUBST(BUILD_WITH_DPDK_LIBS)
+fi
+# }}}
+
 # --with-java {{{
 with_java_home="$JAVA_HOME"
 if test "x$with_java_home" = "x"
@@ -4023,6 +4098,55 @@ fi
 AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes")
 # }}}
 
+# --with-libpqos {{{
+with_libpqos_cppflags=""
+with_libpqos_ldflags=""
+AC_ARG_WITH(libpqos, [AS_HELP_STRING([--with-libpqos@<:@=PREFIX@:>@], [Path to libpqos.])],
+[
+       if test "x$withval" != "xno" && test "x$withval" != "xyes"
+       then
+               with_libpqos_cppflags="-I$withval/include"
+               with_libpqos_ldflags="-L$withval/lib"
+               with_libpqos="yes"
+       else
+               with_libpqos="$withval"
+       fi
+],
+[
+       with_libpqos="yes"
+])
+if test "x$with_libpqos" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_libpqos_cppflags"
+
+       AC_CHECK_HEADERS(pqos.h, [with_libpqos="yes"], [with_libpqos="no (pqos.h not found)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libpqos" = "xyes"
+then
+       SAVE_CPPFLAGS="$CPPFLAGS"
+       SAVE_LDFLAGS="$LDFLAGS"
+       CPPFLAGS="$CPPFLAGS $with_libpqos_cppflags"
+       LDFLAGS="$LDFLAGS $with_libpqos_ldflags"
+
+       AC_CHECK_LIB(pqos, pqos_init, [with_libpqos="yes"], [with_libpqos="no (Can't find libpqos)"])
+
+       CPPFLAGS="$SAVE_CPPFLAGS"
+       LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_libpqos" = "xyes"
+then
+       BUILD_WITH_LIBPQOS_CPPFLAGS="$with_libpqos_cppflags"
+       BUILD_WITH_LIBPQOS_LDFLAGS="$with_libpqos_ldflags"
+       BUILD_WITH_LIBPQOS_LIBS="-lpqos"
+       AC_SUBST(BUILD_WITH_LIBPQOS_CPPFLAGS)
+       AC_SUBST(BUILD_WITH_LIBPQOS_LDFLAGS)
+       AC_SUBST(BUILD_WITH_LIBPQOS_LIBS)
+fi
+# }}}
+
 # --with-libprotobuf {{{
 with_libprotobuf_cppflags=""
 with_libprotobuf_ldflags=""
@@ -5703,12 +5827,15 @@ plugin_curl_xml="no"
 plugin_df="no"
 plugin_disk="no"
 plugin_drbd="no"
+plugin_dpdk="no"
 plugin_entropy="no"
 plugin_ethstat="no"
 plugin_fhcount="no"
 plugin_fscache="no"
 plugin_gps="no"
 plugin_grpc="no"
+plugin_hugepages="no"
+plugin_intel_rdt="no"
 plugin_interface="no"
 plugin_ipmi="no"
 plugin_ipvs="no"
@@ -5757,6 +5884,7 @@ then
        plugin_entropy="yes"
        plugin_fhcount="yes"
        plugin_fscache="yes"
+       plugin_hugepages="yes"
        plugin_interface="yes"
        plugin_ipc="yes"
        plugin_irq="yes"
@@ -6151,6 +6279,7 @@ AC_PLUGIN([dbi],                 [$with_libdbi],            [General database st
 AC_PLUGIN([df],                  [$plugin_df],              [Filesystem usage statistics])
 AC_PLUGIN([disk],                [$plugin_disk],            [Disk usage statistics])
 AC_PLUGIN([dns],                 [$with_libpcap],           [DNS traffic analysis])
+AC_PLUGIN([dpdkstat],            [$with_libdpdk],           [Stats & Status from DPDK])
 AC_PLUGIN([drbd],                [$plugin_drbd],            [DRBD statistics])
 AC_PLUGIN([email],               [yes],                     [EMail statistics])
 AC_PLUGIN([entropy],             [$plugin_entropy],         [Entropy statistics])
@@ -6163,6 +6292,8 @@ AC_PLUGIN([gmond],               [$with_libganglia],        [Ganglia plugin])
 AC_PLUGIN([gps],                 [$plugin_gps],             [GPS plugin])
 AC_PLUGIN([grpc],                [$plugin_grpc],            [gRPC plugin])
 AC_PLUGIN([hddtemp],             [yes],                     [Query hddtempd])
+AC_PLUGIN([hugepages],           [$plugin_hugepages],       [Hugepages statistics])
+AC_PLUGIN([intel_rdt],           [$with_libpqos],           [Intel RDT monitor plugin])
 AC_PLUGIN([interface],           [$plugin_interface],       [Interface traffic statistics])
 AC_PLUGIN([ipc],                 [$plugin_ipc],             [IPC statistics])
 AC_PLUGIN([ipmi],                [$plugin_ipmi],            [IPMI sensor statistics])
@@ -6490,6 +6621,7 @@ AC_MSG_RESULT([    libaquaero5 . . . . . $with_libaquaero5])
 AC_MSG_RESULT([    libatasmart . . . . . $with_libatasmart])
 AC_MSG_RESULT([    libcurl . . . . . . . $with_libcurl])
 AC_MSG_RESULT([    libdbi  . . . . . . . $with_libdbi])
+AC_MSG_RESULT([    libdpdk . . . . . . . $with_libdpdk])
 AC_MSG_RESULT([    libesmtp  . . . . . . $with_libesmtp])
 AC_MSG_RESULT([    libganglia  . . . . . $with_libganglia])
 AC_MSG_RESULT([    libgcrypt . . . . . . $with_libgcrypt])
@@ -6523,6 +6655,7 @@ AC_MSG_RESULT([    libpcap . . . . . . . $with_libpcap])
 AC_MSG_RESULT([    libperfstat . . . . . $with_perfstat])
 AC_MSG_RESULT([    libperl . . . . . . . $with_libperl])
 AC_MSG_RESULT([    libpq . . . . . . . . $with_libpq])
+AC_MSG_RESULT([    libpqos . . . . . . . $with_libpqos])
 AC_MSG_RESULT([    libprotobuf . . . . . $with_libprotobuf])
 AC_MSG_RESULT([    libprotobuf-c . . . . $with_libprotobuf_c])
 AC_MSG_RESULT([    libpython . . . . . . $with_libpython])
@@ -6581,6 +6714,7 @@ AC_MSG_RESULT([    dbi . . . . . . . . . $enable_dbi])
 AC_MSG_RESULT([    df  . . . . . . . . . $enable_df])
 AC_MSG_RESULT([    disk  . . . . . . . . $enable_disk])
 AC_MSG_RESULT([    dns . . . . . . . . . $enable_dns])
+AC_MSG_RESULT([    dpdkstat . . . . . . .$enable_dpdkstat])
 AC_MSG_RESULT([    drbd  . . . . . . . . $enable_drbd])
 AC_MSG_RESULT([    email . . . . . . . . $enable_email])
 AC_MSG_RESULT([    entropy . . . . . . . $enable_entropy])
@@ -6593,6 +6727,8 @@ AC_MSG_RESULT([    gmond . . . . . . . . $enable_gmond])
 AC_MSG_RESULT([    gps . . . . . . . . . $enable_gps])
 AC_MSG_RESULT([    grpc  . . . . . . . . $enable_grpc])
 AC_MSG_RESULT([    hddtemp . . . . . . . $enable_hddtemp])
+AC_MSG_RESULT([    hugepages . . . . . . $enable_hugepages])
+AC_MSG_RESULT([    intel_rdt. . . . .  . $enable_intel_rdt])
 AC_MSG_RESULT([    interface . . . . . . $enable_interface])
 AC_MSG_RESULT([    ipc . . . . . . . . . $enable_ipc])
 AC_MSG_RESULT([    ipmi  . . . . . . . . $enable_ipmi])
index 1edcfc6152b32baac895ba795f41a51553a373ec..b53cf953fcf201f7fb21c98bf830afda70e8908b 100644 (file)
@@ -152,8 +152,8 @@ sub check_end {
                #try at least $self->{main}->{conf}->{collectd_retries} to get a
                #connection
                for (my $i = 0; $i < $self->{main}->{conf}->{collectd_retries} ; ++$i) {
-                       last if $sock = new IO::Socket::UNIX
-                               ($self->{main}->{conf}->{collectd_socket});
+                       my ($socket_path) = $self->{main}->{conf}->{collectd_socket} =~ /(.*)/; # Untaint path, which can contain any characters.
+                       last if $sock = new IO::Socket::UNIX $socket_path;
                        #sleep a random value between 0 and 50 microsecs to try for a new
                        #thread
                        usleep(int(rand(50))); 
index ab3ec2fd383df59a5f4c6624ee1d79a554c09fc5..adeae8c383801a088479340f727d83737967b5d9 100644 (file)
@@ -85,21 +85,22 @@ static int my_init (void)
 } /* static int my_init (void) */
 
 /*
- * This function is called in regular intervalls to collect the data.
+ * This is a utility function used by the read callback to populate a
+ * value_list_t and pass it to plugin_dispatch_values.
  */
-static int my_read (void)
+static int my_submit (gauge_t value)
 {
-       value_t values[1]; /* the size of this list should equal the number of
-                                                 data sources */
        value_list_t vl = VALUE_LIST_INIT;
 
-       /* do the magic to read the data */
-       values[0].gauge = random ();
-
-       vl.values     = values;
+       /* Convert the gauge_t to a value_t and add it to the value_list_t. */
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       vl.time       = time (NULL);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+
+       /* Only set vl.time yourself if you update multiple metrics (i.e. you
+        * have multiple calls to plugin_dispatch_values()) and they need to all
+        * have the same timestamp. */
+       /* vl.time = cdtime(); */
+
        sstrncpy (vl.plugin, "myplugin", sizeof (vl.plugin));
 
        /* it is strongly recommended to use a type defined in the types.db file
@@ -110,7 +111,19 @@ static int my_read (void)
 
        /* dispatch the values to collectd which passes them on to all registered
         * write functions */
-       plugin_dispatch_values (&vl);
+       return plugin_dispatch_values (&vl);
+}
+
+/*
+ * This function is called in regular intervalls to collect the data.
+ */
+static int my_read (void)
+{
+       /* do the magic to read the data */
+       gauge_t value = random ();
+
+       if (my_submit (value) != 0)
+               WARNING ("myplugin plugin: Dispatching a random value failed.");
 
        /* A return value != 0 indicates an error and the plugin will be skipped
         * for an increasing amount of time. */
index 4c136d65b162a8a998e0098839d9fc57cc85e2af..eaf6f31adab19f4ec5f9c7d07d12cba0cc002ac8 100644 (file)
@@ -73,6 +73,7 @@
 %define with_gmond 0%{!?_without_gmond:1}
 %define with_gps 0%{!?_without_gps:1}
 %define with_hddtemp 0%{!?_without_hddtemp:1}
+%define with_hugepages 0%{!?_without_hugepages:1}
 %define with_interface 0%{!?_without_interface:1}
 %define with_ipc 0%{!?_without_ipc:1}
 %define with_ipmi 0%{!?_without_ipmi:1}
 %define with_barometer 0%{!?_without_barometer:0}
 # plugin grpc disabled, requires protobuf-compiler >= 3.0
 %define with_grpc 0%{!?_without_grpc:0}
+# plugin dpdkstat disabled, requires libdpdk
+%define with_dpdkstat 0%{!?_without_dpdkstat:0}
 # plugin lpar disabled, requires AIX
 %define with_lpar 0%{!?_without_lpar:0}
+# plugin intel_rdt disabled, requires intel-cmt-cat
+%define with_intel_rdt 0%{!?_without_intel_rdt:0}
 # plugin mic disabled, requires Mic
 %define with_mic 0%{!?_without_mic:0}
 # plugin netapp disabled, requires libnetapp
 
 Summary:       Statistics collection and monitoring daemon
 Name:          collectd
-Version:       5.6.1
+Version:       5.7.0
 Release:       1%{?dist}
 URL:           https://collectd.org
 Source:                https://collectd.org/files/%{name}-%{version}.tar.bz2
@@ -451,6 +456,17 @@ The HDDTemp plugin collects the temperature of hard disks. The temperatures are
 provided via SMART and queried by the external hddtemp daemon.
 %endif
 
+%if %{with_intel_rdt}
+%package intel_rdt
+Summary:       Intel RDT plugin for collectd
+Group:         System Environment/Daemons
+Requires:      %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: intel-cmt-cat
+%description intel_rdt
+The intel_rdt plugin collects information provided by monitoring features of
+Intel Resource Director Technology (Intel(R) RDT).
+%endif
+
 %if %{with_ipmi}
 %package ipmi
 Summary:       IPMI plugin for collectd
@@ -1068,6 +1084,12 @@ Collectd utilities
 %define _with_drbd --disable-drbd
 %endif
 
+%if %{with_dpdkstat}
+%define _with_dpdkstat --enable-dpdkstat
+%else
+%define _with_dpdkstat --disable-dpdkstat
+%endif
+
 %if %{with_email}
 %define _with_email --enable-email
 %else
@@ -1134,6 +1156,18 @@ Collectd utilities
 %define _with_hddtemp --disable-hddtemp
 %endif
 
+%if %{with_hugepages}
+%define _with_hugepages --enable-hugepages
+%else
+%define _with_hugepages --disable-hugepages
+%endif
+
+%if %{with_intel_rdt}
+%define _with_intel_rdt --enable-intel_rdt
+%else
+%define _with_intel_rdt --disable-intel_rdt
+%endif
+
 %if %{with_interface}
 %define _with_interface --enable-interface
 %else
@@ -1751,6 +1785,7 @@ Collectd utilities
        %{?_with_disk} \
        %{?_with_dns} \
        %{?_with_drbd} \
+       %{?_with_dpdkstat} \
        %{?_with_email} \
        %{?_with_entropy} \
        %{?_with_ethstat} \
@@ -1762,6 +1797,8 @@ Collectd utilities
        %{?_with_gps} \
        %{?_with_grpc} \
        %{?_with_hddtemp} \
+       %{?_with_hugepages} \
+       %{?_with_intel_rdt} \
        %{?_with_interface} \
        %{?_with_ipc} \
        %{?_with_ipmi} \
@@ -2027,6 +2064,9 @@ fi
 %if %{with_drbd}
 %{_libdir}/%{name}/drbd.so
 %endif
+%if %{with_dpdkstat}
+%{_libdir}/%{name}/dpdkstat.so
+%endif
 %if %{with_ethstat}
 %{_libdir}/%{name}/ethstat.so
 %endif
@@ -2045,6 +2085,9 @@ fi
 %if %{with_fscache}
 %{_libdir}/%{name}/fscache.so
 %endif
+%if %{with_hugepages}
+%{_libdir}/%{name}/hugepages.so
+%endif
 %if %{with_interface}
 %{_libdir}/%{name}/interface.so
 %endif
@@ -2304,6 +2347,11 @@ fi
 %{_libdir}/%{name}/hddtemp.so
 %endif
 
+%if %{with_intel_rdt}
+%files intel_rdt
+%{_libdir}/%{name}/intel_rdt.so
+%endif
+
 %if %{with_ipmi}
 %files ipmi
 %{_libdir}/%{name}/ipmi.so
@@ -2512,6 +2560,11 @@ fi
 %doc contrib/
 
 %changelog
+* Mon Oct 10 2016 Marc Fournier <marc.fournier@camptocamp.com> - 5.7.0-1
+- New PRE-RELEASE version
+- New plugins enabled by default: hugepages
+- New plugins disabled by default: dpdkstat, intel_rdt
+
 * Mon Oct 10 2016 Victor Demonchy <v.demonchy@criteo.com> - 5.6.1-1
 - New upstream version
 
diff --git a/docs/BUILD.dpdkstat.md b/docs/BUILD.dpdkstat.md
new file mode 100644 (file)
index 0000000..b502edd
--- /dev/null
@@ -0,0 +1,230 @@
+# The dpdkstat plugin
+
+**Data Plane Development Kit** (DPDK) is a set of drivers and libraries for fast
+packet processing.
+
+## Summary
+
+The *dpdkstat plugin* has the following requirements:
+
+ * DPDK 16.04 or later
+ * GCC 4.9 or later
+
+You can also build with GCC 4.8 (e.g. Ubuntu 14.04) if you specify the SSSE3
+instruction set manually:
+
+    make -j CFLAGS+='-mssse3'
+
+## Building DPDK
+
+ *  Setup the build environment:
+
+    Ensure that you have GCC 4.9 or later. Ubuntu 14.04, for example, has GCC
+    4.8 by default and requires an upgrade:
+
+        add-apt-repository ppa:ubuntu-toolchain-r/test
+        apt-get update
+        apt-get install gcc-4.9
+
+    If you know that the platform that you wish to run collectd on supports the
+    SSSE3 instruction set, GCC 4.8 also works if you enable SSSE3 manually:
+
+        make -j CFLAGS+='-mssse3'
+
+ *  Clone DPDK:
+
+        git clone git://dpdk.org/dpdk
+
+ *  Checkout the [DPDK system
+    requirements](http://dpdk.org/doc/guides/linux_gsg/sys_reqs.html) and make
+    sure you have the required tools and hugepage setup as specified there.
+
+    **Note:** It's recommended to use the 1GB hugepage setup for best
+    performance, please follow the instruction for "Reserving Hugepages for DPDK
+    Use" in the link above.
+
+    However if you plan on configuring 2MB hugepages on the fly please ensure to
+    add appropriate commands to reserve hugepages in a system startup script if
+    collectd is booted at system startup time. These commands include:
+
+        mkdir -p /mnt/huge
+        mount -t hugetlbfs nodev /mnt/huge
+        echo 64 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
+
+ *  To configure the DPDK build for the combined shared library modify
+    `config/common_base` in your DPDK as follows
+
+        #
+        # Compile to share library
+        #
+        -CONFIG_RTE_BUILD_SHARED_LIB=n
+        +CONFIG_RTE_BUILD_SHARED_LIB=y
+
+ *  Prepare the configuration for the appropriate target as specified at:
+    http://dpdk.org/doc/guides/linux_gsg/build_dpdk.html.
+
+    For example:
+
+        make config T=x86_64-native-linuxapp-gcc
+
+ *  Build the target:
+
+        make
+
+ *  Install DPDK to `/usr`
+
+        sudo make install prefix=/usr
+
+    **Note 1:** You must run make install as the configuration of collectd with
+    DPDK expects DPDK to be installed somewhere.
+
+    **Note 2:** If you don't specify a prefix then DPDK will be installed in
+    `/usr/local/`.
+
+    **Note 3:** If you are not root then use sudo to make install DPDK to the
+    appropriate location.
+
+ *  Check that the DPDK library has been installed in `/usr/lib` or `/lib`:
+
+        ls /usr/lib | grep dpdk
+
+ *  Bind the interfaces to use with dpdkstat to DPDK:
+
+    DPDK devices can be setup with either the VFIO (for DPDK 1.7+) or UIO
+    modules.
+
+    **Note:** UIO requires inserting an out of tree driver `igb_uio.ko` that is
+    available in DPDK.
+
+    **UIO Setup:**
+
+     *  Insert `uio.ko`:
+
+            sudo modprobe uio
+
+     *  Insert `igb_uio.ko`:
+
+            sudo insmod $DPDK_BUILD/kmod/igb_uio.ko
+
+     *  Bind network device to `igb_uio`:
+
+            sudo $DPDK_DIR/tools/dpdk_nic_bind.py --bind=igb_uio eth1
+
+    **VFIO Setup:**
+
+     *  VFIO needs to be supported in the kernel and the BIOS. More information
+        can be found at: http://dpdk.org/doc/guides/linux_gsg/build_dpdk.html.
+     *  Insert the `vfio-pci.ko` module:
+
+            modprobe vfio-pci
+
+     *  Set the correct permissions for the VFIO device:
+
+            sudo /usr/bin/chmod a+x /dev/vfio
+            sudo /usr/bin/chmod 0666 /dev/vfio/*
+
+     *  Bind the network device to `vfio-pci`:
+
+            sudo $DPDK_DIR/tools/dpdk_nic_bind.py --bind=vfio-pci eth1
+
+        **Note:** Please ensure to add appropriate commands to bind the network
+        interfaces to DPDK in a system startup script if collectd is booted at
+        system startup time.
+
+     *  Run `ldconfig` to update the shared library cache.
+
+### Static library
+
+To build static DPDK library for use with collectd:
+
+ *  To configure DPDK to build the combined static library `libdpdk.a` ensure
+    that `CONFIG_RTE_BUILD_SHARED_LIB` is set to “n” in `config/common_base` in
+    your DPDK as follows:
+
+        #
+        # Compile to share library
+        #
+        CONFIG_RTE_BUILD_SHARED_LIB=n
+
+ *  Prepare the configuration for the appropriate target as specified at:
+    http://dpdk.org/doc/guides/linux_gsg/build_dpdk.html.
+
+    For example:
+
+        make config T=x86_64-native-linuxapp-gcc
+
+ *  Build the target using `-fPIC`:
+
+        make EXTRA_CFLAGS=-fPIC -j
+
+ *  Install DPDK to `/usr`:
+
+        sudo make install prefix=/usr
+
+## Build collectd with DPDK
+
+**Note:** DPDK 16.04 is the minimum version and currently supported version of
+DPDK required for the dpdkstat plugin. This is to allow the plugin to take
+advantage of functions added to detect if the DPDK primary process is alive.
+
+
+**Note:** The *Address-Space Layout Randomization* (ASLR) security feature in
+Linux should be disabled, in order for the same hugepage memory mappings to be
+present in all DPDK multi-process applications. Note that this has security
+implications.
+
+ *  To disable ASLR:
+
+        echo 0 > /proc/sys/kernel/randomize_va_space
+
+ *  To fully enable ASLR:
+
+        echo 2 > /proc/sys/kernel/randomize_va_space
+
+See also: http://dpdk.org/doc/guides/prog_guide/multi_proc_support.html
+
+ *  Generate the build script as specified below. (i.e. run `build.sh`).
+ *  Configure collectd with the DPDK shared library:
+
+        ./configure --with-libdpdk=/usr
+
+### Build with the static DPDK library
+
+To configure collectd with the DPDK static library:
+
+ *  Run *configure* with the following CFLAGS:
+
+        ./configure --with-libdpdk=/usr CFLAGS=" -lpthread -Wl,--whole-archive -Wl,-ldpdk -Wl,-lm -Wl,-lrt -Wl,-lpcap -Wl,-ldl -Wl,--no-whole-archive"
+
+ *  Make sure that dpdk and dpdkstat are enabled in the *configure* output.
+
+    Expected output:
+
+        Libraries:
+        ...
+        libdpdk  . . . . . . . . yes
+        
+        Modules:
+        ...
+        dpdkstat . . . . . . .yes
+
+ *  Build collectd:
+
+        make -j && make -j install.
+
+    **Note:** As mentioned above, if you are building on Ubuntu 14.04 with
+    GCC <= 4.8.X, you need to use:
+
+        make -j CFLAGS+='-mssse3' && make -j install
+
+## Caveats
+
+ *  The same PCI device configuration should be passed to the primary process as
+    the secondary process uses the same port indexes as the primary.
+ *  A blacklist / whitelist of NICs isn't supported yet.
+
+## License
+
+The *dpdkstat plugin* is copyright (c) 2016 *Intel Corporation* and licensed
+under the *MIT license*. Full licensing terms can be found in the file
+`COPYING`.
diff --git a/docs/BUILD.java.md b/docs/BUILD.java.md
new file mode 100644 (file)
index 0000000..2f4c0c2
--- /dev/null
@@ -0,0 +1,50 @@
+# Building with Java
+
+This file gives some background and hints how the *java plugin* needs to be
+configured.
+
+## Dependencies
+
+The *java plugin* requires a version of Java with *Java Native Interface* (JNI)
+**1.2** or later.
+
+## Configure and flags
+
+To determine the location of the required files of a Java installation is not an
+easy task, because the locations vary with your kernel (Linux, SunOS, …) and
+with your architecture (x86, SPARC, …) and there is no `java-config` script we
+could use. Configuration of the JVM library is therefore a bit tricky.
+
+The easiest way to use the `--with-java="${JAVA_HOME}"` option, where
+`JAVA_HOME` is usually something like:
+
+    /usr/lib/jvm/java-1.5.0-sun-1.5.0.14
+
+The configure script will then use *find(1)* to look for the following files:
+
+ *  `jni.h`
+ *  `jni_md.h`
+ *  `libjvm.so`
+
+If found, appropriate CPP-flags and LD-flags are set and the following library
+checks succeed.
+
+If this doesn't work for you, you have the possibility to specify CPP-flags,
+C-flags, LD-flags and LIBS for the *java plugin* by hand, using the following
+environment variables:
+
+ *  `JAVA_CPPFLAGS`
+ *  `JAVA_CFLAGS`
+ *  `JAVA_LDFLAGS`
+ *  `JAVA_LIBS`
+
+For example (shortened for demonstration purposes):
+
+    ./configure JAVA_CPPFLAGS="-I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
+
+Adding `-ljvm` to JAVA_LIBS is done automatically, you don't have to do that.
+
+## License
+
+The *java plugin* is licensed under the *GNU General Public License, version 2*.
+Full licensing terms can be found in the file `COPYING`.
index 917c5deb679985dd90388176f7e9449569e3ef37..614d1bd00acf03106f50f732c8a244c69bca0055 100644 (file)
@@ -30,25 +30,25 @@ option go_package = "collectd.org/rpc/proto";
 import "types.proto";
 
 service Collectd {
-  // DispatchValues reads the value lists from the DispatchValuesRequest stream.
+  // PutValues reads the value lists from the PutValuesRequest stream.
   // The gRPC server embedded into collectd will inject them into the system
   // just like the network plugin.
-  rpc DispatchValues(stream DispatchValuesRequest)
-      returns (DispatchValuesResponse);
+  rpc PutValues(stream PutValuesRequest)
+      returns (PutValuesResponse);
 
   // QueryValues returns a stream of matching value lists from collectd's
   // internal cache.
   rpc QueryValues(QueryValuesRequest) returns (stream QueryValuesResponse);
 }
 
-// The arguments to DispatchValues.
-message DispatchValuesRequest {
+// The arguments to PutValues.
+message PutValuesRequest {
   // value_list is the metric to be sent to the server.
   collectd.types.ValueList value_list = 1;
 }
 
-// The response from DispatchValues.
-message DispatchValuesResponse {}
+// The response from PutValues.
+message PutValuesResponse {}
 
 // The arguments to QueryValues.
 message QueryValuesRequest {
index 37160c108013b7a1091988b72abad282c53db6e4..7254bd9c5916d90c7e577a38ff80d8a63debc777 100644 (file)
@@ -49,6 +49,21 @@ TESTS += test_utils_latency
 test_utils_latency_SOURCES = utils_latency_test.c testing.h
 test_utils_latency_LDADD = liblatency.la daemon/libplugin_mock.la -lm
 
+noinst_LTLIBRARIES += libcmds.la
+libcmds_la_SOURCES = utils_cmds.c utils_cmds.h \
+               utils_cmd_flush.c utils_cmd_flush.h \
+               utils_cmd_getval.c utils_cmd_getval.h \
+               utils_cmd_listval.c utils_cmd_listval.h \
+               utils_cmd_putval.c utils_cmd_putval.h \
+               utils_parse_option.c
+libcmds_la_LIBADD = daemon/libcommon.la daemon/libmetadata.la \
+               daemon/libplugin_mock.la -lm
+check_PROGRAMS += test_utils_cmds
+TESTS += test_utils_cmds
+test_utils_cmds_SOURCES = utils_cmds_test.c testing.h
+test_utils_cmds_LDADD = libcmds.la \
+               daemon/libplugin_mock.la daemon/libmetadata.la
+
 noinst_LTLIBRARIES += liblookup.la
 liblookup_la_SOURCES = utils_vl_lookup.c utils_vl_lookup.h
 liblookup_la_LIBADD = daemon/libavltree.la
@@ -154,8 +169,9 @@ endif
 if BUILD_PLUGIN_AMQP
 pkglib_LTLIBRARIES += amqp.la
 amqp_la_SOURCES = amqp.c \
+                 utils_cmds.c utils_cmds.h \
                  utils_cmd_putval.c utils_cmd_putval.h \
-                 utils_parse_option.c utils_parse_option.h \
+                 utils_parse_option.c utils_parse_option.h \
                  utils_format_graphite.c utils_format_graphite.h
 amqp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
 amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
@@ -213,7 +229,7 @@ endif
 
 if BUILD_PLUGIN_BATTERY
 pkglib_LTLIBRARIES += battery.la
-battery_la_SOURCES = battery.c
+battery_la_SOURCES = battery.c battery_statefs.c
 battery_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 if BUILD_WITH_LIBIOKIT
 battery_la_LDFLAGS += -framework IOKit
@@ -390,6 +406,14 @@ dns_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 dns_la_LIBADD = -lpcap
 endif
 
+if BUILD_PLUGIN_DPDKSTAT
+pkglib_LTLIBRARIES += dpdkstat.la
+dpdkstat_la_SOURCES = dpdkstat.c
+dpdkstat_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_DPDK_CFLAGS)
+dpdkstat_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_DPDK_LDFLAGS)
+dpdkstat_la_LIBADD = $(BUILD_WITH_DPDK_LIBS) 
+endif
+
 if BUILD_PLUGIN_DRBD
 pkglib_LTLIBRARIES += drbd.la
 drbd_la_SOURCES = drbd.c
@@ -411,6 +435,7 @@ endif
 if BUILD_PLUGIN_EXEC
 pkglib_LTLIBRARIES += exec.la
 exec_la_SOURCES = exec.c \
+                 utils_cmds.c utils_cmds.h \
                  utils_cmd_putnotif.c utils_cmd_putnotif.h \
                  utils_cmd_putval.c utils_cmd_putval.h \
                  utils_parse_option.h utils_parse_option.c
@@ -470,6 +495,12 @@ hddtemp_la_LIBADD += -lsocket
 endif
 endif
 
+if BUILD_PLUGIN_HUGEPAGES
+pkglib_LTLIBRARIES += hugepages.la
+hugepages_la_SOURCES = hugepages.c
+hugepages_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
 if BUILD_PLUGIN_INTERFACE
 pkglib_LTLIBRARIES += interface.la
 interface_la_SOURCES = interface.c
@@ -948,6 +979,14 @@ protocols_la_SOURCES = protocols.c
 protocols_la_LDFLAGS = $(PLUGIN_LDFLAGS)
 endif
 
+if BUILD_PLUGIN_INTEL_RDT
+pkglib_LTLIBRARIES += intel_rdt.la
+intel_rdt_la_SOURCES = intel_rdt.c
+intel_rdt_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPQOS_LDFLAGS)
+intel_rdt_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBPQOS_CPPFLAGS)
+intel_rdt_la_LIBADD = $(BUILD_WITH_LIBPQOS_LIBS)
+endif
+
 if BUILD_PLUGIN_REDIS
 pkglib_LTLIBRARIES += redis.la
 redis_la_SOURCES = redis.c
@@ -1167,6 +1206,7 @@ endif
 if BUILD_PLUGIN_UNIXSOCK
 pkglib_LTLIBRARIES += unixsock.la
 unixsock_la_SOURCES = unixsock.c \
+                     utils_cmds.c utils_cmds.h \
                      utils_cmd_flush.h utils_cmd_flush.c \
                      utils_cmd_getval.h utils_cmd_getval.c \
                      utils_cmd_getthreshold.h utils_cmd_getthreshold.c \
@@ -1266,6 +1306,7 @@ if BUILD_PLUGIN_WRITE_KAFKA
 pkglib_LTLIBRARIES += write_kafka.la
 write_kafka_la_SOURCES = write_kafka.c \
                         utils_format_graphite.c utils_format_graphite.h \
+                        utils_cmds.c utils_cmds.h \
                         utils_cmd_putval.c utils_cmd_putval.h \
                         utils_crc32.c utils_crc32.h
 write_kafka_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRDKAFKA_CPPFLAGS)
@@ -1278,6 +1319,7 @@ pkglib_LTLIBRARIES += write_log.la
 write_log_la_SOURCES = write_log.c \
                         utils_format_graphite.c utils_format_graphite.h
 write_log_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+write_log_la_LIBADD = libformat_json.la
 endif
 
 if BUILD_PLUGIN_WRITE_MONGODB
index 2744c89ecb8a9caff99bc543555dd72660a2719d..bb37b858fd846737bd48c204434b5257287d2f48 100644 (file)
@@ -38,7 +38,7 @@
 
 struct aggregation_s /* {{{ */
 {
-  identifier_t ident;
+  lookup_identifier_t ident;
   unsigned int group_by;
 
   unsigned int regex_fields;
@@ -62,7 +62,7 @@ typedef struct agg_instance_s agg_instance_t;
 struct agg_instance_s /* {{{ */
 {
   pthread_mutex_t lock;
-  identifier_t ident;
+  lookup_identifier_t ident;
 
   int ds_type;
 
index 89f051e81960668c957abfe72239c542ed4681d2..f9777a9b2a6f390c4ed4eec927f0e01465538f16 100644 (file)
@@ -599,9 +599,9 @@ static int camqp_read_body (camqp_config_t *conf, /* {{{ */
 
     if (strcasecmp ("text/collectd", content_type) == 0)
     {
-        status = handle_putval (stderr, body);
+        status = cmd_handle_putval (stderr, body);
         if (status != 0)
-            ERROR ("amqp plugin: handle_putval failed with status %i.",
+            ERROR ("amqp plugin: cmd_handle_putval failed with status %i.",
                     status);
         return (status);
     }
@@ -838,10 +838,10 @@ static int camqp_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
 
     if (conf->format == CAMQP_FORMAT_COMMAND)
     {
-        status = create_putval (buffer, sizeof (buffer), ds, vl);
+        status = cmd_create_putval (buffer, sizeof (buffer), ds, vl);
         if (status != 0)
         {
-            ERROR ("amqp plugin: create_putval failed with status %i.",
+            ERROR ("amqp plugin: cmd_create_putval failed with status %i.",
                     status);
             return (status);
         }
@@ -1070,11 +1070,13 @@ static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */
     if (publish)
     {
         char cbname[128];
-        user_data_t ud = { conf, camqp_config_free };
-
         ssnprintf (cbname, sizeof (cbname), "amqp/%s", conf->name);
 
-        status = plugin_register_write (cbname, camqp_write, &ud);
+        status = plugin_register_write (cbname, camqp_write,
+                &(user_data_t) {
+                    .data = conf,
+                    .free_func = camqp_config_free,
+                });
         if (status != 0)
         {
             camqp_config_free (conf);
index b57d08edc447c9005d32fded65b85d00d425b111..7ccdb60d56a91963d5ca99e08ca9346c6695ea23 100644 (file)
@@ -239,11 +239,6 @@ static int config_add (oconfig_item_t *ci)
 
        if (status == 0)
        {
-               user_data_t ud = {
-                       .data = st,
-                       .free_func = apache_free
-               };
-
                char callback_name[3*DATA_MAX_NAME_LEN];
 
                ssnprintf (callback_name, sizeof (callback_name),
@@ -255,7 +250,11 @@ static int config_add (oconfig_item_t *ci)
                                /* name      = */ callback_name,
                                /* callback  = */ apache_read_host,
                                /* interval  = */ 0,
-                               /* user_data = */ &ud);
+                               &(user_data_t) {
+                                       .data = st,
+                                       .free_func = apache_free,
+                               });
+
        }
 
        if (status != 0)
@@ -395,8 +394,8 @@ static void submit_value (const char *type, const char *type_instance,
        vl.values = &value;
        vl.values_len = 1;
 
-       sstrncpy (vl.host, (st->host != NULL) ? st->host : hostname_g,
-                       sizeof (vl.host));
+       if (st->host != NULL)
+               sstrncpy (vl.host, st->host, sizeof (vl.host));
 
        sstrncpy (vl.plugin, "apache", sizeof (vl.plugin));
        if (st->name != NULL)
@@ -412,19 +411,15 @@ static void submit_value (const char *type, const char *type_instance,
 } /* void submit_value */
 
 static void submit_derive (const char *type, const char *type_instance,
-               derive_t c, apache_t *st)
+               derive_t d, apache_t *st)
 {
-       value_t v;
-       v.derive = c;
-       submit_value (type, type_instance, v, st);
+       submit_value (type, type_instance, (value_t) { .derive = d }, st);
 } /* void submit_derive */
 
 static void submit_gauge (const char *type, const char *type_instance,
                gauge_t g, apache_t *st)
 {
-       value_t v;
-       v.gauge = g;
-       submit_value (type, type_instance, v, st);
+       submit_value (type, type_instance, (value_t) { .gauge = g }, st);
 } /* void submit_gauge */
 
 static void submit_scoreboard (char *buf, apache_t *st)
index af5f24c70f2f2d1e5544a7a1c62cd7f880b27ba4..937f2a0696052bb0c3ce16422e5a8bf42097e91c 100644 (file)
@@ -416,16 +416,11 @@ static int apcups_config (oconfig_item_t *ci)
 
 static void apc_submit_generic (const char *type, const char *type_inst, double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "apcups", sizeof (vl.plugin));
-       sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
index 48fbcb91e53117832fc26160df4f8ecd4fa96947..17c822ff3c91ca9f44a52188ac2d9ecb5faebd18 100644 (file)
@@ -83,19 +83,11 @@ static int as_init (void)
 static void as_submit (const char *type, const char *type_instance,
                double val)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       DEBUG ("type = %s; type_instance = %s; val = %f;",
-                       type, type_instance, val);
-
-       values[0].gauge = val;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = val };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "apple_sensors", sizeof (vl.plugin));
-       sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
index 81a4efd4337257865dd78d293d065572c3aa7b7e..8872409fcc118c691c4a0a85cdbdf0e14c00fb6b 100644 (file)
@@ -60,19 +60,15 @@ static void aquaero_submit (const char *type, const char *type_instance,
                double value)
 {
        const char *instance = conf_device?conf_device:"default";
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
        /* Don't report undefined values. */
        if (value == AQ5_FLOAT_UNDEF)
                return;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "aquaero", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
index 11bb97f0c6bce3b3abe457090053173d91a01737..b14be3c0d709528bf226b9980127b091c3c692b5 100644 (file)
@@ -126,14 +126,10 @@ static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 static int ascent_submit_gauge (const char *plugin_instance, /* {{{ */
     const char *type, const char *type_instance, gauge_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "ascent", sizeof (vl.plugin));
 
   if (plugin_instance != NULL)
index 998932daa826c308f95ce50fcb8c6958820ac527..53c55b844247b2e19d091fd270501fd5ec025e16 100644 (file)
@@ -1600,7 +1600,6 @@ static int MPL115_collectd_barometer_read (void)
 
     norm_pressure = abs_to_mean_sea_level_pressure(pressure);
 
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
     sstrncpy (vl.plugin_instance, "mpl115", sizeof (vl.plugin_instance));
 
@@ -1663,7 +1662,6 @@ static int MPL3115_collectd_barometer_read (void)
 
     norm_pressure = abs_to_mean_sea_level_pressure(pressure);
 
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
     sstrncpy (vl.plugin_instance, "mpl3115", sizeof (vl.plugin_instance));
 
@@ -1726,7 +1724,6 @@ static int BMP085_collectd_barometer_read (void)
 
     norm_pressure = abs_to_mean_sea_level_pressure(pressure);
 
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "barometer", sizeof (vl.plugin));
     sstrncpy (vl.plugin_instance, "bmp085", sizeof (vl.plugin_instance));
 
index a0843196a302c55c8647dd64b67ae2038d05fa00..a909b755fe324fa66dfc0cb6e903b5c120ff3166 100644 (file)
 # define SYSFS_FACTOR 0.000001
 #endif /* KERNEL_LINUX */
 
+int battery_read_statefs (void); /* defined in battery_statefs; used by StateFS backend */
+
 static _Bool report_percent = 0;
 static _Bool report_degraded = 0;
+static _Bool query_statefs = 0;
 
 static void battery_submit2 (char const *plugin_instance, /* {{{ */
                char const *type, char const *type_instance, gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "battery", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@ -359,6 +358,9 @@ static int battery_read (void) /* {{{ */
        gauge_t capacity_full = NAN; /* Total capacity */
        gauge_t capacity_design = NAN; /* Full design capacity */
 
+       if (query_statefs)
+               return battery_read_statefs ();
+
 #if HAVE_IOKIT_PS_IOPOWERSOURCES_H
        get_via_io_power_sources (&charge_rel, &current, &voltage);
 #endif
@@ -386,47 +388,17 @@ static int sysfs_file_to_buffer(char const *dir, /* {{{ */
                char const *basename,
                char *buffer, size_t buffer_size)
 {
-       int status;
-       FILE *fp;
        char filename[PATH_MAX];
+       int status;
 
        ssnprintf (filename, sizeof (filename), "%s/%s/%s",
                        dir, power_supply, basename);
 
-       /* No file isn't the end of the world -- not every system will be
-        * reporting the same set of statistics */
-       if (access (filename, R_OK) != 0)
-               return ENOENT;
-
-       fp = fopen (filename, "r");
-       if (fp == NULL)
-       {
-               status = errno;
-               if (status != ENOENT)
-               {
-                       char errbuf[1024];
-                       WARNING ("battery plugin: fopen (%s) failed: %s", filename,
-                                       sstrerror (status, errbuf, sizeof (errbuf)));
-               }
-               return status;
-       }
-
-       if (fgets (buffer, buffer_size, fp) == NULL)
-       {
-               status = errno;
-               if (status != ENODEV)
-               {
-                       char errbuf[1024];
-                       WARNING ("battery plugin: fgets (%s) failed: %s", filename,
-                                       sstrerror (status, errbuf, sizeof (errbuf)));
-               }
-               fclose (fp);
+       status = (int) read_file_contents (filename, buffer, buffer_size);
+       if (status < 0)
                return status;
-       }
 
        strstripnewline (buffer);
-
-       fclose (fp);
        return 0;
 } /* }}} int sysfs_file_to_buffer */
 
@@ -778,6 +750,9 @@ static int battery_read (void) /* {{{ */
 {
        int status;
 
+       if (query_statefs)
+               return battery_read_statefs ();
+
        DEBUG ("battery plugin: Trying sysfs ...");
        status = read_sysfs ();
        if (status == 0)
@@ -808,6 +783,8 @@ static int battery_config (oconfig_item_t *ci)
                        cf_util_get_boolean (child, &report_percent);
                else if (strcasecmp ("ReportDegraded", child->key) == 0)
                        cf_util_get_boolean (child, &report_degraded);
+               else if (strcasecmp ("QueryStateFS", child->key) == 0)
+                       cf_util_get_boolean (child, &query_statefs);
                else
                        WARNING ("battery plugin: Ignoring unknown "
                                        "configuration option \"%s\".",
diff --git a/src/battery_statefs.c b/src/battery_statefs.c
new file mode 100644 (file)
index 0000000..a0ff187
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * collectd - src/statefs_battery.c
+ * Copyright (C) 2016 rinigus
+ *
+ *
+The MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+ * Authors:
+ *   rinigus <http://github.com/rinigus>
+
+ Battery stats are collected from StateFS Battery namespace. Reported
+ units are as follows:
+
+ capacity %
+ charge %
+ current A
+ energy Wh
+ power W
+ temperature C
+ timefull and timelow seconds
+ voltage V
+
+ Provider at
+ https://git.merproject.org/mer-core/statefs-providers/blob/master/src/power_udev/provider_power_udev.cpp
+
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <stdio.h>
+
+#define STATEFS_ROOT "/run/state/namespaces/Battery/"
+
+static void battery_submit(const char *type, gauge_t value,
+                           const char *type_instance) {
+  value_list_t vl = VALUE_LIST_INIT;
+
+  vl.values = &(value_t) { .gauge = value };
+  vl.values_len = 1;
+  sstrncpy(vl.plugin, "battery", sizeof(vl.plugin));
+  /* statefs supports 1 battery at present */
+  sstrncpy(vl.plugin_instance, "0", sizeof(vl.plugin_instance));
+  sstrncpy(vl.type, type, sizeof(vl.type));
+  if (type_instance != NULL)
+    sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
+  plugin_dispatch_values(&vl);
+}
+
+/* cannot be static, is referred to from battery.c */
+int battery_read_statefs(void) {
+  value_t v;
+  int success = 0;
+
+  if (parse_value_file(STATEFS_ROOT "ChargePercentage", &v, DS_TYPE_GAUGE) == 0) {
+    battery_submit("charge", v.gauge, NULL);
+    success++;
+  } else if (parse_value_file(STATEFS_ROOT "Capacity", &v, DS_TYPE_GAUGE) == 0) {
+    // Use capacity as a charge estimate if ChargePercentage is not available
+    battery_submit("charge", v.gauge, NULL);
+    success++;
+  } else {
+    WARNING("battery plugin: Neither \""STATEFS_ROOT"ChargePercentage\" "
+            "nor \""STATEFS_ROOT"Capacity\" could be read.");
+  }
+
+  struct {
+    char *path;
+    char *type;
+    char *type_instance;
+    gauge_t factor;
+  } metrics[] = {
+    {STATEFS_ROOT "Current",       "current",     NULL,  1e-6}, // from uA to A
+    {STATEFS_ROOT "Energy",        "energy_wh",   NULL,  1e-6}, // from uWh to Wh
+    {STATEFS_ROOT "Power",         "power",       NULL,  1e-6}, // from uW to W
+    {STATEFS_ROOT "Temperature",   "temperature", NULL,   0.1}, // from 10xC to C
+    {STATEFS_ROOT "TimeUntilFull", "duration",    "full", 1.0},
+    {STATEFS_ROOT "TimeUntilLow",  "duration",    "low",  1.0},
+    {STATEFS_ROOT "Voltage",       "voltage",     NULL,  1e-6}, // from uV to V
+  };
+
+  for (size_t i = 0; i < STATIC_ARRAY_SIZE(metrics); i++) {
+    if (parse_value_file(metrics[i].path, &v, DS_TYPE_GAUGE) != 0) {
+      WARNING("battery plugin: Reading \"%s\" failed.", metrics[i].path);
+      continue;
+    }
+
+    battery_submit(metrics[i].type, v.gauge * metrics[i].factor, metrics[i].type_instance);
+    success++;
+  }
+
+  if (success == 0) {
+    ERROR("battery plugin: statefs backend: none of the statistics are available");
+    return (-1);
+  }
+
+  return (0);
+}
index 9b6b32e3dada7811eca47ba32268b18decec1aff..2b7ad7579c5ec410b2451f953fdb0cbf36d251c1 100644 (file)
@@ -125,47 +125,47 @@ static char   bind_curl_error[CURL_ERROR_SIZE];
 static const translation_info_t nsstats_translation_table[] = /* {{{ */
 {
   /* Requests */
-  { "Requestv4",       "dns_request",  "IPv4"        },
-  { "Requestv6",       "dns_request",  "IPv6"        },
-  { "ReqEdns0",        "dns_request",  "EDNS0"       },
-  { "ReqBadEDNSVer",   "dns_request",  "BadEDNSVer"  },
-  { "ReqTSIG",         "dns_request",  "TSIG"        },
-  { "ReqSIG0",         "dns_request",  "SIG0"        },
-  { "ReqBadSIG",       "dns_request",  "BadSIG"      },
-  { "ReqTCP",          "dns_request",  "TCP"         },
+  { "Requestv4",       "dns_request",  "IPv4"          },
+  { "Requestv6",       "dns_request",  "IPv6"          },
+  { "ReqEdns0",        "dns_request",  "EDNS0"         },
+  { "ReqBadEDNSVer",   "dns_request",  "BadEDNSVer"    },
+  { "ReqTSIG",         "dns_request",  "TSIG"          },
+  { "ReqSIG0",         "dns_request",  "SIG0"          },
+  { "ReqBadSIG",       "dns_request",  "BadSIG"        },
+  { "ReqTCP",          "dns_request",  "TCP"           },
   /* Rejects */
-  { "AuthQryRej",      "dns_reject",   "authorative" },
-  { "RecQryRej",       "dns_reject",   "recursive"   },
-  { "XfrRej",          "dns_reject",   "transfer"    },
-  { "UpdateRej",       "dns_reject",   "update"      },
+  { "AuthQryRej",      "dns_reject",   "authoritative" },
+  { "RecQryRej",       "dns_reject",   "recursive"     },
+  { "XfrRej",          "dns_reject",   "transfer"      },
+  { "UpdateRej",       "dns_reject",   "update"        },
   /* Responses */
-  { "Response",        "dns_response", "normal"      },
-  { "TruncatedResp",   "dns_response", "truncated"   },
-  { "RespEDNS0",       "dns_response", "EDNS0"       },
-  { "RespTSIG",        "dns_response", "TSIG"        },
-  { "RespSIG0",        "dns_response", "SIG0"        },
+  { "Response",        "dns_response", "normal"        },
+  { "TruncatedResp",   "dns_response", "truncated"     },
+  { "RespEDNS0",       "dns_response", "EDNS0"         },
+  { "RespTSIG",        "dns_response", "TSIG"          },
+  { "RespSIG0",        "dns_response", "SIG0"          },
   /* Queries */
-  { "QryAuthAns",      "dns_query",    "authorative" },
-  { "QryNoauthAns",    "dns_query",    "nonauth"     },
-  { "QryReferral",     "dns_query",    "referral"    },
-  { "QryRecursion",    "dns_query",    "recursion"   },
-  { "QryDuplicate",    "dns_query",    "dupliate"    },
-  { "QryDropped",      "dns_query",    "dropped"     },
-  { "QryFailure",      "dns_query",    "failure"     },
+  { "QryAuthAns",      "dns_query",    "authoritative" },
+  { "QryNoauthAns",    "dns_query",    "nonauth"       },
+  { "QryReferral",     "dns_query",    "referral"      },
+  { "QryRecursion",    "dns_query",    "recursion"     },
+  { "QryDuplicate",    "dns_query",    "duplicate"     },
+  { "QryDropped",      "dns_query",    "dropped"       },
+  { "QryFailure",      "dns_query",    "failure"       },
   /* Response codes */
-  { "QrySuccess",      "dns_rcode",    "tx-NOERROR"  },
-  { "QryNxrrset",      "dns_rcode",    "tx-NXRRSET"  },
-  { "QrySERVFAIL",     "dns_rcode",    "tx-SERVFAIL" },
-  { "QryFORMERR",      "dns_rcode",    "tx-FORMERR"  },
-  { "QryNXDOMAIN",     "dns_rcode",    "tx-NXDOMAIN" }
+  { "QrySuccess",      "dns_rcode",    "tx-NOERROR"    },
+  { "QryNxrrset",      "dns_rcode",    "tx-NXRRSET"    },
+  { "QrySERVFAIL",     "dns_rcode",    "tx-SERVFAIL"   },
+  { "QryFORMERR",      "dns_rcode",    "tx-FORMERR"    },
+  { "QryNXDOMAIN",     "dns_rcode",    "tx-NXDOMAIN"   }
 #if 0
-  { "XfrReqDone",      "type", "type_instance"       },
-  { "UpdateReqFwd",    "type", "type_instance"       },
-  { "UpdateRespFwd",   "type", "type_instance"       },
-  { "UpdateFwdFail",   "type", "type_instance"       },
-  { "UpdateDone",      "type", "type_instance"       },
-  { "UpdateFail",      "type", "type_instance"       },
-  { "UpdateBadPrereq", "type", "type_instance"       },
+  { "XfrReqDone",      "type",         "type_instance" },
+  { "UpdateReqFwd",    "type",         "type_instance" },
+  { "UpdateRespFwd",   "type",         "type_instance" },
+  { "UpdateFwdFail",   "type",         "type_instance" },
+  { "UpdateDone",      "type",         "type_instance" },
+  { "UpdateFail",      "type",         "type_instance" },
+  { "UpdateBadPrereq", "type",         "type_instance" },
 #endif
 };
 static int nsstats_translation_table_length =
@@ -247,16 +247,12 @@ static int memsummary_translation_table_length =
 static void submit (time_t ts, const char *plugin_instance, /* {{{ */
     const char *type, const char *type_instance, value_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0] = value;
-
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
   if (config_parse_time)
     vl.time = TIME_T_TO_CDTIME_T (ts);
-  sstrncpy(vl.host, hostname_g, sizeof(vl.host));
   sstrncpy(vl.plugin, "bind", sizeof(vl.plugin));
   if (plugin_instance) {
     sstrncpy(vl.plugin_instance, plugin_instance,
index e6d3767b3140d786698f054796b23b4ed903b78f..7c5c8a5be989f048f023215a0922588079623ac7 100644 (file)
@@ -1162,7 +1162,6 @@ cconn_process_data(struct cconn *io, yajl_struct *yajl, yajl_handle hand)
     }
 
     vtmp->vlist = (value_list_t)VALUE_LIST_INIT;
-    sstrncpy(vtmp->vlist.host, hostname_g, sizeof(vtmp->vlist.host));
     sstrncpy(vtmp->vlist.plugin, "ceph", sizeof(vtmp->vlist.plugin));
     sstrncpy(vtmp->vlist.plugin_instance, io->d->name, sizeof(vtmp->vlist.plugin_instance));
 
@@ -1468,15 +1467,22 @@ static int cconn_main_loop(uint32_t request_type)
     struct timeval end_tv;
     struct cconn io_array[g_num_daemons];
 
-    DEBUG("ceph plugin: entering cconn_main_loop(request_type = %d)", request_type);
+    DEBUG ("ceph plugin: entering cconn_main_loop(request_type = %"PRIu32")", request_type);
+
+    if (g_num_daemons < 1)
+    {
+        ERROR ("ceph plugin: No daemons configured. See the \"Daemon\" config option.");
+        return ENOENT;
+    }
 
     /* create cconn array */
-    memset(io_array, 0, sizeof(io_array));
-    for(size_t i = 0; i < g_num_daemons; ++i)
+    for (size_t i = 0; i < g_num_daemons; i++)
     {
-        io_array[i].d = g_daemons[i];
-        io_array[i].request_type = request_type;
-        io_array[i].state = CSTATE_UNCONNECTED;
+        io_array[i] = (struct cconn) {
+            .d = g_daemons[i],
+            .request_type = request_type,
+            .state = CSTATE_UNCONNECTED,
+        };
     }
 
     /** Calculate the time at which we should give up */
index f7c7e0d6345676ab77c79d8c6f0a880331b75273..2584eff01edd2a71d1b7acc69f1ac02b400d49ec 100644 (file)
@@ -46,7 +46,6 @@ static void cgroups_submit_one (char const *plugin_instance,
 
        vl.values = &value;
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cgroups", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
index f6294e49112dabdcf70a0c84c78e96e40b2a5945..77ba8cc460564d42ed6b8794080a36234e3c0199 100644 (file)
@@ -677,18 +677,12 @@ ntohf(tFloat p_float)
 static void
 chrony_push_data(const char *p_type, const char *p_type_inst, double p_value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = p_value;    /* TODO: Check type??? (counter, gauge, derive, absolute) */
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = p_value };
   vl.values_len = 1;
 
   /* XXX: Shall g_chrony_host/g_chrony_port be reflected in the plugin's output? */
-  /* hostname_g is set in daemon/collectd.c (from config, via gethostname or by resolving localhost) */
-  /* defined as: char hostname_g[DATA_MAX_NAME_LEN]; (never NULL) */
-  sstrncpy(vl.host, hostname_g, sizeof(vl.host));
   sstrncpy(vl.plugin, PLUGIN_NAME_SHORT, sizeof(vl.plugin));
   if (g_chrony_plugin_instance != NULL)
   {
index 0102e9216d39e1bd685fe49de5b92f707da50d16..9af3c0c9af759f4c76d3dc410c21b83799b90b69 100644 (file)
@@ -75,6 +75,20 @@ Adds I<Dir> to the B<@INC> array. This is the same as using the B<-IDir>
 command line option or B<use lib Dir> in the source code. Please note that it
 only has effect on plugins loaded after this option.
 
+=item B<RegisterLegacyFlush> I<true|false>
+
+The C<Perl plugin> used to register one flush callback (called B<"perl">) and
+call all Perl-based flush handlers when this callback was called. Newer versions
+of the plugin wrap the Perl flush handlers and register them directly with the
+daemon I<in addition> to the legacy B<"perl"> callback. This allows to call
+specific Perl flush handlers, but has the downside that flushing I<all> plugins
+now calls the Perl flush handlers twice (once directly and once via the legacy
+callback). Unfortunately, removing the B<"perl"> callback would break backwards
+compatibility.
+
+This option allows you to disable the legacy B<"perl"> flush callback if you care
+about the double call and don't call the B<"perl"> callback in your setup.
+
 =back
 
 =head1 WRITING YOUR OWN PLUGINS
@@ -759,18 +773,6 @@ dispatched by the perl plugin after upgrades.
 
 =back
 
-=head1 KNOWN BUGS
-
-=over 4
-
-=item *
-
-Currently, it is not possible to flush a single Perl plugin only. You can
-either flush all Perl plugins or none at all and you have to use C<perl> as
-plugin name when doing so.
-
-=back
-
 =head1 SEE ALSO
 
 L<collectd(1)>,
index f0ac28713b1f30195df8e20683b314dec92402c9..ae2995115e34d7b072e8c6a0cfaf7be97f916359 100644 (file)
 #@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
 #@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
 #@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
+#@BUILD_PLUGIN_DPDKSTAT_TRUE@LoadPlugin dpdkstat
 #@BUILD_PLUGIN_DRBD_TRUE@LoadPlugin drbd
 #@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
 #@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
 #@BUILD_PLUGIN_GPS_TRUE@LoadPlugin gps
 #@BUILD_PLUGIN_GRPC_TRUE@LoadPlugin grpc
 #@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
+#@BUILD_PLUGIN_HUGEPAGES_TRUE@LoadPlugin hugepages
+#@BUILD_PLUGIN_INTEL_RDT_TRUE@LoadPlugin intel_rdt
 @BUILD_PLUGIN_INTERFACE_TRUE@@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
 #@BUILD_PLUGIN_IPC_TRUE@LoadPlugin ipc
 #@BUILD_PLUGIN_IPMI_TRUE@LoadPlugin ipmi
 #<Plugin "battery">
 #  ValuesPercentage false
 #  ReportDegraded false
+#  QueryStateFS false
 #</Plugin>
 
 #<Plugin "bind">
 #      SelectNumericQueryTypes true
 #</Plugin>
 
+#<Plugin dpdkstat>
+#       Interval 1
+#       Coremask "0xf"
+#       ProcessType "secondary"
+#       FilePrefix "rte"
+#       EnabledPortMask 0xffff
+#       PortName "interface1"
+#       PortName "interface2"
+#</Plugin>
+
 #<Plugin email>
 #      SocketFile "@localstatedir@/run/@PACKAGE_NAME@-email"
 #      SocketGroup "collectd"
 #  Port "7634"
 #</Plugin>
 
+#<Plugin hugepages>
+#    ReportPerNodeHP  true
+#    ReportRootHP     true
+#    ValuesPages      true
+#    ValuesBytes      false
+#    ValuesPercentage false
+#</Plugin>
+
+#<Plugin "intel_rdt">
+#  Cores "0-2"
+#</Plugin>
+
 #<Plugin interface>
 #      Interface "eth0"
 #      IgnoreSelected false
 
 #<Plugin memcached>
 #      <Instance "local">
-#              Host "127.0.0.1"
+#              #Host "memcache.example.com"
+#              Address "127.0.0.1"
 #              Port "11211"
 #      </Instance>
 #</Plugin>
 #    AlwaysAppendDS false
 #    EscapeCharacter "_"
 #    SeparateInstances false
+#    DropDuplicateFields false
 #  </Node>
 #</Plugin>
 
index 9c97137ce8b9121f0536efb3cef1d335aafac189..1310c50d754bcbef6cdce361eeb341960f5dc46c 100644 (file)
@@ -1114,6 +1114,13 @@ When set to B<true>, the battery plugin will report three values: B<charged>
 and "remaining capacity") and B<degraded> (difference between "design capacity"
 and "last full capacity").
 
+=item B<QueryStateFS> B<false>|B<true>
+
+When set to B<true>, the battery plugin will only read statistics
+related to battery performance as exposed by StateFS at
+/run/state. StateFS is used in Mer-based Sailfish OS, for
+example.
+
 =back
 
 =head2 Plugin C<bind>
@@ -2369,6 +2376,67 @@ Enabled by default, collects unknown (and thus presented as numeric only) query
 
 =back
 
+=head2 Plugin C<dpdkstat>
+
+The I<dpdkstat plugin> collects information about DPDK interfaces using the
+extended NIC stats API in DPDK.
+
+B<Synopsis:>
+
+ <Plugin "dpdkstat">
+    Coremask "0x4"
+    MemoryChannels "4"
+    ProcessType "secondary"
+    FilePrefix "rte"
+    EnabledPortMask 0xffff
+    PortName "interface1"
+    PortName "interface2"
+ </Plugin>
+
+B<Options:>
+
+=over 4
+
+=item B<Coremask> I<Mask>
+
+A string containing an hexadecimal bit mask of the cores to run on. Note that
+core numbering can change between platforms and should be determined beforehand.
+
+=item B<Memorychannels> I<Channels>
+
+A string containing a number of memory channels per processor socket.
+
+=item B<ProcessType> I<type>
+
+A string containing the type of DPDK process instance.
+
+=item B<FilePrefix> I<File>
+
+The prefix text used for hugepage filenames. The filename will be set to
+/var/run/.<prefix>_config where prefix is what is passed in by the user.
+
+=item B<SocketMemory> I<MB>
+
+A string containing amount of Memory to allocate from hugepages on specific
+sockets in MB
+
+=item B<EnabledPortMask> I<Mask>
+
+A hexidecimal bit mask of the DPDK ports which should be enabled. A mask
+of 0x0 means that all ports will be disabled. A bitmask of all Fs means
+that all ports will be enabled. This is an optional argument - default
+is all ports enabled.
+
+=item B<PortName> I<Name>
+
+A string containing an optional name for the enabled DPDK ports. Each PortName
+option should contain only one port name; specify as many PortName options as
+desired. Default naming convention will be used if PortName is blank. If there
+are less PortName options than there are enabled ports, the default naming
+convention will be used for the additional ports.
+
+=back
+
 =head2 Plugin C<email>
 
 =over 4
@@ -2819,6 +2887,101 @@ TCP-Port to connect to. Defaults to B<7634>.
 
 =back
 
+=head2 Plugin C<hugepages>
+
+To collect B<hugepages> information, collectd reads directories
+"/sys/devices/system/node/*/hugepages" and
+"/sys/kernel/mm/hugepages".
+Reading of these directories can be disabled by the following
+options (default is enabled).
+
+=over 4
+
+=item B<ReportPerNodeHP> B<true>|B<false>
+
+If enabled, information will be collected from the hugepage
+counters in "/sys/devices/system/node/*/hugepages".
+This is used to check the per-node hugepage statistics on
+a NUMA system.
+
+=item B<ReportRootHP> B<true>|B<false>
+
+If enabled, information will be collected from the hugepage
+counters in "/sys/kernel/mm/hugepages".
+This can be used on both NUMA and non-NUMA systems to check
+the overall hugepage statistics.
+
+=item B<ValuesPages> B<true>|B<false>
+
+Whether to report hugepages metrics in number of pages.
+Defaults to B<true>.
+
+=item B<ValuesBytes> B<false>|B<true>
+
+Whether to report hugepages metrics in bytes.
+Defaults to B<false>.
+
+=item B<ValuesPercentage> B<false>|B<true>
+
+Whether to report hugepages metrics as percentage.
+Defaults to B<false>.
+
+=back
+
+=head2 Plugin C<intel_rdt>
+
+The I<intel_rdt> plugin collects information provided by monitoring features of
+Intel Resource Director Technology (Intel(R) RDT) like Cache Monitoring
+Technology (CMT), Memory Bandwidth Monitoring (MBM). These features provide
+information about utilization of shared resources. CMT monitors last level cache
+occupancy (LLC). MBM supports two types of events reporting local and remote
+memory bandwidth. Local memory bandwidth (MBL) reports the bandwidth of
+accessing memory associated with the local socket. Remote memory bandwidth (MBR)
+reports the bandwidth of accessing the remote socket. Also this technology
+allows to monitor instructions per clock (IPC).
+Monitor events are hardware dependant. Monitoring capabilities are detected on
+plugin initialization and only supported events are monitored.
+
+B<Synopsis:>
+
+  <Plugin "intel_rdt">
+    Cores "0-2" "3,4,6" "8-10,15"
+  </Plugin>
+
+B<Options:>
+
+=over 4
+
+=item B<Interval> I<seconds>
+
+The interval within which to retrieve statistics on monitored events in seconds.
+For milliseconds divide the time by 1000 for example if the desired interval
+is 50ms, set interval to 0.05. Due to limited capacity of counters it is not
+recommended to set interval higher than 1 sec.
+
+=item B<Cores> I<cores groups>
+
+All events are reported on a per core basis. Monitoring of the events can be
+configured for group of cores (aggregated statistics). This field defines groups
+of cores on which to monitor supported events. The field is represented as list
+of strings with core group values. Each string represents a list of cores in a
+group. Allowed formats are:
+    0,1,2,3
+    0-10,20-18
+    1,3,5-8,10,0x10-12
+
+If an empty string is provided as value for this field default cores
+configuration is applied - a separate group is created for each core.
+
+=back
+
+B<Note:> By default global interval is used to retrieve statistics on monitored
+events. To configure a plugin specific interval use B<Interval> option of the
+intel_rdt <LoadPlugin> block. For milliseconds divide the time by 1000 for
+example if the desired interval is 50ms, set interval to 0.05.
+Due to limited capacity of counters it is not recommended to set interval higher
+than 1 sec.
+
 =head2 Plugin C<interface>
 
 =over 4
@@ -3232,11 +3395,12 @@ interpreted. For a description of match blocks, please see L<"Plugin tail">.
 
 The B<memcached plugin> connects to a memcached server and queries statistics
 about cache utilization, memory and bandwidth used.
-L<http://www.danga.com/memcached/>
+L<http://memcached.org/>
 
  <Plugin "memcached">
    <Instance "name">
-     Host "memcache.example.com"
+     #Host "memcache.example.com"
+     Address "127.0.0.1"
      Port 11211
    </Instance>
  </Plugin>
@@ -3249,16 +3413,25 @@ following options are allowed:
 
 =item B<Host> I<Hostname>
 
-Hostname to connect to. Defaults to B<127.0.0.1>.
+Sets the B<host> field of dispatched values. Defaults to the global hostname
+setting.
+For backwards compatibility, values are also dispatched with the global
+hostname when B<Host> is set to B<127.0.0.1> or B<localhost> and B<Address> is
+not set.
+
+=item B<Address> I<Address>
+
+Hostname or IP to connect to. For backwards compatibility, defaults to the
+value of B<Host> or B<127.0.0.1> if B<Host> is unset.
 
 =item B<Port> I<Port>
 
-TCP-Port to connect to. Defaults to B<11211>.
+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.
+setting is given, the B<Address> and B<Port> settings are ignored.
 
 =back
 
@@ -5699,7 +5872,7 @@ values are made available through those parameters:
 
 =item B<$1>
 
-The timestamp of the queried value as a floating point number.
+The timestamp of the queried value as an RFC 3339-formatted local time.
 
 =item B<$2>
 
@@ -7791,6 +7964,32 @@ If set to B<true>, append the name of the I<Data Source> (DS) to the "metric"
 identifier. If set to B<false> (the default), this is only done when there is
 more than one DS.
 
+=item B<DropDuplicateFields> B<false>|B<true>
+
+If set to B<true>, detect and remove duplicate components in Graphite metric
+names. For example, the metric name  C<host.load.load.shortterm> will
+be shortened to C<host.load.shortterm>.
+
+=back
+
+=head2 Plugin C<write_log>
+
+The C<write_log> plugin writes metrics as INFO log messages.
+
+This plugin supports two output formats: I<Graphite> and I<JSON>.
+
+Synopsis:
+
+ <Plugin write_log>
+   Format Graphite
+ </Plugin>
+
+=over 4
+
+=item B<Format> I<Format>
+
+The output format to use. Can be one of C<Graphite> or C<JSON>.
+
 =back
 
 =head2 Plugin C<write_tsdb>
@@ -9066,6 +9265,8 @@ Available options:
 
 =item B<TypeInstance> I<Regex>
 
+=item B<MetaData> I<String> I<Regex>
+
 Match values where the given regular expressions match the various fields of
 the identifier of a value. If multiple regular expressions are given, B<all>
 regexen must match for a value to match.
@@ -9354,6 +9555,10 @@ Available options:
 
 =item B<TypeInstance> I<Regex> I<Replacement>
 
+=item B<MetaData> I<String> I<Regex> I<Replacement>
+
+=item B<DeleteMetaData> I<String> I<Regex>
+
 Match the appropriate field with the given regular expression I<Regex>. If the
 regular expression matches, that part that matches is replaced with
 I<Replacement>. If multiple places of the input buffer match a given regular
@@ -9392,9 +9597,37 @@ Available options:
 
 =item B<MetaData> I<String> I<String>
 
-Set the appropriate field to the given string. The strings for plugin instance
-and type instance may be empty, the strings for host and plugin may not be
-empty. It's currently not possible to set the type of a value this way.
+Set the appropriate field to the given string. The strings for plugin instance,
+type instance, and meta data may be empty, the strings for host and plugin may
+not be empty. It's currently not possible to set the type of a value this way.
+
+The following placeholders will be replaced by an appropriate value:
+
+=over 4
+
+=item B<%{host}>
+
+=item B<%{plugin}>
+
+=item B<%{plugin_instance}>
+
+=item B<%{type}>
+
+=item B<%{type_instance}>
+
+These placeholders are replaced by the identifier field of the same name.
+
+=item B<%{meta:>I<name>B<}>
+
+These placeholders are replaced by the meta data value with the given name.
+
+=back
+
+Please note that these placeholders are B<case sensitive>!
+
+=item B<DeleteMetaData> I<String>
+
+Delete the named meta data field.
 
 =back
 
index ce90ede34749e5e30b4014e99193539119f5ea68..26f62786b242872dd89c4a943358f3d0164b2d45 100644 (file)
@@ -61,7 +61,6 @@ static void conntrack_submit (const char *type, const char *type_instance,
 
        vl.values = &conntrack;
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "conntrack", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_instance != NULL)
@@ -74,61 +73,26 @@ static void conntrack_submit (const char *type, const char *type_instance,
 static int conntrack_read (void)
 {
        value_t conntrack, conntrack_max, conntrack_pct;
-       FILE *fh;
-       char buffer[64] = { 0 };
-       size_t buffer_len;
 
-       fh = fopen (old_files?CONNTRACK_FILE_OLD:CONNTRACK_FILE, "r");
-       if (fh == NULL)
-               return (-1);
-
-       if (fgets (buffer, sizeof (buffer), fh) == NULL)
+       char const *path = old_files ? CONNTRACK_FILE_OLD : CONNTRACK_FILE;
+       if (parse_value_file (path, &conntrack, DS_TYPE_GAUGE) != 0)
        {
-               fclose (fh);
+               ERROR ("conntrack plugin: Reading \"%s\" failed.", path);
                return (-1);
        }
-       fclose (fh);
 
-       /* strip trailing newline. */
-       buffer_len = strlen (buffer);
-       while ((buffer_len > 0) && isspace ((int) buffer[buffer_len - 1]))
+       path = old_files ? CONNTRACK_MAX_FILE_OLD : CONNTRACK_MAX_FILE;
+       if (parse_value_file (path, &conntrack_max, DS_TYPE_GAUGE) != 0)
        {
-               buffer[buffer_len - 1] = 0;
-               buffer_len--;
-       }
-
-       if (parse_value (buffer, &conntrack, DS_TYPE_GAUGE) != 0)
-               return (-1);
-
-       conntrack_submit ("conntrack", NULL, conntrack);
-
-       fh = fopen (old_files?CONNTRACK_MAX_FILE_OLD:CONNTRACK_MAX_FILE, "r");
-       if (fh == NULL)
-               return (-1);
-
-       memset (buffer, 0, sizeof (buffer));
-       if (fgets (buffer, sizeof (buffer), fh) == NULL)
-       {
-               fclose (fh);
+               ERROR ("conntrack plugin: Reading \"%s\" failed.", path);
                return (-1);
        }
-       fclose (fh);
-
-       /* strip trailing newline. */
-       buffer_len = strlen (buffer);
-       while ((buffer_len > 0) && isspace ((int) buffer[buffer_len - 1]))
-       {
-               buffer[buffer_len - 1] = 0;
-               buffer_len--;
-       }
-
-       if (parse_value (buffer, &conntrack_max, DS_TYPE_GAUGE) != 0)
-               return (-1);
 
-       conntrack_submit ("conntrack", "max", conntrack_max);
        conntrack_pct.gauge = (conntrack.gauge / conntrack_max.gauge) * 100;
-       conntrack_submit ("percent", "used", conntrack_pct);
 
+       conntrack_submit ("conntrack", NULL,   conntrack);
+       conntrack_submit ("conntrack", "max",  conntrack_max);
+       conntrack_submit ("percent",   "used", conntrack_pct);
 
        return (0);
 } /* static int conntrack_read */
index 76e2a6c0b935c9225d50e96e7c2405554f459476..834fbd74cd9182c7931c6a2ce898cb98650c01cc 100644 (file)
 
 static void cs_submit (derive_t context_switches)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].derive = (derive_t) context_switches;
-
-       vl.values = values;
+       vl.values = &(value_t) { .derive = context_switches };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "contextswitch", sizeof (vl.plugin));
        sstrncpy (vl.type, "contextswitch", sizeof (vl.type));
 
index 1ac5b4a3b94a9cea50835485befc4adf7c934b88..36c49720f1bcf464f33a2e653236d80c64f5dcd5 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -162,6 +162,12 @@ static int maxcpu;
 /* #endif  HAVE_LIBSTATGRAB */
 
 #elif defined(HAVE_PERFSTAT)
+#define TOTAL_IDLE 0
+#define TOTAL_USER 1
+#define TOTAL_SYS 2
+#define TOTAL_WAIT 3
+#define TOTAL_STAT_NUM 4
+static value_to_rate_state_t total_conv[TOTAL_STAT_NUM];
 static perfstat_cpu_t *perfcpu;
 static int numcpu;
 static int pnumcpu;
@@ -325,15 +331,11 @@ static int init (void)
 
 static void submit_value (int cpu_num, int cpu_state, const char *type, value_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       memcpy(&values[0], &value, sizeof(value));
-
-       vl.values = values;
+       vl.values = &value;
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, cpu_state_names[cpu_state],
@@ -346,26 +348,22 @@ static void submit_value (int cpu_num, int cpu_state, const char *type, value_t
        plugin_dispatch_values (&vl);
 }
 
-static void submit_percent(int cpu_num, int cpu_state, gauge_t percent)
+static void submit_percent (int cpu_num, int cpu_state, gauge_t value)
 {
-       value_t value;
-
        /* This function is called for all known CPU states, but each read
         * method will only report a subset. The remaining states are left as
         * NAN and we ignore them here. */
-       if (isnan (percent))
+       if (isnan (value))
                return;
 
-       value.gauge = percent;
-       submit_value (cpu_num, cpu_state, "percent", value);
+       submit_value (cpu_num, cpu_state, "percent",
+                       (value_t) { .gauge = value });
 }
 
-static void submit_derive(int cpu_num, int cpu_state, derive_t derive)
+static void submit_derive (int cpu_num, int cpu_state, derive_t value)
 {
-       value_t value;
-
-       value.derive = derive;
-       submit_value (cpu_num, cpu_state, "cpu", value);
+       submit_value (cpu_num, cpu_state, "cpu",
+                       (value_t) { .derive = value });
 }
 
 /* Takes the zero-index number of a CPU and makes sure that the module-global
@@ -406,6 +404,24 @@ static cpu_state_t *get_cpu_state (size_t cpu_num, size_t state) /* {{{ */
        return (&cpu_states[index]);
 } /* }}} cpu_state_t *get_cpu_state */
 
+#if defined(HAVE_PERFSTAT) /* {{{ */
+/* populate global aggregate cpu rate */
+static int total_rate(gauge_t *sum_by_state, size_t state, derive_t d,
+                                         value_to_rate_state_t* conv, cdtime_t now)
+{
+       gauge_t rate = NAN;
+       int status = value_to_rate (&rate, (value_t) { .derive = d }, DS_TYPE_DERIVE, now, conv);
+       if (status != 0)
+               return (status);
+
+       sum_by_state[state] = rate;
+
+       if (state != COLLECTD_CPU_STATE_IDLE)
+               RATE_ADD (sum_by_state[COLLECTD_CPU_STATE_ACTIVE], sum_by_state[state]);
+       return (0);
+}
+#endif /* }}} HAVE_PERFSTAT */
+
 /* Populates the per-CPU COLLECTD_CPU_STATE_ACTIVE rate and the global rate_by_state
  * array. */
 static void aggregate (gauge_t *sum_by_state) /* {{{ */
@@ -434,6 +450,27 @@ static void aggregate (gauge_t *sum_by_state) /* {{{ */
 
                RATE_ADD (sum_by_state[COLLECTD_CPU_STATE_ACTIVE], this_cpu_states[COLLECTD_CPU_STATE_ACTIVE].rate);
        }
+
+#if defined(HAVE_PERFSTAT) /* {{{ */
+       cdtime_t now = cdtime ();
+       perfstat_cpu_total_t cputotal = { 0 };
+
+       if (!perfstat_cpu_total(NULL, &cputotal, sizeof(cputotal), 1)) {
+               char errbuf[1024];
+               WARNING ("cpu plugin: perfstat_cpu_total: %s",
+                               sstrerror (errno, errbuf, sizeof (errbuf)));
+               return;
+       }
+
+       /* Reset COLLECTD_CPU_STATE_ACTIVE */
+       sum_by_state[COLLECTD_CPU_STATE_ACTIVE] = NAN;
+
+       /* Physical Processor Utilization */
+       total_rate(sum_by_state, COLLECTD_CPU_STATE_IDLE,   (derive_t) cputotal.pidle, &total_conv[TOTAL_IDLE], now);
+       total_rate(sum_by_state, COLLECTD_CPU_STATE_USER,   (derive_t) cputotal.puser, &total_conv[TOTAL_USER], now);
+       total_rate(sum_by_state, COLLECTD_CPU_STATE_SYSTEM, (derive_t) cputotal.psys , &total_conv[TOTAL_SYS],  now);
+       total_rate(sum_by_state, COLLECTD_CPU_STATE_WAIT,   (derive_t) cputotal.pwait, &total_conv[TOTAL_WAIT], now);
+#endif /* }}} HAVE_PERFSTAT */
 } /* }}} void aggregate */
 
 /* Commits (dispatches) the values for one CPU or the global aggregation.
@@ -464,17 +501,13 @@ static void cpu_commit_one (int cpu_num, /* {{{ */
 } /* }}} void cpu_commit_one */
 
 /* Commits the number of cores */
-static void cpu_commit_num_cpu (gauge_t num_cpu) /* {{{ */
+static void cpu_commit_num_cpu (gauge_t value) /* {{{ */
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = num_cpu;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
        sstrncpy (vl.type, "count", sizeof (vl.type));
 
@@ -555,7 +588,7 @@ static int cpu_stage (size_t cpu_num, size_t state, derive_t d, cdtime_t now) /*
        int status;
        cpu_state_t *s;
        gauge_t rate = NAN;
-       value_t val = {.derive = d};
+       value_t val = { .derive = d };
 
        if (state >= COLLECTD_CPU_STATE_ACTIVE)
                return (EINVAL);
index 1e9e857980c68c3ebcb19af9e9b8c15d3f83ddcc..285ee6c6819931b8635aca06d1ac088dff67601b 100644 (file)
@@ -25,8 +25,6 @@
 #include "common.h"
 #include "plugin.h"
 
-#define MODULE_NAME "cpufreq"
-
 static int num_cpu = 0;
 
 static int cpufreq_init (void)
@@ -59,72 +57,38 @@ static int cpufreq_init (void)
        return (0);
 } /* int cpufreq_init */
 
-static void cpufreq_submit (int cpu_num, double value)
+static void cpufreq_submit (int cpu_num, value_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &value;
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpufreq", sizeof (vl.plugin));
        sstrncpy (vl.type, "cpufreq", sizeof (vl.type));
-       ssnprintf (vl.type_instance, sizeof (vl.type_instance),
-                       "%i", cpu_num);
+       ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%i", cpu_num);
 
        plugin_dispatch_values (&vl);
 }
 
 static int cpufreq_read (void)
 {
-        int status;
-       unsigned long long val;
-       FILE *fp;
-       char filename[256];
-       char buffer[16];
-
        for (int i = 0; i < num_cpu; i++)
        {
-               status = ssnprintf (filename, sizeof (filename),
-                               "/sys/devices/system/cpu/cpu%d/cpufreq/"
-                               "scaling_cur_freq", i);
-               if ((status < 1) || ((unsigned int)status >= sizeof (filename)))
-                       return (-1);
+               char filename[PATH_MAX];
+               ssnprintf (filename, sizeof (filename),
+                               "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
 
-               if ((fp = fopen (filename, "r")) == NULL)
+               value_t v;
+               if (parse_value_file (filename, &v, DS_TYPE_GAUGE) != 0)
                {
-                       char errbuf[1024];
-                       WARNING ("cpufreq: fopen (%s): %s", filename,
-                                       sstrerror (errno, errbuf,
-                                               sizeof (errbuf)));
-                       return (-1);
+                       WARNING ("cpufreq plugin: Reading \"%s\" failed.", filename);
+                       continue;
                }
 
-               if (fgets (buffer, 16, fp) == NULL)
-               {
-                       char errbuf[1024];
-                       WARNING ("cpufreq: fgets: %s",
-                                       sstrerror (errno, errbuf,
-                                               sizeof (errbuf)));
-                       fclose (fp);
-                       return (-1);
-               }
-
-               if (fclose (fp))
-               {
-                       char errbuf[1024];
-                       WARNING ("cpufreq: fclose: %s",
-                                       sstrerror (errno, errbuf,
-                                               sizeof (errbuf)));
-               }
-
-
-               /* You're seeing correctly: The file is reporting kHz values.. */
-               val = atoll (buffer) * 1000;
+               /* convert kHz to Hz */
+               v.gauge *= 1000.0;
 
-               cpufreq_submit (i, val);
+               cpufreq_submit (i, v);
        }
 
        return (0);
index 326c29ce2bf2394346bfc46665cdde42d224d477..31bb25d67ed4ba618f0133deac0a082d80c5ec13 100644 (file)
 #include <time.h>
 
 static void cpusleep_submit(derive_t cpu_sleep) {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].derive = cpu_sleep;
-
-  vl.values = values;
+  vl.values = &(value_t) { .derive = cpu_sleep };
   vl.values_len = 1;
-  sstrncpy(vl.host, hostname_g, sizeof(vl.host));
   sstrncpy(vl.plugin, "cpusleep", sizeof(vl.plugin));
   sstrncpy(vl.type, "total_time_in_ms", sizeof(vl.type));
 
index 74ef13c97463469e42f878b3235f328b2ed11f1f..1a5258e59552bfc34024e4fc1e8d34c72c533b3e 100644 (file)
@@ -608,16 +608,12 @@ static int cc_init (void) /* {{{ */
 } /* }}} int cc_init */
 
 static void cc_submit (const web_page_t *wp, const web_match_t *wm, /* {{{ */
-    const cu_match_value_t *mv)
+    value_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0] = mv->value;
-
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, wm->type, sizeof (vl.type));
@@ -629,14 +625,10 @@ static void cc_submit (const web_page_t *wp, const web_match_t *wm, /* {{{ */
 
 static void cc_submit_response_code (const web_page_t *wp, long code) /* {{{ */
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = code;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = (gauge_t) code };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, "response_code", sizeof (vl.type));
@@ -647,14 +639,10 @@ static void cc_submit_response_code (const web_page_t *wp, long code) /* {{{ */
 static void cc_submit_response_time (const web_page_t *wp, /* {{{ */
     cdtime_t response_time)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = CDTIME_T_TO_DOUBLE (response_time);
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = CDTIME_T_TO_DOUBLE (response_time) };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, "response_time", sizeof (vl.type));
@@ -714,7 +702,7 @@ static int cc_read_page (web_page_t *wp) /* {{{ */
       continue;
     }
 
-    cc_submit (wp, wm, mv);
+    cc_submit (wp, wm, mv->value);
     match_value_reset (mv);
   } /* for (wm = wp->matches; wm != NULL; wm = wm->next) */
 
index 7d1d8e9309c19dff2132e0deea6fac7559115152..4dab1abd8f11928fb00585550e3132fd92c9c05a 100644 (file)
@@ -775,14 +775,12 @@ static int cj_config_add_url (oconfig_item_t *ci) /* {{{ */
     cb_name = ssnprintf_alloc ("curl_json-%s-%s",
                db->instance, db->url ? db->url : db->sock);
 
-    user_data_t ud = {
-      .data = db,
-      .free_func = cj_free
-    };
-
     plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read,
                                   /* interval = */ db->interval,
-                                  &ud);
+                                  &(user_data_t) {
+                                    .data = db,
+                                    .free_func = cj_free,
+                                  });
     sfree (cb_name);
   }
   else
index c8a1313cbec48769c882ab5cb034faae3da1cc07..924665c72af1b2e792b9a8f317372713f79b1b83 100644 (file)
@@ -1026,13 +1026,12 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */
 
     cb_name = ssnprintf_alloc ("curl_xml-%s-%s", db->instance, db->url);
 
-    user_data_t ud = {
-      .data = db,
-      .free_func = cx_free
-    };
-
     plugin_register_complex_read (/* group = */ "curl_xml", cb_name, cx_read,
-                                  /* interval = */ 0, &ud);
+        /* interval = */ 0,
+        &(user_data_t) {
+          .data = db,
+          .free_func = cx_free,
+        });
     sfree (cb_name);
   }
   else
index 8573579166ab7e0aa13078d934ec92ffbf30324e..c9e49f8070536e8d1b99044c74fa0352b7c40178 100644 (file)
@@ -101,7 +101,7 @@ static int init_hostname (void)
        int status;
 
        str = global_option_get ("Hostname");
-       if (str != NULL)
+       if ((str != NULL) && (str[0] != 0))
        {
                sstrncpy (hostname_g, str, sizeof (hostname_g));
                return (0);
@@ -602,7 +602,7 @@ int main (int argc, char **argv)
         * something wrong.
         */
        if (init_global_variables () != 0)
-               return (1);
+               exit (EXIT_FAILURE);
 
        if (test_config)
                return (0);
index 477d75990515c21ea3eb08b78c59450d0da45012..7c64796aa54a1e064d7531b77ca76da0e4c06152 100644 (file)
@@ -339,50 +339,60 @@ int strsplit (char *string, char **fields, size_t size)
        return ((int) i);
 }
 
-int strjoin (char *buffer, size_t buffer_size,
-               char **fields, size_t fields_num,
-               const char *sep)
-{
-       size_t avail;
-       char *ptr;
-       size_t sep_len;
+int strjoin(char *buffer, size_t buffer_size, char **fields, size_t fields_num,
+            const char *sep) {
+  size_t avail = 0;
+  char *ptr = buffer;
+  size_t sep_len = 0;
 
-       if ((buffer_size < 1) || (fields_num == 0))
-               return (-1);
+  size_t buffer_req = 0;
 
-       memset (buffer, 0, buffer_size);
-       ptr = buffer;
-       avail = buffer_size - 1;
+  if (((fields_num != 0) && (fields == NULL)) ||
+      ((buffer_size != 0) && (buffer == NULL)))
+    return (-EINVAL);
 
-       sep_len = 0;
-       if (sep != NULL)
-               sep_len = strlen (sep);
+  if (buffer != NULL)
+    buffer[0] = 0;
 
-       for (size_t i = 0; i < fields_num; i++)
-       {
-               size_t field_len;
+  if (buffer_size != 0)
+    avail = buffer_size - 1;
 
-               if ((i > 0) && (sep_len > 0))
-               {
-                       if (avail < sep_len)
-                               return (-1);
+  if (sep != NULL)
+    sep_len = strlen(sep);
 
-                       memcpy (ptr, sep, sep_len);
-                       ptr += sep_len;
-                       avail -= sep_len;
-               }
+  for (size_t i = 0; i < fields_num; i++) {
+    size_t field_len = strlen(fields[i]);
 
-               field_len = strlen (fields[i]);
-               if (avail < field_len)
-                       return (-1);
+    if (i != 0)
+      buffer_req += sep_len;
+    buffer_req += field_len;
 
-               memcpy (ptr, fields[i], field_len);
-               ptr += field_len;
-               avail -= field_len;
-       }
+    if ((i != 0) && (sep_len > 0)) {
+      if (sep_len >= avail) {
+        /* prevent subsequent iterations from writing to the
+         * buffer. */
+        avail = 0;
+        continue;
+      }
 
-       assert (buffer[buffer_size - 1] == 0);
-       return ((int) strlen (buffer));
+      memcpy(ptr, sep, sep_len);
+
+      ptr += sep_len;
+      avail -= sep_len;
+    }
+
+    if (field_len > avail)
+      field_len = avail;
+
+    memcpy(ptr, fields[i], field_len);
+    ptr += field_len;
+
+    avail -= field_len;
+    if (ptr != NULL)
+      *ptr = 0;
+  }
+
+  return (int)buffer_req;
 }
 
 int escape_string (char *buffer, size_t buffer_size)
@@ -1006,7 +1016,8 @@ int format_values (char *ret, size_t ret_len, /* {{{ */
 
 int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
-               char **ret_type, char **ret_type_instance)
+               char **ret_type, char **ret_type_instance,
+               char *default_host)
 {
        char *hostname = NULL;
        char *plugin = NULL;
@@ -1025,8 +1036,19 @@ int parse_identifier (char *str, char **ret_host,
 
        type = strchr (plugin, '/');
        if (type == NULL)
-               return (-1);
-       *type = '\0'; type++;
+       {
+               if (default_host == NULL)
+                       return (-1);
+               /* else: no host specified; use default */
+               type = plugin;
+               plugin = hostname;
+               hostname = default_host;
+       }
+       else
+       {
+               *type = '\0';
+               type++;
+       }
 
        plugin_instance = strchr (plugin, '-');
        if (plugin_instance != NULL)
@@ -1067,7 +1089,8 @@ int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
 
        status = parse_identifier (str_copy, &host,
                        &plugin, &plugin_instance,
-                       &type, &type_instance);
+                       &type, &type_instance,
+                       /* default_host = */ NULL);
        if (status != 0)
                return (status);
 
@@ -1204,6 +1227,28 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
        return (0);
 } /* int parse_values */
 
+int parse_value_file (char const *path, value_t *ret_value, int ds_type)
+{
+       FILE *fh;
+       char buffer[256];
+
+       fh = fopen (path, "r");
+       if (fh == NULL)
+               return (-1);
+
+       if (fgets (buffer, sizeof (buffer), fh) == NULL)
+       {
+               fclose (fh);
+               return (-1);
+       }
+
+       fclose (fh);
+
+       strstripnewline (buffer);
+
+       return parse_value (buffer, ret_value, ds_type);
+} /* int parse_value_file */
+
 #if !HAVE_GETPWNAM_R
 int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
                size_t buflen, struct passwd **pwbufp)
index 720e5f1bc0a408f097fe1d586b5bbb26dda9bcce..67ca1c14cc6e8d9fcdbe4f70de47911d33d69f2d 100644 (file)
@@ -147,10 +147,12 @@ int strsplit (char *string, char **fields, size_t size);
  *   is equivalent to the Perl built-in `join'.
  *
  * PARAMETERS
- *   `dst'         Buffer where the result is stored.
+ *   `dst'         Buffer where the result is stored. Can be NULL if you need to
+ *                 determine the required buffer size only.
  *   `dst_len'     Length of the destination buffer. No more than this many
  *                 bytes will be written to the memory pointed to by `dst',
- *                 including the trailing null-byte.
+ *                 including the trailing null-byte. Must be zero if dst is
+ *                 NULL.
  *   `fields'      Array of strings to be joined.
  *   `fields_num'  Number of elements in the `fields' array.
  *   `sep'         String to be inserted between any two elements of `fields'.
@@ -158,9 +160,10 @@ int strsplit (char *string, char **fields, size_t size);
  *                 Instead of passing "" (empty string) one can pass NULL.
  *
  * RETURN VALUE
- *   Returns the number of characters in `dst', NOT including the trailing
- *   null-byte. If an error occurred (empty array or `dst' too small) a value
- *   smaller than zero will be returned.
+ *   Returns the number of characters in the resulting string, excluding a
+ *   tailing null byte. If this value is greater than or equal to "dst_len", the
+ *   result in "dst" is truncated (but still null terminated). On error a
+ *   negative value is returned.
  */
 int strjoin (char *dst, size_t dst_len, char **fields, size_t fields_num, const char *sep);
 
@@ -317,11 +320,17 @@ int format_values (char *ret, size_t ret_len,
 
 int parse_identifier (char *str, char **ret_host,
                char **ret_plugin, char **ret_plugin_instance,
-               char **ret_type, char **ret_type_instance);
+               char **ret_type, char **ret_type_instance,
+               char *default_host);
 int parse_identifier_vl (const char *str, value_list_t *vl);
 int parse_value (const char *value, value_t *ret_value, int ds_type);
 int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
 
+/* parse_value_file reads "path" and parses its content as an integer or
+ * floating point, depending on "ds_type". On success, the value is stored in
+ * "ret_value" and zero is returned. On failure, a non-zero value is returned. */
+int parse_value_file (char const *path, value_t *ret_value, int ds_type);
+
 #if !HAVE_GETPWNAM_R
 int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
                size_t buflen, struct passwd **pwbufp);
index 202ddf6cd3ab82aa0af180edf40a44e794908376..44e198ddfafd97ccbcc0abf0b2cffa088b3cb9f8 100644 (file)
@@ -148,46 +148,54 @@ DEF_TEST(strsplit)
   return (0);
 }
 
-DEF_TEST(strjoin)
-{
-  char buffer[16];
-  char *fields[4];
-  int status;
-
-  fields[0] = "foo";
-  fields[1] = "bar";
-  fields[2] = "baz";
-  fields[3] = "qux";
-
-  status = strjoin (buffer, sizeof (buffer), fields, 2, "!");
-  OK(status == 7);
-  EXPECT_EQ_STR ("foo!bar", buffer);
-
-  status = strjoin (buffer, sizeof (buffer), fields, 1, "!");
-  OK(status == 3);
-  EXPECT_EQ_STR ("foo", buffer);
-
-  status = strjoin (buffer, sizeof (buffer), fields, 0, "!");
-  OK(status < 0);
-
-  status = strjoin (buffer, sizeof (buffer), fields, 2, "rcht");
-  OK(status == 10);
-  EXPECT_EQ_STR ("foorchtbar", buffer);
-
-  status = strjoin (buffer, sizeof (buffer), fields, 4, "");
-  OK(status == 12);
-  EXPECT_EQ_STR ("foobarbazqux", buffer);
+DEF_TEST(strjoin) {
+  struct {
+    char **fields;
+    size_t fields_num;
+    char *separator;
+
+    int want_return;
+    char *want_buffer;
+  } cases
+      [] = {
+          /* Normal case. */
+          {(char *[]){"foo", "bar"}, 2, "!", 7, "foo!bar"},
+          /* One field only. */
+          {(char *[]){"foo"}, 1, "!", 3, "foo"},
+          /* No fields at all. */
+          {NULL, 0, "!", 0, ""},
+          /* Longer separator. */
+          {(char *[]){"foo", "bar"}, 2, "rcht", 10, "foorchtbar"},
+          /* Empty separator. */
+          {(char *[]){"foo", "bar"}, 2, "", 6, "foobar"},
+          /* NULL separator. */
+          {(char *[]){"foo", "bar"}, 2, NULL, 6, "foobar"},
+          /* buffer not large enough -> string is truncated. */
+          {(char *[]){"aaaaaa", "bbbbbb", "c!"}, 3, "-", 16, "aaaaaa-bbbbbb-c"},
+          /* buffer not large enough -> last field fills buffer completely. */
+          {(char *[]){"aaaaaaa", "bbbbbbb", "!"}, 3, "-", 17,
+           "aaaaaaa-bbbbbbb"},
+          /* buffer not large enough -> string does *not* end in separator. */
+          {(char *[]){"aaaa", "bbbb", "cccc", "!"}, 4, "-", 16,
+           "aaaa-bbbb-cccc"},
+          /* buffer not large enough -> string does not end with partial
+             separator. */
+          {(char *[]){"aaaaaa", "bbbbbb", "!"}, 3, "+-", 17, "aaaaaa+-bbbbbb"},
+      };
+
+  for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
+    char buffer[16];
+    int status;
 
-  status = strjoin (buffer, sizeof (buffer), fields, 4, "!");
-  OK(status == 15);
-  EXPECT_EQ_STR ("foo!bar!baz!qux", buffer);
+    memset(buffer, 0xFF, sizeof(buffer));
+    status = strjoin(buffer, sizeof(buffer), cases[i].fields,
+                     cases[i].fields_num, cases[i].separator);
+    EXPECT_EQ_INT(cases[i].want_return, status);
+    EXPECT_EQ_STR(cases[i].want_buffer, buffer);
+  }
 
-  fields[0] = "0123";
-  fields[1] = "4567";
-  fields[2] = "8901";
-  fields[3] = "2345";
-  status = strjoin (buffer, sizeof (buffer), fields, 4, "-");
-  OK(status < 0);
+  /* use (NULL, 0) to determine required buffer size. */
+  EXPECT_EQ_INT(3, strjoin(NULL, 0, (char *[]){"a", "b"}, 2, "-"));
 
   return (0);
 }
index 9e4fd07ecfdf99716a11e64532a8ccb6d5654041..a11fccb2e2fb125b02ffc9d8d048ad58f3388972 100644 (file)
 
 #include "collectd.h"
 
+#include "common.h"
 #include "plugin.h"
 #include "meta_data.h"
 
+#define MD_MAX_NONSTRING_CHARS 128
+
 /*
  * Data types
  */
@@ -729,4 +732,68 @@ int meta_data_get_boolean (meta_data_t *md, /* {{{ */
   return (0);
 } /* }}} int meta_data_get_boolean */
 
+int meta_data_as_string (meta_data_t *md, /* {{{ */
+    const char *key, char **value)
+{
+  meta_entry_t *e;
+  char *actual;
+  char buffer[MD_MAX_NONSTRING_CHARS];  /* For non-string types. */
+  char *temp;
+  int type;
+
+  if ((md == NULL) || (key == NULL) || (value == NULL))
+    return (-EINVAL);
+
+  pthread_mutex_lock (&md->lock);
+
+  e = md_entry_lookup (md, key);
+  if (e == NULL)
+  {
+    pthread_mutex_unlock (&md->lock);
+    return (-ENOENT);
+  }
+
+  type = e->type;
+
+  switch (type)
+  {
+    case MD_TYPE_STRING:
+      actual = e->value.mv_string;
+      break;
+    case MD_TYPE_SIGNED_INT:
+      ssnprintf (buffer, sizeof (buffer), "%"PRIi64, e->value.mv_signed_int);
+      actual = buffer;
+      break;
+    case MD_TYPE_UNSIGNED_INT:
+      ssnprintf (buffer, sizeof (buffer), "%"PRIu64, e->value.mv_unsigned_int);
+      actual = buffer;
+      break;
+    case MD_TYPE_DOUBLE:
+      ssnprintf (buffer, sizeof (buffer), GAUGE_FORMAT, e->value.mv_double);
+      actual = buffer;
+      break;
+    case MD_TYPE_BOOLEAN:
+      actual = e->value.mv_boolean ? "true" : "false";
+      break;
+    default:
+      pthread_mutex_unlock (&md->lock);
+      ERROR ("meta_data_as_string: unknown type %d for key `%s'", type, key);
+      return (-ENOENT);
+  }
+
+  pthread_mutex_unlock (&md->lock);
+
+  temp = md_strdup (actual);
+  if (temp == NULL)
+  {
+    pthread_mutex_unlock (&md->lock);
+    ERROR ("meta_data_as_string: md_strdup failed for key `%s'.", key);
+    return (-ENOMEM);
+  }
+
+  *value = temp;
+
+  return (0);
+} /* }}} int meta_data_as_string */
+
 /* vim: set sw=2 sts=2 et fdm=marker : */
index 0398c5460715fa9dd877d3f8209242a8d92cf2f1..f4a4f2120e867504f79b691b9c72ae3846a60925 100644 (file)
@@ -84,5 +84,10 @@ int meta_data_get_boolean (meta_data_t *md,
     const char *key,
     _Bool *value);
 
+/* Returns the value as a string, regardless of the type. */
+int meta_data_as_string (meta_data_t *md,
+    const char *key,
+    char **value);
+
 #endif /* META_DATA_H */
 /* vim: set sw=2 sts=2 et : */
index 1fbd77dfcadf6a22d8b2d484eb3c361352337e97..7446b6fab84dc300f41a9675d9653bfdfdf69a3c 100644 (file)
@@ -151,34 +151,28 @@ static const char *plugin_get_dir (void)
 }
 
 static void plugin_update_internal_statistics (void) { /* {{{ */
-       derive_t copy_write_queue_length;
-       value_list_t vl = VALUE_LIST_INIT;
-       value_t values[2];
 
-       copy_write_queue_length = write_queue_length;
+       gauge_t copy_write_queue_length = (gauge_t) write_queue_length;
 
        /* Initialize `vl' */
-       vl.values = values;
-       vl.values_len = 2;
-       vl.time = 0;
+       value_list_t vl = VALUE_LIST_INIT;
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "collectd", sizeof (vl.plugin));
 
-       vl.type_instance[0] = 0;
-       vl.values_len = 1;
-
        /* Write queue */
        sstrncpy (vl.plugin_instance, "write_queue",
                        sizeof (vl.plugin_instance));
 
        /* Write queue : queue length */
-       vl.values[0].gauge = (gauge_t) copy_write_queue_length;
+       vl.values = &(value_t) { .gauge = copy_write_queue_length };
+       vl.values_len = 1;
        sstrncpy (vl.type, "queue_length", sizeof (vl.type));
        vl.type_instance[0] = 0;
        plugin_dispatch_values (&vl);
 
        /* Write queue : Values dropped (queue length > low limit) */
-       vl.values[0].derive = (derive_t) stats_values_dropped;
+       vl.values = &(value_t) { .gauge = (gauge_t) stats_values_dropped };
+       vl.values_len = 1;
        sstrncpy (vl.type, "derive", sizeof (vl.type));
        sstrncpy (vl.type_instance, "dropped", sizeof (vl.type_instance));
        plugin_dispatch_values (&vl);
@@ -188,7 +182,8 @@ static void plugin_update_internal_statistics (void) { /* {{{ */
                        sizeof (vl.plugin_instance));
 
        /* Cache : Nb entry in cache tree */
-       vl.values[0].gauge = (gauge_t) uc_get_size();
+       vl.values = &(value_t) { .gauge = (gauge_t) uc_get_size() };
+       vl.values_len = 1;
        sstrncpy (vl.type, "cache_size", sizeof (vl.type));
        vl.type_instance[0] = 0;
        plugin_dispatch_values (&vl);
@@ -728,6 +723,9 @@ static value_list_t *plugin_value_list_clone (value_list_t const *vl_orig) /* {{
                return (NULL);
        memcpy (vl, vl_orig, sizeof (*vl));
 
+       if (vl->host[0] == 0)
+               sstrncpy (vl->host, hostname_g, sizeof (vl->host));
+
        vl->values = calloc (vl_orig->values_len, sizeof (*vl->values));
        if (vl->values == NULL)
        {
@@ -2083,15 +2081,16 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
        int status;
        static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
 
-       value_t *saved_values;
-       int      saved_values_len;
-
        data_set_t *ds;
 
-       int free_meta_data = 0;
+       _Bool free_meta_data = 0;
 
-       assert(vl);
-       assert(vl->plugin);
+       assert (vl != NULL);
+
+       /* These fields are initialized by plugin_value_list_clone() if needed: */
+       assert (vl->host[0] != 0);
+       assert (vl->time != 0); /* The time is determined at _enqueue_ time. */
+       assert (vl->interval != 0);
 
        if (vl->type[0] == 0 || vl->values == NULL || vl->values_len < 1)
        {
@@ -2131,11 +2130,6 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
                return (-1);
        }
 
-       /* Assured by plugin_value_list_clone(). The time is determined at
-        * _enqueue_ time. */
-       assert (vl->time != 0);
-       assert (vl->interval != 0);
-
        DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
                        "host = %s; "
                        "plugin = %s; plugin_instance = %s; "
@@ -2173,31 +2167,6 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
        escape_slashes (vl->type, sizeof (vl->type));
        escape_slashes (vl->type_instance, sizeof (vl->type_instance));
 
-       /* Copy the values. This way, we can assure `targets' that they get
-        * dynamically allocated values, which they can free and replace if
-        * they like. */
-       if ((pre_cache_chain != NULL) || (post_cache_chain != NULL))
-       {
-               saved_values     = vl->values;
-               saved_values_len = vl->values_len;
-
-               vl->values = (value_t *) calloc (vl->values_len,
-                               sizeof (*vl->values));
-               if (vl->values == NULL)
-               {
-                       ERROR ("plugin_dispatch_values: calloc failed.");
-                       vl->values = saved_values;
-                       return (-1);
-               }
-               memcpy (vl->values, saved_values,
-                               vl->values_len * sizeof (*vl->values));
-       }
-       else /* if ((pre == NULL) && (post == NULL)) */
-       {
-               saved_values     = NULL;
-               saved_values_len = 0;
-       }
-
        if (pre_cache_chain != NULL)
        {
                status = fc_process_chain (ds, vl, pre_cache_chain);
@@ -2209,17 +2178,7 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
                                        status, status);
                }
                else if (status == FC_TARGET_STOP)
-               {
-                       /* Restore the state of the value_list so that plugins
-                        * don't get confused.. */
-                       if (saved_values != NULL)
-                       {
-                               sfree (vl->values);
-                               vl->values     = saved_values;
-                               vl->values_len = saved_values_len;
-                       }
                        return (0);
-               }
        }
 
        /* Update the value cache */
@@ -2239,15 +2198,6 @@ static int plugin_dispatch_values_internal (value_list_t *vl)
        else
                fc_default_action (ds, vl);
 
-       /* Restore the state of the value_list so that plugins don't get
-        * confused.. */
-       if (saved_values != NULL)
-       {
-               sfree (vl->values);
-               vl->values     = saved_values;
-               vl->values_len = saved_values_len;
-       }
-
        if ((free_meta_data != 0) && (vl->meta != NULL))
        {
                meta_data_destroy (vl->meta);
index d3038a395ea5f1c6ec52ce9eff27d3667e8a53b4..5a4e4c75af12679c0c84c68b7b0892c5a7cc0c0a 100644 (file)
 /*
  * Public data types
  */
+struct identifier_s
+{
+       char *host;
+       char *plugin;
+       char *plugin_instance;
+       char *type;
+       char *type_instance;
+};
+typedef struct identifier_s identifier_t;
+
 typedef unsigned long long counter_t;
 typedef double gauge_t;
 typedef int64_t derive_t;
@@ -110,9 +120,7 @@ struct value_list_s
 };
 typedef struct value_list_s value_list_t;
 
-#define VALUE_LIST_INIT { NULL, 0, 0, plugin_get_interval (), \
-       "localhost", "", "", "", "", NULL }
-#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "", "", NULL }
+#define VALUE_LIST_INIT { .values = NULL, .meta = NULL }
 
 struct data_source_s
 {
index b6efa3ad788387528074efc38b258b6ef309b6dd..e01e2569429e3f10e91683f3bbd4df102af690b8 100644 (file)
@@ -57,6 +57,21 @@ int plugin_dispatch_values (value_list_t const *vl)
   return ENOTSUP;
 }
 
+int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier)
+{
+  return ENOTSUP;
+}
+
+static data_source_t magic_ds[] = {{ "value", DS_TYPE_DERIVE, 0.0, NAN }};
+static data_set_t magic = { "MAGIC", 1, magic_ds };
+const data_set_t *plugin_get_ds (const char *name)
+{
+  if (strcmp (name, "MAGIC"))
+    return NULL;
+
+  return &magic;
+}
+
 void plugin_log (int level, char const *format, ...)
 {
   char buffer[1024];
index 93c2519469f6f9436468719db5da0a49fc0fbdf1..e020429bee06c999b4fb0fd9faa3dc0ace21592c 100644 (file)
@@ -85,9 +85,9 @@ uc_iter_t *uc_get_iterator (void);
  *
  * PARAMETERS
  *   `iter'     The iterator object to advance.
- *   `ret_name' Pointer to a string where to store the name. The returned
- *              value is a copy of the value and has to be freed by the
- *              caller.
+ *   `ret_name' Optional pointer to a string where to store the name. If not
+ *              NULL, the returned value is a copy of the value and has to be
+ *              freed by the caller.
  *
  * RETURN VALUE
  *   Zero upon success or non-zero if the iterator ie NULL or no further
index 1080c806b8697a170c46eb3d834fa226e52481af..3a14d043274ad82cd847a1352974b1468c58b34b 100644 (file)
  */
 
 #include "utils_cache.h"
+#include <errno.h>
 
 gauge_t *uc_get_rate (__attribute__((unused)) data_set_t const *ds,
                       __attribute__((unused)) value_list_t const *vl)
 {
+  errno = ENOTSUP;
   return (NULL);
 }
+
+int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num)
+{
+  return (ENOTSUP);
+}
+
+int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
+{
+  return (ENOTSUP);
+}
index ffcaa90a118a131e7d727c46e68844670227f2e3..377336f6f18ee7dd022590f1183f32d50a3f6d9f 100644 (file)
@@ -88,7 +88,6 @@ static int simple_submit_match (cu_match_t *match, void *user_data)
 
   vl.values = values;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, data->plugin_instance,
       sizeof (vl.plugin_instance));
index 86476ea63b4cd95728cfd843a48b52d26859d979..a3a9c33ae78343a291d07fd5d6cddee572bf3d68 100644 (file)
@@ -54,10 +54,10 @@ cdtime_t cdtime (void) /* {{{ */
     char errbuf[1024];
     ERROR ("cdtime: clock_gettime failed: %s",
         sstrerror (errno, errbuf, sizeof (errbuf)));
-    return (0);
+    return 0;
   }
 
-  return (TIMESPEC_TO_CDTIME_T (&ts));
+  return TIMESPEC_TO_CDTIME_T (&ts);
 } /* }}} cdtime_t cdtime */
 # else /* !HAVE_CLOCK_GETTIME */
 /* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
@@ -72,14 +72,64 @@ cdtime_t cdtime (void) /* {{{ */
     char errbuf[1024];
     ERROR ("cdtime: gettimeofday failed: %s",
         sstrerror (errno, errbuf, sizeof (errbuf)));
-    return (0);
+    return 0;
   }
 
-  return (TIMEVAL_TO_CDTIME_T (&tv));
+  return TIMEVAL_TO_CDTIME_T (&tv);
 } /* }}} cdtime_t cdtime */
 # endif
 #endif
 
+/**********************************************************************
+ Time retrieval functions
+***********************************************************************/
+
+static int get_utc_time (cdtime_t t, struct tm *t_tm, long *nsec) /* {{{ */
+{
+  struct timespec t_spec;
+  int status;
+
+  CDTIME_T_TO_TIMESPEC (t, &t_spec);
+  NORMALIZE_TIMESPEC (t_spec);
+
+  if (gmtime_r (&t_spec.tv_sec, t_tm) == NULL) {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("get_utc_time: gmtime_r failed: %s",
+        sstrerror (status, errbuf, sizeof (errbuf)));
+    return status;
+  }
+
+  *nsec = t_spec.tv_nsec;
+  return 0;
+} /* }}} int get_utc_time */
+
+static int get_local_time (cdtime_t t, struct tm *t_tm, long *nsec) /* {{{ */
+{
+  struct timespec t_spec;
+  int status;
+
+  CDTIME_T_TO_TIMESPEC (t, &t_spec);
+  NORMALIZE_TIMESPEC (t_spec);
+
+  if (localtime_r (&t_spec.tv_sec, t_tm) == NULL) {
+    char errbuf[1024];
+    status = errno;
+    ERROR ("get_local_time: localtime_r failed: %s",
+        sstrerror (status, errbuf, sizeof (errbuf)));
+    return status;
+  }
+
+  *nsec = t_spec.tv_nsec;
+  return 0;
+} /* }}} int get_local_time */
+
+/**********************************************************************
+ Formatting functions
+***********************************************************************/
+
+static const char zulu_zone[] = "Z";
+
 /* format_zone reads time zone information from "extern long timezone", exported
  * by <time.h>, and formats it according to RFC 3339. This differs from
  * strftime()'s "%z" format by including a colon between hour and minute. */
@@ -112,60 +162,90 @@ static int format_zone (char *buffer, size_t buffer_size, struct tm const *tm) /
   return 0;
 } /* }}} int format_zone */
 
-static int format_rfc3339 (char *buffer, size_t buffer_size, cdtime_t t, _Bool print_nano) /* {{{ */
+int format_rfc3339 (char *buffer, size_t buffer_size, struct tm const *t_tm, long nsec, _Bool print_nano, char const *zone) /* {{{ */
+{
+  int len;
+  char *pos = buffer;
+  size_t size_left = buffer_size;
+
+  if ((len = strftime (pos, size_left, "%Y-%m-%dT%H:%M:%S", t_tm)) == 0)
+    return ENOMEM;
+  pos += len;
+  size_left -= len;
+
+  if (print_nano) {
+    if ((len = ssnprintf (pos, size_left, ".%09ld", nsec)) == 0)
+      return ENOMEM;
+    pos += len;
+    size_left -= len;
+  }
+
+  sstrncpy (pos, zone, size_left);
+  return 0;
+} /* }}} int format_rfc3339 */
+
+int format_rfc3339_utc (char *buffer, size_t buffer_size, cdtime_t t, _Bool print_nano) /* {{{ */
 {
-  struct timespec t_spec;
   struct tm t_tm;
-  char base[20]; /* 2006-01-02T15:04:05 */
-  char nano[11]; /* .999999999 */
-  char zone[7];  /* +00:00 */
-  char *fields[] = {base, nano, zone};
-  size_t len;
+  long nsec = 0;
   int status;
 
-  CDTIME_T_TO_TIMESPEC (t, &t_spec);
-  NORMALIZE_TIMESPEC (t_spec);
+  if ((status = get_utc_time (t, &t_tm, &nsec)) != 0)
+    return status;  /* The error should have already be reported. */
 
-  if (localtime_r (&t_spec.tv_sec, &t_tm) == NULL) {
-    char errbuf[1024];
-    status = errno;
-    ERROR ("format_rfc3339: localtime_r failed: %s",
-        sstrerror (status, errbuf, sizeof (errbuf)));
-    return (status);
-  }
+  return format_rfc3339 (buffer, buffer_size, &t_tm, nsec, print_nano, zulu_zone);
+} /* }}} int format_rfc3339_utc */
 
-  len = strftime (base, sizeof (base), "%Y-%m-%dT%H:%M:%S", &t_tm);
-  if (len == 0)
-    return ENOMEM;
+int format_rfc3339_local (char *buffer, size_t buffer_size, cdtime_t t, _Bool print_nano) /* {{{ */
+{
+  struct tm t_tm;
+  long nsec = 0;
+  int status;
+  char zone[7];  /* +00:00 */
 
-  if (print_nano)
-    ssnprintf (nano, sizeof (nano), ".%09ld", (long) t_spec.tv_nsec);
-  else
-    sstrncpy (nano, "", sizeof (nano));
+  if ((status = get_local_time (t, &t_tm, &nsec)) != 0)
+    return status;  /* The error should have already be reported. */
 
-  status = format_zone (zone, sizeof (zone), &t_tm);
-  if (status != 0)
+  if ((status = format_zone (zone, sizeof (zone), &t_tm)) != 0)
     return status;
 
-  if (strjoin (buffer, buffer_size, fields, STATIC_ARRAY_SIZE (fields), "") < 0)
-    return ENOMEM;
-  return 0;
-} /* }}} int format_rfc3339 */
+  return format_rfc3339 (buffer, buffer_size, &t_tm, nsec, print_nano, zone);
+} /* }}} int format_rfc3339_local */
+
+/**********************************************************************
+ Public functions
+***********************************************************************/
 
 int rfc3339 (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
 {
   if (buffer_size < RFC3339_SIZE)
     return ENOMEM;
 
-  return format_rfc3339 (buffer, buffer_size, t, 0);
-} /* }}} size_t cdtime_to_rfc3339 */
+  return format_rfc3339_utc (buffer, buffer_size, t, 0);
+} /* }}} int rfc3339 */
 
 int rfc3339nano (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
 {
   if (buffer_size < RFC3339NANO_SIZE)
     return ENOMEM;
 
-  return format_rfc3339 (buffer, buffer_size, t, 1);
-} /* }}} size_t cdtime_to_rfc3339nano */
+  return format_rfc3339_utc (buffer, buffer_size, t, 1);
+} /* }}} int rfc3339nano */
+
+int rfc3339_local (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
+{
+  if (buffer_size < RFC3339_SIZE)
+    return ENOMEM;
+
+  return format_rfc3339_local (buffer, buffer_size, t, 0);
+} /* }}} int rfc3339 */
+
+int rfc3339nano_local (char *buffer, size_t buffer_size, cdtime_t t) /* {{{ */
+{
+  if (buffer_size < RFC3339NANO_SIZE)
+    return ENOMEM;
+
+  return format_rfc3339_local (buffer, buffer_size, t, 1);
+} /* }}} int rfc3339nano */
 
 /* vim: set sw=2 sts=2 et fdm=marker : */
index 4d88dccb6684ec3f4c823f3429ce5a9455d35e1a..7834723917587a9e1837ef29a72e373f08c90f3d 100644 (file)
@@ -82,15 +82,24 @@ extern cdtime_t cdtime_mock;
 
 cdtime_t cdtime (void);
 
-#define RFC3339_SIZE     26
-#define RFC3339NANO_SIZE 36
+#define RFC3339_SIZE     26  /* 2006-01-02T15:04:05+00:00 */
+#define RFC3339NANO_SIZE 36  /* 2006-01-02T15:04:05.999999999+00:00 */
 
-/* rfc3339 formats a cdtime_t time in RFC 3339 format with second precision. */
+/* rfc3339 formats a cdtime_t time as UTC in RFC 3339 zulu format with second
+ * precision, e.g., "2006-01-02T15:04:05Z". */
 int rfc3339 (char *buffer, size_t buffer_size, cdtime_t t);
 
-/* rfc3339nano formats a cdtime_t time in RFC 3339 format with nanosecond
- * precision. */
+/* rfc3339nano formats a cdtime_t as UTC time in RFC 3339 zulu format with
+ * nanosecond precision, e.g., "2006-01-02T15:04:05.999999999Z". */
 int rfc3339nano (char *buffer, size_t buffer_size, cdtime_t t);
 
+/* rfc3339 formats a cdtime_t time as local in RFC 3339 format with second
+ * precision, e.g., "2006-01-02T15:04:05+00:00". */
+int rfc3339_local (char *buffer, size_t buffer_size, cdtime_t t);
+
+/* rfc3339nano formats a cdtime_t time as local in RFC 3339 format with
+ * nanosecond precision, e.g., "2006-01-02T15:04:05.999999999+00:00". */
+int rfc3339nano_local (char *buffer, size_t buffer_size, cdtime_t t);
+
 #endif /* UTILS_TIME_H */
 /* vim: set sw=2 sts=2 et : */
index 068bf4d2f014c0643c02240dcebe4abdd3336b34..fefbf87bcab0a4a101e6bd2a1f899a37394d3052 100644 (file)
--- a/src/dbi.c
+++ b/src/dbi.c
@@ -390,24 +390,19 @@ static int cdbi_config_add_database (oconfig_item_t *ci) /* {{{ */
     }
     else
     {
-      char *name = NULL;
-
       databases = temp;
       databases[databases_num] = db;
       databases_num++;
 
-      name = ssnprintf_alloc("dbi:%s", db->name);
-
-      user_data_t ud = {
-        .data = db
-      };
-
+      char *name = ssnprintf_alloc("dbi:%s", db->name);
       plugin_register_complex_read (/* group = */ NULL,
           /* name = */ name ? name : db->name,
           /* callback = */ cdbi_read_database,
           /* interval = */ (db->interval > 0) ? db->interval : 0,
-          /* user_data = */ &ud);
-      free (name);
+          &(user_data_t) {
+            .data = db,
+         });
+      sfree (name);
     }
   }
 
@@ -452,14 +447,14 @@ static int cdbi_init (void) /* {{{ */
   if (queries_num == 0)
   {
     ERROR ("dbi plugin: No <Query> blocks have been found. Without them, "
-        "this plugin can't do anything useful, so we will returns an error.");
+        "this plugin can't do anything useful, so we will return an error.");
     return (-1);
   }
 
   if (databases_num == 0)
   {
     ERROR ("dbi plugin: No <Database> blocks have been found. Without them, "
-        "this plugin can't do anything useful, so we will returns an error.");
+        "this plugin can't do anything useful, so we will return an error.");
     return (-1);
   }
 
index 4a86799c2e5d7ec7a3bbb6b3003bca8879eede0b..d9ffa8b16ab32203b51b1ab74179078d5c74f182 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -161,14 +161,10 @@ static void df_submit_one (char *plugin_instance,
                const char *type, const char *type_instance,
                gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "df", sizeof (vl.plugin));
        if (plugin_instance != NULL)
                sstrncpy (vl.plugin_instance, plugin_instance,
@@ -229,7 +225,10 @@ static int df_read (void)
                        }
 
                        /* Duplicate found: leave non-NULL dup_ptr. */
-                       if (by_device && (strcmp (mnt_ptr->spec_device, dup_ptr->spec_device) == 0))
+                       if (by_device
+                            && (mnt_ptr->spec_device != NULL)
+                            && (dup_ptr->spec_device != NULL)
+                            && (strcmp (mnt_ptr->spec_device, dup_ptr->spec_device) == 0))
                                break;
                        else if (!by_device && (strcmp (mnt_ptr->dir, dup_ptr->dir) == 0))
                                break;
index d7eb0a5c407011c9789ee2fe43e4d46f938e2414..a07288d13336958f232e9616f93e10084bedcf08 100644 (file)
@@ -128,7 +128,7 @@ static int numdisk = 0;
 /* #endif HAVE_LIBKSTAT */
 
 #elif defined(HAVE_LIBSTATGRAB)
-/* #endif HAVE_LIBKSTATGRAB */
+/* #endif HAVE_LIBSTATGRAB */
 
 #elif HAVE_PERFSTAT
 static perfstat_disk_t * stat_disk;
@@ -297,15 +297,14 @@ static void disk_submit (const char *plugin_instance,
                const char *type,
                derive_t read, derive_t write)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = read;
-       values[1].derive = write;
+       value_t values[] = {
+               { .derive = read },
+               { .derive = write },
+       };
 
        vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values_len = STATIC_ARRAY_SIZE (values);
        sstrncpy (vl.plugin, "disk", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
@@ -317,15 +316,14 @@ static void disk_submit (const char *plugin_instance,
 #if KERNEL_FREEBSD || KERNEL_LINUX
 static void submit_io_time (char const *plugin_instance, derive_t io_time, derive_t weighted_time)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = io_time;
-       values[1].derive = weighted_time;
+       value_t values[] = {
+               { .derive = io_time },
+               { .derive = weighted_time },
+       };
 
        vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values_len = STATIC_ARRAY_SIZE (values);
        sstrncpy (vl.plugin, "disk", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, "disk_io_time", sizeof (vl.type));
@@ -337,14 +335,10 @@ static void submit_io_time (char const *plugin_instance, derive_t io_time, deriv
 #if KERNEL_LINUX
 static void submit_in_progress (char const *disk_name, gauge_t in_progress)
 {
-       value_t v;
        value_list_t vl = VALUE_LIST_INIT;
 
-       v.gauge = in_progress;
-
-       vl.values = &v;
+       vl.values = &(value_t) { .gauge = in_progress };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "disk", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, disk_name, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, "pending_operations", sizeof (vl.type));
@@ -352,7 +346,6 @@ static void submit_in_progress (char const *disk_name, gauge_t in_progress)
        plugin_dispatch_values (&vl);
 }
 
-
 static counter_t disk_calc_time_incr (counter_t delta_time, counter_t delta_ops)
 {
        double interval = CDTIME_T_TO_DOUBLE (plugin_get_interval ());
index 0494b4baeb20494f3a00fdb629eb2d738b637077..04e5a1e6459671d04aab853256616514a3ad5a32 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -370,14 +370,10 @@ static int dns_init (void)
 static void submit_derive (const char *type, const char *type_instance,
                derive_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].derive = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .derive = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "dns", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
@@ -387,15 +383,14 @@ static void submit_derive (const char *type, const char *type_instance,
 
 static void submit_octets (derive_t queries, derive_t responses)
 {
-       value_t values[2];
+       value_t values[] = {
+          { .derive = queries },
+          { .derive = responses },
+        };
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].derive = queries;
-       values[1].derive = responses;
-
        vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values_len = STATIC_ARRAY_SIZE (values);
        sstrncpy (vl.plugin, "dns", sizeof (vl.plugin));
        sstrncpy (vl.type, "dns_octets", sizeof (vl.type));
 
diff --git a/src/dpdkstat.c b/src/dpdkstat.c
new file mode 100644 (file)
index 0000000..3c636f7
--- /dev/null
@@ -0,0 +1,782 @@
+/*-
+ * collectd - src/dpdkstat.c
+ * MIT License
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Maryam Tahhan <maryam.tahhan@intel.com>
+ *   Harry van Haaren <harry.van.haaren@intel.com>
+ */
+
+#include "collectd.h"
+
+#include "common.h" /* auxiliary functions */
+#include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
+#include "utils_time.h"
+
+#include <getopt.h>
+#include <semaphore.h>
+#include <sys/mman.h>
+#include <sys/queue.h>
+#include <poll.h>
+
+#include <rte_config.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_malloc.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_launch.h>
+#include <rte_tailq.h>
+#include <rte_lcore.h>
+#include <rte_per_lcore.h>
+#include <rte_debug.h>
+#include <rte_log.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_string_fns.h>
+
+#define DPDK_DEFAULT_RTE_CONFIG "/var/run/.rte_config"
+#define DPDK_MAX_ARGC 8
+#define DPDKSTAT_MAX_BUFFER_SIZE (4096 * 4)
+#define DPDK_SHM_NAME "dpdk_collectd_stats_shm"
+#define ERR_BUF_SIZE 1024
+#define REINIT_SHM 1
+#define RESET 1
+#define NO_RESET 0
+
+enum DPDK_HELPER_ACTION {
+  DPDK_HELPER_ACTION_COUNT_STATS,
+  DPDK_HELPER_ACTION_SEND_STATS,
+};
+
+enum DPDK_HELPER_STATUS {
+  DPDK_HELPER_NOT_INITIALIZED = 0,
+  DPDK_HELPER_WAITING_ON_PRIMARY,
+  DPDK_HELPER_INITIALIZING_EAL,
+  DPDK_HELPER_ALIVE_SENDING_STATS,
+  DPDK_HELPER_GRACEFUL_QUIT,
+};
+
+struct dpdk_config_s {
+  /* General DPDK params */
+  char coremask[DATA_MAX_NAME_LEN];
+  char memory_channels[DATA_MAX_NAME_LEN];
+  char socket_memory[DATA_MAX_NAME_LEN];
+  char process_type[DATA_MAX_NAME_LEN];
+  char file_prefix[DATA_MAX_NAME_LEN];
+  cdtime_t interval;
+  uint32_t eal_initialized;
+  uint32_t enabled_port_mask;
+  char port_name[RTE_MAX_ETHPORTS][DATA_MAX_NAME_LEN];
+  uint32_t eal_argc;
+  /* Helper info */
+  int collectd_reinit_shm;
+  pid_t helper_pid;
+  sem_t sema_helper_get_stats;
+  sem_t sema_stats_in_shm;
+  int helper_pipes[2];
+  enum DPDK_HELPER_STATUS helper_status;
+  enum DPDK_HELPER_ACTION helper_action;
+  /* xstats info */
+  uint32_t num_ports;
+  uint32_t num_xstats;
+  cdtime_t port_read_time[RTE_MAX_ETHPORTS];
+  uint32_t num_stats_in_port[RTE_MAX_ETHPORTS];
+  struct rte_eth_link link_status[RTE_MAX_ETHPORTS];
+  struct rte_eth_xstats *xstats;
+  /* rte_eth_xstats from here on until the end of the SHM */
+};
+typedef struct dpdk_config_s dpdk_config_t;
+
+static int g_configured;
+static dpdk_config_t *g_configuration;
+
+static void dpdk_config_init_default(void);
+static int dpdk_config(oconfig_item_t *ci);
+static int dpdk_helper_init_eal(void);
+static int dpdk_helper_run(void);
+static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action);
+static int dpdk_init(void);
+static int dpdk_read(user_data_t *ud);
+static int dpdk_shm_cleanup(void);
+static int dpdk_shm_init(size_t size);
+
+/* Write the default configuration to the g_configuration instances */
+static void dpdk_config_init_default(void) {
+  g_configuration->interval = plugin_get_interval();
+  if (g_configuration->interval == cf_get_default_interval())
+    WARNING("dpdkstat: No time interval was configured, default value %lu ms "
+            "is set",
+            CDTIME_T_TO_MS(g_configuration->interval));
+  /* Default is all ports enabled */
+  g_configuration->enabled_port_mask = ~0;
+  g_configuration->eal_argc = DPDK_MAX_ARGC;
+  g_configuration->eal_initialized = 0;
+  ssnprintf(g_configuration->coremask, DATA_MAX_NAME_LEN, "%s", "0xf");
+  ssnprintf(g_configuration->memory_channels, DATA_MAX_NAME_LEN, "%s", "1");
+  ssnprintf(g_configuration->process_type, DATA_MAX_NAME_LEN, "%s",
+            "secondary");
+  ssnprintf(g_configuration->file_prefix, DATA_MAX_NAME_LEN, "%s",
+            DPDK_DEFAULT_RTE_CONFIG);
+
+  for (int i = 0; i < RTE_MAX_ETHPORTS; i++)
+    g_configuration->port_name[i][0] = 0;
+}
+
+static int dpdk_config(oconfig_item_t *ci) {
+  int port_counter = 0;
+  /* Allocate g_configuration and
+   * initialize a POSIX SHared Memory (SHM) object.
+   */
+  int err = dpdk_shm_init(sizeof(dpdk_config_t));
+  if (err) {
+    char errbuf[ERR_BUF_SIZE];
+    ERROR("dpdkstat: error in shm_init, %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    return -1;
+  }
+
+  /* Set defaults for config, overwritten by loop if config item exists */
+  dpdk_config_init_default();
+
+  for (int i = 0; i < ci->children_num; i++) {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp("Coremask", child->key) == 0) {
+      cf_util_get_string_buffer(child, g_configuration->coremask,
+                                sizeof(g_configuration->coremask));
+      DEBUG("dpdkstat:COREMASK %s ", g_configuration->coremask);
+    } else if (strcasecmp("MemoryChannels", child->key) == 0) {
+      cf_util_get_string_buffer(child, g_configuration->memory_channels,
+                                sizeof(g_configuration->memory_channels));
+      DEBUG("dpdkstat:Memory Channels %s ", g_configuration->memory_channels);
+    } else if (strcasecmp("SocketMemory", child->key) == 0) {
+      cf_util_get_string_buffer(child, g_configuration->socket_memory,
+                                sizeof(g_configuration->memory_channels));
+      DEBUG("dpdkstat: socket mem %s ", g_configuration->socket_memory);
+    } else if (strcasecmp("ProcessType", child->key) == 0) {
+      cf_util_get_string_buffer(child, g_configuration->process_type,
+                                sizeof(g_configuration->process_type));
+      DEBUG("dpdkstat: proc type %s ", g_configuration->process_type);
+    } else if ((strcasecmp("FilePrefix", child->key) == 0) &&
+               (child->values[0].type == OCONFIG_TYPE_STRING)) {
+      ssnprintf(g_configuration->file_prefix, DATA_MAX_NAME_LEN,
+                "/var/run/.%s_config", child->values[0].value.string);
+      DEBUG("dpdkstat: file prefix %s ", g_configuration->file_prefix);
+    } else if ((strcasecmp("EnabledPortMask", child->key) == 0) &&
+               (child->values[0].type == OCONFIG_TYPE_NUMBER)) {
+      g_configuration->enabled_port_mask =
+          (uint32_t)child->values[0].value.number;
+      DEBUG("dpdkstat: Enabled Port Mask %u",
+            g_configuration->enabled_port_mask);
+    } else if (strcasecmp("PortName", child->key) == 0) {
+      cf_util_get_string_buffer(
+          child, g_configuration->port_name[port_counter],
+          sizeof(g_configuration->port_name[port_counter]));
+      DEBUG("dpdkstat: Port %d Name: %s ", port_counter,
+            g_configuration->port_name[port_counter]);
+      port_counter++;
+    } else {
+      WARNING("dpdkstat: The config option \"%s\" is unknown.", child->key);
+    }
+  }                 /* End for (int i = 0; i < ci->children_num; i++)*/
+  g_configured = 1; /* Bypass configuration in dpdk_shm_init(). */
+
+  return 0;
+}
+
+/*
+ * Allocate g_configuration and initialize SHared Memory (SHM)
+ * for config and helper process
+ */
+static int dpdk_shm_init(size_t size) {
+  /*
+   * Check if SHM is already configured: when config items are provided, the
+   * config function initializes SHM. If there is no config, then init() will
+   * just return.
+   */
+  if (g_configuration)
+    return 0;
+
+  char errbuf[ERR_BUF_SIZE];
+
+  /* Create and open a new object, or open an existing object. */
+  int fd = shm_open(DPDK_SHM_NAME, O_CREAT | O_TRUNC | O_RDWR, 0666);
+  if (fd < 0) {
+    WARNING("dpdkstat:Failed to open %s as SHM:%s", DPDK_SHM_NAME,
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+    goto fail;
+  }
+  /* Set the size of the shared memory object. */
+  int ret = ftruncate(fd, size);
+  if (ret != 0) {
+    WARNING("dpdkstat:Failed to resize SHM:%s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+    goto fail_close;
+  }
+  /* Map the shared memory object into this process' virtual address space. */
+  g_configuration = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (g_configuration == MAP_FAILED) {
+    WARNING("dpdkstat:Failed to mmap SHM:%s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+    goto fail_close;
+  }
+  /*
+   * Close the file descriptor, the shared memory object still exists
+   * and can only be removed by calling shm_unlink().
+   */
+  close(fd);
+
+  /* Initialize g_configuration. */
+  memset(g_configuration, 0, size);
+
+  /* Initialize the semaphores for SHM use */
+  int err = sem_init(&g_configuration->sema_helper_get_stats, 1, 0);
+  if (err) {
+    ERROR("dpdkstat semaphore init failed: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    goto fail_close;
+  }
+  err = sem_init(&g_configuration->sema_stats_in_shm, 1, 0);
+  if (err) {
+    ERROR("dpdkstat semaphore init failed: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    goto fail_close;
+  }
+
+  g_configuration->xstats = NULL;
+
+  return 0;
+
+fail_close:
+  close(fd);
+fail:
+  /* Reset to zero, as it was set to MAP_FAILED aka: (void *)-1. Avoid
+   * an issue if collectd attempts to run this plugin failure.
+   */
+  g_configuration = 0;
+  return -1;
+}
+
+static int dpdk_re_init_shm() {
+  dpdk_config_t temp_config;
+  memcpy(&temp_config, g_configuration, sizeof(dpdk_config_t));
+  DEBUG("dpdkstat: %s: ports %" PRIu32 ", xstats %" PRIu32, __func__,
+        temp_config.num_ports, temp_config.num_xstats);
+
+  size_t shm_xstats_size =
+      sizeof(dpdk_config_t) +
+      (sizeof(struct rte_eth_xstats) * g_configuration->num_xstats);
+  DEBUG("=== SHM new size for %" PRIu32 " xstats", g_configuration->num_xstats);
+
+  int err = dpdk_shm_cleanup();
+  if (err) {
+    ERROR("dpdkstat: Error in shm_cleanup in %s", __func__);
+    return err;
+  }
+  err = dpdk_shm_init(shm_xstats_size);
+  if (err) {
+    WARNING("dpdkstat: Error in shm_init in %s", __func__);
+    return err;
+  }
+  /* If the XML config() function has been run, don't re-initialize defaults */
+  if (!g_configured)
+    dpdk_config_init_default();
+
+  memcpy(g_configuration, &temp_config, sizeof(dpdk_config_t));
+  g_configuration->collectd_reinit_shm = 0;
+  g_configuration->xstats = (struct rte_eth_xstats *)(g_configuration + 1);
+  return 0;
+}
+
+static int dpdk_init(void) {
+  int err = dpdk_shm_init(sizeof(dpdk_config_t));
+  if (err) {
+    ERROR("dpdkstat: %s : error %d in shm_init()", __func__, err);
+    return err;
+  }
+
+  /* If the XML config() function has been run, dont re-initialize defaults */
+  if (!g_configured) {
+    dpdk_config_init_default();
+  }
+
+  return 0;
+}
+
+static int dpdk_helper_stop(int reset) {
+  g_configuration->helper_status = DPDK_HELPER_GRACEFUL_QUIT;
+  if (reset) {
+    g_configuration->eal_initialized = 0;
+    g_configuration->num_ports = 0;
+    g_configuration->xstats = NULL;
+    g_configuration->num_xstats = 0;
+    for (int i = 0; i < RTE_MAX_ETHPORTS; i++)
+      g_configuration->num_stats_in_port[i] = 0;
+  }
+  close(g_configuration->helper_pipes[1]);
+  int err = kill(g_configuration->helper_pid, SIGKILL);
+  if (err) {
+    char errbuf[ERR_BUF_SIZE];
+    WARNING("dpdkstat: error sending kill to helper: %s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+  }
+
+  return 0;
+}
+
+static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action) {
+  char errbuf[ERR_BUF_SIZE];
+  g_configuration->eal_initialized = 0;
+  g_configuration->helper_action = action;
+  /*
+   * Create a pipe for helper stdout back to collectd. This is necessary for
+   * logging EAL failures, as rte_eal_init() calls rte_panic().
+   */
+  if (pipe(g_configuration->helper_pipes) != 0) {
+    DEBUG("dpdkstat: Could not create helper pipe: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    return -1;
+  }
+
+  int pipe0_flags = fcntl(g_configuration->helper_pipes[0], F_GETFL, 0);
+  int pipe1_flags = fcntl(g_configuration->helper_pipes[1], F_GETFL, 0);
+  if (pipe0_flags == -1 || pipe1_flags == -1) {
+    WARNING("dpdkstat: Failed setting up pipe flags: %s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+  }
+  int pipe0_err = fcntl(g_configuration->helper_pipes[0], F_SETFL,
+                        pipe1_flags | O_NONBLOCK);
+  int pipe1_err = fcntl(g_configuration->helper_pipes[1], F_SETFL,
+                        pipe0_flags | O_NONBLOCK);
+  if (pipe0_err == -1 || pipe1_err == -1) {
+    WARNING("dpdkstat: Failed setting up pipes: %s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+  }
+
+  pid_t pid = fork();
+  if (pid > 0) {
+    close(g_configuration->helper_pipes[1]);
+    g_configuration->helper_pid = pid;
+    DEBUG("dpdkstat: helper pid %lu", (long)g_configuration->helper_pid);
+    /* Kick helper once its alive to have it start processing */
+    sem_post(&g_configuration->sema_helper_get_stats);
+  } else if (pid == 0) {
+    /* Replace stdout with a pipe to collectd. */
+    close(g_configuration->helper_pipes[0]);
+    close(STDOUT_FILENO);
+    dup2(g_configuration->helper_pipes[1], STDOUT_FILENO);
+    dpdk_helper_run();
+    exit(0);
+  } else {
+    ERROR("dpdkstat: Failed to fork helper process: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    return -1;
+  }
+  return 0;
+}
+
+/*
+ * Initialize the DPDK EAL, if this returns, EAL is successfully initialized.
+ * On failure, the EAL prints an error message, and the helper process exits.
+ */
+static int dpdk_helper_init_eal(void) {
+  g_configuration->helper_status = DPDK_HELPER_INITIALIZING_EAL;
+  char *argp[(g_configuration->eal_argc) + 1];
+  int i = 0;
+
+  argp[i++] = "collectd-dpdk";
+  if (strcasecmp(g_configuration->coremask, "") != 0) {
+    argp[i++] = "-c";
+    argp[i++] = g_configuration->coremask;
+  }
+  if (strcasecmp(g_configuration->memory_channels, "") != 0) {
+    argp[i++] = "-n";
+    argp[i++] = g_configuration->memory_channels;
+  }
+  if (strcasecmp(g_configuration->socket_memory, "") != 0) {
+    argp[i++] = "--socket-mem";
+    argp[i++] = g_configuration->socket_memory;
+  }
+  if (strcasecmp(g_configuration->file_prefix, "") != 0 &&
+      strcasecmp(g_configuration->file_prefix, DPDK_DEFAULT_RTE_CONFIG) != 0) {
+    argp[i++] = "--file-prefix";
+    argp[i++] = g_configuration->file_prefix;
+  }
+  if (strcasecmp(g_configuration->process_type, "") != 0) {
+    argp[i++] = "--proc-type";
+    argp[i++] = g_configuration->process_type;
+  }
+  g_configuration->eal_argc = i;
+
+  g_configuration->eal_initialized = 1;
+  int ret = rte_eal_init(g_configuration->eal_argc, argp);
+  if (ret < 0) {
+    g_configuration->eal_initialized = 0;
+    return ret;
+  }
+  return 0;
+}
+
+static int dpdk_helper_run(void) {
+  char errbuf[ERR_BUF_SIZE];
+  pid_t ppid = getppid();
+  g_configuration->helper_status = DPDK_HELPER_WAITING_ON_PRIMARY;
+
+  while (1) {
+    /* sem_timedwait() to avoid blocking forever */
+    struct timespec ts;
+    cdtime_t now = cdtime();
+    cdtime_t safety_period = MS_TO_CDTIME_T(1500);
+    CDTIME_T_TO_TIMESPEC(now + safety_period + g_configuration->interval * 2,
+                         &ts);
+    int ret = sem_timedwait(&g_configuration->sema_helper_get_stats, &ts);
+
+    if (ret == -1 && errno == ETIMEDOUT) {
+      ERROR("dpdkstat-helper: sem timedwait()"
+            " timeout, did collectd terminate?");
+      dpdk_helper_stop(RESET);
+    }
+    /* Parent PID change means collectd died so quit the helper process. */
+    if (ppid != getppid()) {
+      WARNING("dpdkstat-helper: parent PID changed, quitting.");
+      dpdk_helper_stop(RESET);
+    }
+
+    /* Checking for DPDK primary process. */
+    if (!rte_eal_primary_proc_alive(g_configuration->file_prefix)) {
+      if (g_configuration->eal_initialized) {
+        WARNING("dpdkstat-helper: no primary alive but EAL initialized:"
+                " quitting.");
+        dpdk_helper_stop(RESET);
+      }
+      g_configuration->helper_status = DPDK_HELPER_WAITING_ON_PRIMARY;
+      /* Back to start of while() - waiting for primary process */
+      continue;
+    }
+
+    if (!g_configuration->eal_initialized) {
+      /* Initialize EAL. */
+      int ret = dpdk_helper_init_eal();
+      if (ret != 0) {
+        WARNING("ERROR INITIALIZING EAL");
+        dpdk_helper_stop(RESET);
+      }
+    }
+
+    g_configuration->helper_status = DPDK_HELPER_ALIVE_SENDING_STATS;
+
+    uint8_t nb_ports = rte_eth_dev_count();
+    if (nb_ports == 0) {
+      DEBUG("dpdkstat-helper: No DPDK ports available. "
+            "Check bound devices to DPDK driver.");
+      dpdk_helper_stop(RESET);
+    }
+
+    if (nb_ports > RTE_MAX_ETHPORTS)
+      nb_ports = RTE_MAX_ETHPORTS;
+
+    int len = 0, enabled_port_count = 0, num_xstats = 0;
+    for (uint8_t i = 0; i < nb_ports; i++) {
+      if (!(g_configuration->enabled_port_mask & (1 << i)))
+        continue;
+
+      if (g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) {
+        len = rte_eth_xstats_get(i, NULL, 0);
+        if (len < 0) {
+          ERROR("dpdkstat-helper: Cannot get xstats count on port %" PRIu8, i);
+          break;
+        }
+        num_xstats += len;
+        g_configuration->num_stats_in_port[enabled_port_count] = len;
+        enabled_port_count++;
+        continue;
+      } else {
+        len = g_configuration->num_stats_in_port[enabled_port_count];
+        g_configuration->port_read_time[enabled_port_count] = cdtime();
+        ret = rte_eth_xstats_get(
+            i, g_configuration->xstats + num_xstats,
+            g_configuration->num_stats_in_port[enabled_port_count]);
+        if (ret < 0 || ret != len) {
+          DEBUG("dpdkstat-helper: Error reading xstats on port %" PRIu8
+                " len = %d",
+                i, len);
+          break;
+        }
+        num_xstats += g_configuration->num_stats_in_port[enabled_port_count];
+        enabled_port_count++;
+      }
+    } /* for (nb_ports) */
+
+    if (g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) {
+      g_configuration->num_ports = enabled_port_count;
+      g_configuration->num_xstats = num_xstats;
+      DEBUG("dpdkstat-helper ports: %" PRIu32 ", num stats: %" PRIu32,
+            g_configuration->num_ports, g_configuration->num_xstats);
+      /* Exit, allowing collectd to re-init SHM to the right size */
+      g_configuration->collectd_reinit_shm = REINIT_SHM;
+      dpdk_helper_stop(NO_RESET);
+    }
+    /* Now kick collectd send thread to send the stats */
+    int err = sem_post(&g_configuration->sema_stats_in_shm);
+    if (err) {
+      WARNING("dpdkstat: error posting semaphore to helper %s",
+              sstrerror(errno, errbuf, sizeof(errbuf)));
+      dpdk_helper_stop(RESET);
+    }
+  } /* while(1) */
+
+  return 0;
+}
+
+static void dpdk_submit_xstats(const char *dev_name,
+                               const struct rte_eth_xstats *xstats,
+                               uint32_t counters, cdtime_t port_read_time) {
+  for (uint32_t j = 0; j < counters; j++) {
+    value_list_t vl = VALUE_LIST_INIT;
+    char *type_end;
+
+    vl.values = &(value_t){.derive = (derive_t)xstats[j].value};
+    vl.values_len = 1; /* Submit stats one at a time */
+    vl.time = port_read_time;
+    sstrncpy(vl.plugin, "dpdkstat", sizeof(vl.plugin));
+    sstrncpy(vl.plugin_instance, dev_name,
+             sizeof(vl.plugin_instance));
+
+    type_end = strrchr(xstats[j].name, '_');
+
+    if ((type_end != NULL) &&
+        (strncmp(xstats[j].name, "rx_", strlen("rx_")) == 0)) {
+      if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+        sstrncpy(vl.type, "if_rx_errors", sizeof(vl.type));
+      } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) {
+        sstrncpy(vl.type, "if_rx_dropped", sizeof(vl.type));
+      } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) {
+        sstrncpy(vl.type, "if_rx_octets", sizeof(vl.type));
+      } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) {
+        sstrncpy(vl.type, "if_rx_packets", sizeof(vl.type));
+      } else if (strncmp(type_end, "_placement", strlen("_placement")) == 0) {
+        sstrncpy(vl.type, "if_rx_errors", sizeof(vl.type));
+      } else if (strncmp(type_end, "_buff", strlen("_buff")) == 0) {
+        sstrncpy(vl.type, "if_rx_errors", sizeof(vl.type));
+      } else {
+        /* Does not fit obvious type: use a more generic one */
+        sstrncpy(vl.type, "derive", sizeof(vl.type));
+      }
+
+    } else if ((type_end != NULL) &&
+               (strncmp(xstats[j].name, "tx_", strlen("tx_"))) == 0) {
+      if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+        sstrncpy(vl.type, "if_tx_errors", sizeof(vl.type));
+      } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) {
+        sstrncpy(vl.type, "if_tx_dropped", sizeof(vl.type));
+      } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) {
+        sstrncpy(vl.type, "if_tx_octets", sizeof(vl.type));
+      } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) {
+        sstrncpy(vl.type, "if_tx_packets", sizeof(vl.type));
+      } else {
+        /* Does not fit obvious type: use a more generic one */
+        sstrncpy(vl.type, "derive", sizeof(vl.type));
+      }
+    } else if ((type_end != NULL) &&
+               (strncmp(xstats[j].name, "flow_", strlen("flow_"))) == 0) {
+
+      if (strncmp(type_end, "_filters", strlen("_filters")) == 0) {
+        sstrncpy(vl.type, "operations", sizeof(vl.type));
+      } else if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+        sstrncpy(vl.type, "errors", sizeof(vl.type));
+      } else if (strncmp(type_end, "_filters", strlen("_filters")) == 0) {
+        sstrncpy(vl.type, "filter_result", sizeof(vl.type));
+      }
+    } else if ((type_end != NULL) &&
+               (strncmp(xstats[j].name, "mac_", strlen("mac_"))) == 0) {
+      if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+        sstrncpy(vl.type, "errors", sizeof(vl.type));
+      }
+    } else {
+      /* Does not fit obvious type, or strrchr error:
+       *   use a more generic type */
+      sstrncpy(vl.type, "derive", sizeof(vl.type));
+    }
+
+    sstrncpy(vl.type_instance, xstats[j].name,
+             sizeof(vl.type_instance));
+    plugin_dispatch_values(&vl);
+  }
+}
+
+static int dpdk_read(user_data_t *ud) {
+  int ret = 0;
+
+  /*
+   * Check if SHM flag is set to be re-initialized. AKA DPDK ports have been
+   * counted, so re-init SHM to be large enough to fit all the statistics.
+   */
+  if (g_configuration->collectd_reinit_shm) {
+    DEBUG("dpdkstat: read() now reinit SHM then launching send-thread");
+    dpdk_re_init_shm();
+  }
+
+  /*
+   * Check if DPDK proc is alive, and has already counted port / stats. This
+   * must be done in dpdk_read(), because the DPDK primary process may not be
+   * alive at dpdk_init() time.
+   */
+  if (g_configuration->helper_status == DPDK_HELPER_NOT_INITIALIZED ||
+      g_configuration->helper_status == DPDK_HELPER_GRACEFUL_QUIT) {
+    int action = DPDK_HELPER_ACTION_SEND_STATS;
+    if (g_configuration->num_xstats == 0)
+      action = DPDK_HELPER_ACTION_COUNT_STATS;
+    /* Spawn the helper thread to count stats or to read stats. */
+    int err = dpdk_helper_spawn(action);
+    if (err) {
+      char errbuf[ERR_BUF_SIZE];
+      ERROR("dpdkstat: error spawning helper %s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+      return -1;
+    }
+  }
+
+  pid_t ws = waitpid(g_configuration->helper_pid, NULL, WNOHANG);
+  /*
+   * Conditions under which to respawn helper:
+   *  waitpid() fails, helper process died (or quit), so respawn
+   */
+  _Bool respawn_helper = 0;
+  if (ws != 0) {
+    respawn_helper = 1;
+  }
+
+  char buf[DPDKSTAT_MAX_BUFFER_SIZE];
+  char out[DPDKSTAT_MAX_BUFFER_SIZE];
+
+  /* non blocking check on helper logging pipe */
+  struct pollfd fds = {
+      .fd = g_configuration->helper_pipes[0], .events = POLLIN,
+  };
+  int data_avail = poll(&fds, 1, 0);
+  if (data_avail < 0) {
+    char errbuf[ERR_BUF_SIZE];
+    if (errno != EINTR || errno != EAGAIN)
+      ERROR("dpdkstats: poll(2) failed: %s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+  }
+  while (data_avail) {
+    int nbytes = read(g_configuration->helper_pipes[0], buf, sizeof(buf));
+    if (nbytes <= 0)
+      break;
+    ssnprintf(out, nbytes, "%s", buf);
+    DEBUG("dpdkstat: helper-proc: %s", out);
+  }
+
+  if (respawn_helper) {
+    if (g_configuration->helper_pid)
+      dpdk_helper_stop(RESET);
+    dpdk_helper_spawn(DPDK_HELPER_ACTION_COUNT_STATS);
+  }
+
+  /* Kick helper process through SHM */
+  sem_post(&g_configuration->sema_helper_get_stats);
+
+  struct timespec ts;
+  cdtime_t now = cdtime();
+  CDTIME_T_TO_TIMESPEC(now + g_configuration->interval, &ts);
+  ret = sem_timedwait(&g_configuration->sema_stats_in_shm, &ts);
+  if (ret == -1) {
+    if (errno == ETIMEDOUT)
+      DEBUG(
+          "dpdkstat: timeout in collectd thread: is a DPDK Primary running? ");
+    return 0;
+  }
+
+  /* Dispatch the stats.*/
+  uint32_t count = 0, port_num = 0;
+
+  for (uint32_t i = 0; i < g_configuration->num_ports; i++) {
+    char dev_name[64];
+    cdtime_t port_read_time = g_configuration->port_read_time[i];
+    uint32_t counters_num = g_configuration->num_stats_in_port[i];
+    size_t ports_max = CHAR_BIT * sizeof(g_configuration->enabled_port_mask);
+    for (size_t j = port_num; j < ports_max; j++) {
+      if ((g_configuration->enabled_port_mask & (1 << j)) != 0)
+        break;
+      port_num++;
+    }
+
+    if (g_configuration->port_name[i][0] != 0)
+      ssnprintf(dev_name, sizeof(dev_name), "%s",
+                g_configuration->port_name[i]);
+    else
+      ssnprintf(dev_name, sizeof(dev_name), "port.%" PRIu32, port_num);
+    struct rte_eth_xstats *xstats = g_configuration->xstats + count;
+
+    dpdk_submit_xstats(dev_name, xstats, counters_num, port_read_time);
+    count += counters_num;
+    port_num++;
+  } /* for each port */
+  return 0;
+}
+
+static int dpdk_shm_cleanup(void) {
+  int ret = munmap(g_configuration, sizeof(dpdk_config_t));
+  g_configuration = 0;
+  if (ret) {
+    ERROR("dpdkstat: munmap returned %d", ret);
+    return ret;
+  }
+  ret = shm_unlink(DPDK_SHM_NAME);
+  if (ret) {
+    ERROR("dpdkstat: shm_unlink returned %d", ret);
+    return ret;
+  }
+  return 0;
+}
+
+static int dpdk_shutdown(void) {
+  int ret = 0;
+  char errbuf[ERR_BUF_SIZE];
+  close(g_configuration->helper_pipes[1]);
+  int err = kill(g_configuration->helper_pid, SIGKILL);
+  if (err) {
+    ERROR("dpdkstat: error sending sigkill to helper %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    ret = -1;
+  }
+  err = dpdk_shm_cleanup();
+  if (err) {
+    ERROR("dpdkstat: error cleaning up SHM: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    ret = -1;
+  }
+
+  return ret;
+}
+
+void module_register(void) {
+  plugin_register_complex_config("dpdkstat", dpdk_config);
+  plugin_register_init("dpdkstat", dpdk_init);
+  plugin_register_complex_read(NULL, "dpdkstat", dpdk_read, 0, NULL);
+  plugin_register_shutdown("dpdkstat", dpdk_shutdown);
+}
index 70f03cab280ce8426cbaaa99ea8c2f20d244fa4b..40a3eb22fa851b9d969683e8413c37053a640b79 100644 (file)
@@ -101,7 +101,6 @@ static int drbd_submit_fields (long int resource,
        }
 
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "drbd", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
index 2662da9e3590f83832c321355e353d016afa59d1..1027eb90ad1fed60e77219fa8b71dc399ab315e7 100644 (file)
@@ -653,14 +653,10 @@ static int email_shutdown (void)
 
 static void email_submit (const char *type, const char *type_instance, gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "email", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
index f4f4ac4a916c2952ba92ab94af2a890660c72de6..02ea9e113b5b34af4fb6fa3a0d3a157a7fab2274 100644 (file)
 
 #define ENTROPY_FILE "/proc/sys/kernel/random/entropy_avail"
 
-static void entropy_submit (double entropy)
+static void entropy_submit (value_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = entropy;
-
-       vl.values = values;
+       vl.values = &value;
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "entropy", sizeof (vl.plugin));
        sstrncpy (vl.type, "entropy", sizeof (vl.type));
 
@@ -53,26 +49,14 @@ static void entropy_submit (double entropy)
 
 static int entropy_read (void)
 {
-       double entropy;
-       FILE *fh;
-       char buffer[64];
-
-       fh = fopen (ENTROPY_FILE, "r");
-       if (fh == NULL)
-               return (-1);
-
-       if (fgets (buffer, sizeof (buffer), fh) == NULL)
+       value_t v;
+       if (parse_value_file (ENTROPY_FILE, &v, DS_TYPE_GAUGE) != 0)
        {
-               fclose (fh);
+               ERROR ("entropy plugin: Reading \""ENTROPY_FILE"\" failed.");
                return (-1);
        }
-       fclose (fh);
-
-       entropy = atof (buffer);
-       
-       if (entropy > 0.0)
-               entropy_submit (entropy);
 
+       entropy_submit (v);
        return (0);
 }
 
index d0e77281e69b5d9ff4ff0d1c406a3aaa12b81e8c..6dccb45f14fb7afe536cd8dc5807b5dd6b56ecca 100644 (file)
@@ -172,7 +172,6 @@ static void ethstat_submit_value (const char *device,
 {
   static c_complain_t complain_no_map = C_COMPLAIN_INIT_STATIC;
 
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
   value_map_t *map = NULL;
 
@@ -189,11 +188,9 @@ static void ethstat_submit_value (const char *device,
     return;
   }
 
-  values[0].derive = value;
-  vl.values = values;
+  vl.values = &(value_t) { .derive = value };
   vl.values_len = 1;
 
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "ethstat", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, device, sizeof (vl.plugin_instance));
   if (map != NULL)
index dfd4b05f59a95fc5409ab8b6a86aaba00b49df59..fc40d4a9eff65e1d1300e2160466e9e6d01402b9 100644 (file)
@@ -274,7 +274,7 @@ static void set_environment (void) /* {{{ */
       CDTIME_T_TO_DOUBLE (plugin_get_interval ()));
   setenv ("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1);
 
-  ssnprintf (buffer, sizeof (buffer), "%s", hostname_g);
+  sstrncpy (buffer, hostname_g, sizeof (buffer));
   setenv ("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1);
 #else
   ssnprintf (buffer, sizeof (buffer), "COLLECTD_INTERVAL=%.3f",
@@ -547,7 +547,7 @@ failed:
 static int parse_line (char *buffer) /* {{{ */
 {
   if (strncasecmp ("PUTVAL", buffer, strlen ("PUTVAL")) == 0)
-    return (handle_putval (stdout, buffer));
+    return (cmd_handle_putval (stdout, buffer));
   else if (strncasecmp ("PUTNOTIF", buffer, strlen ("PUTNOTIF")) == 0)
     return (handle_putnotif (stdout, buffer));
   else
index 4b3abff7276502efca4c9697b788a2770561ce41..00bd7325a53da8ec48623cb49c612784b9e6a83f 100644 (file)
@@ -60,17 +60,12 @@ static int fhcount_config(const char *key, const char *value) {
 
 static void fhcount_submit(
     const char *type, const char *type_instance, gauge_t value) {
-
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
 
   // Compose the metric
-  sstrncpy(vl.host, hostname_g, sizeof(vl.host));
   sstrncpy(vl.plugin, "fhcount", sizeof(vl.plugin));
   sstrncpy(vl.type, type, sizeof(vl.type));
   sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
@@ -79,7 +74,6 @@ static void fhcount_submit(
   plugin_dispatch_values(&vl);
 }
 
-
 static int fhcount_read(void) {
   int numfields = 0;
   int buffer_len = 60;
index 9de9e6c53a5fced05d2d8ead5c1297a29195476a..74bc5fb3828bf3006235b47d77c2ea45c14d9a64 100644 (file)
@@ -61,21 +61,17 @@ static size_t directories_num = 0;
 
 static void fc_submit_dir (const fc_directory_conf_t *dir)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = (gauge_t) dir->files_num;
-
-  vl.values = values;
-  vl.values_len = STATIC_ARRAY_SIZE (values);
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  vl.values = &(value_t) { .gauge = (gauge_t) dir->files_num };
+  vl.values_len = 1;
   sstrncpy (vl.plugin, "filecount", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, dir->instance, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, "files", sizeof (vl.type));
 
   plugin_dispatch_values (&vl);
 
-  values[0].gauge = (gauge_t) dir->files_size;
+  vl.values = &(value_t) { .gauge = (gauge_t) dir->files_size };
   sstrncpy (vl.type, "bytes", sizeof (vl.type));
 
   plugin_dispatch_values (&vl);
index 33633d63247db02deb1c7a909d228557b90184c2..3a5baf5bb11e1eac7ca367227a32a52bf3d80a62 100644 (file)
@@ -115,7 +115,6 @@ static void fscache_submit (const char *section, const char *name,
     vl.values = &value;
     vl.values_len = 1;
 
-    sstrncpy(vl.host, hostname_g, sizeof (vl.host));
     sstrncpy(vl.plugin, "fscache", sizeof (vl.plugin));
     sstrncpy(vl.plugin_instance, section, sizeof (vl.plugin_instance));
     sstrncpy(vl.type, "fscache_stat", sizeof(vl.type));
index f72cef4961bfa860f2481b0663ce822a36f592ad..644967b3b7ec79c2bc4e2c977138dd34086041b3 100644 (file)
--- a/src/gps.c
+++ b/src/gps.c
@@ -220,14 +220,10 @@ quit:
  */
 static void cgps_submit (const char *type, gauge_t value, const char *type_instance)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "gps", sizeof (vl.plugin));
   sstrncpy (vl.type, type, sizeof (vl.type));
   sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
index 8b76954d6748090a795d2eaf09fcfe7a8110f7c0..0ae80bb898fa8d00ebd63e7714a7797c670f5c84 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/grpc.cc
  * Copyright (C) 2015-2016 Sebastian Harl
+ * Copyright (C) 2016      Florian octo Forster
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -22,6 +23,7 @@
  *
  * Authors:
  *   Sebastian Harl <sh at tokkee.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include <grpc++/grpc++.h>
@@ -47,8 +49,8 @@ extern "C" {
 
 using collectd::Collectd;
 
-using collectd::DispatchValuesRequest;
-using collectd::DispatchValuesResponse;
+using collectd::PutValuesRequest;
+using collectd::PutValuesResponse;
 using collectd::QueryValuesRequest;
 using collectd::QueryValuesResponse;
 
@@ -283,13 +285,13 @@ public:
                return status;
        }
 
-       grpc::Status DispatchValues(grpc::ServerContext *ctx,
-                                                               grpc::ServerReader<DispatchValuesRequest> *reader,
-                                                               DispatchValuesResponse *res) override {
-               DispatchValuesRequest req;
+       grpc::Status PutValues(grpc::ServerContext *ctx,
+                                                  grpc::ServerReader<PutValuesRequest> *reader,
+                                                  PutValuesResponse *res) override {
+               PutValuesRequest req;
 
                while (reader->Read(&req)) {
-                       value_list_t vl = VALUE_LIST_INIT;
+                       value_list_t vl = {0};
                        auto status = unmarshal_value_list(req.value_list(), &vl);
                        if (!status.ok())
                                return status;
@@ -426,18 +428,18 @@ public:
        CollectdClient(std::shared_ptr<grpc::ChannelInterface> channel) : stub_(Collectd::NewStub(channel)) {
        }
 
-       int DispatchValues(value_list_t const *vl) {
+       int PutValues(value_list_t const *vl) {
                grpc::ClientContext ctx;
 
-               DispatchValuesRequest req;
+               PutValuesRequest req;
                auto status = marshal_value_list(vl, req.mutable_value_list());
                if (!status.ok()) {
                        ERROR("grpc: Marshalling value_list_t failed.");
                        return -1;
                }
 
-               DispatchValuesResponse res;
-               auto stream = stub_->DispatchValues(&ctx, &res);
+               PutValuesResponse res;
+               auto stream = stub_->PutValues(&ctx, &res);
                if (!stream->Write(req)) {
                        NOTICE("grpc: Broken stream.");
                        /* intentionally not returning. */
@@ -451,7 +453,7 @@ public:
                }
 
                return 0;
-       } /* int DispatchValues */
+       } /* int PutValues */
 
 private:
        std::unique_ptr<Collectd::Stub> stub_;
@@ -471,7 +473,7 @@ extern "C" {
                        value_list_t const *vl,
                        user_data_t *ud) {
                CollectdClient *c = (CollectdClient *) ud->data;
-               return c->DispatchValues(vl);
+               return c->PutValues(vl);
        }
 
        static int c_grpc_config_listen(oconfig_item_t *ci)
index 865ea8614afda35cee5993eeec8cf61e86c6f8b6..cb6f6d25b9a486d39a3b18c5c1f9e559e7401e53 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) 2005,2006  Vincent Stehlé
  * Copyright (C) 2006-2010  Florian octo Forster
  * Copyright (C) 2008       Sebastian Harl
+ * Copyright (C) 2014       Carnegie Mellon University
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -22,6 +23,7 @@
  *   Vincent Stehlé <vincent.stehle at free.fr>
  *   Florian octo Forster <octo at collectd.org>
  *   Sebastian Harl <sh at tokkee.org>
+ *   Benjamin Gilbert <bgilbert at backtick.net>
  *
  * TODO:
  *   Do a pass, some day, and spare some memory. We consume too much for now
@@ -38,6 +40,7 @@
 # include <netinet/in.h>
 # include <netinet/tcp.h>
 # include <libgen.h> /* for basename */
+# include <assert.h>
 
 #if HAVE_LINUX_MAJOR_H
 # include <linux/major.h>
@@ -45,6 +48,7 @@
 
 #define HDDTEMP_DEF_HOST "127.0.0.1"
 #define HDDTEMP_DEF_PORT "7634"
+#define HDDTEMP_MAX_RECV_BUF (1 << 20)
 
 static const char *config_keys[] =
 {
@@ -79,11 +83,15 @@ static char hddtemp_port[16];
  *  we need to create a new socket each time. Is there another way?
  *  Hm, maybe we can re-use the `sockaddr' structure? -octo
  */
-static int hddtemp_query_daemon (char *buffer, int buffer_size)
+static char *hddtemp_query_daemon (void)
 {
        int fd;
        ssize_t status;
+
+       char *buffer;
+       int buffer_size;
        int buffer_fill;
+       char *new_buffer;
 
        const char *host;
        const char *port;
@@ -114,7 +122,7 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
                                (ai_return == EAI_SYSTEM)
                                ? sstrerror (errno, errbuf, sizeof (errbuf))
                                : gai_strerror (ai_return));
-               return (-1);
+               return (NULL);
        }
 
        fd = -1;
@@ -154,16 +162,41 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
        if (fd < 0)
        {
                ERROR ("hddtemp plugin: Could not connect to daemon.");
-               return (-1);
+               return (NULL);
        }
 
        /* receive data from the hddtemp daemon */
-       memset (buffer, '\0', buffer_size);
-
+       buffer = NULL;
+       buffer_size = 0;
        buffer_fill = 0;
-       while ((status = read (fd, buffer + buffer_fill, buffer_size - buffer_fill)) != 0)
+       while (1)
        {
-               if (status == -1)
+               if ((buffer_size == 0) || (buffer_fill >= buffer_size - 1))
+               {
+                       if (buffer_size == 0)
+                               buffer_size = 1024;
+                       else
+                               buffer_size *= 2;
+                       if (buffer_size > HDDTEMP_MAX_RECV_BUF)
+                       {
+                               WARNING ("hddtemp plugin: Message from hddtemp has been "
+                                               "truncated.");
+                               break;
+                       }
+                       new_buffer = realloc (buffer, buffer_size);
+                       if (new_buffer == NULL) {
+                               close (fd);
+                               free (buffer);
+                               ERROR ("hddtemp plugin: Allocation failed.");
+                               return (NULL);
+                       }
+                       buffer = new_buffer;
+               }
+               status = read (fd, buffer + buffer_fill, buffer_size - buffer_fill - 1);
+               if (status == 0) {
+                       break;
+               }
+               else if (status == -1)
                {
                        char errbuf[1024];
 
@@ -173,30 +206,25 @@ static int hddtemp_query_daemon (char *buffer, int buffer_size)
                        ERROR ("hddtemp plugin: Error reading from socket: %s",
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
                        close (fd);
-                       return (-1);
+                       free (buffer);
+                       return (NULL);
                }
                buffer_fill += status;
-
-               if (buffer_fill >= buffer_size)
-                       break;
        }
 
-       if (buffer_fill >= buffer_size)
-       {
-               buffer[buffer_size - 1] = '\0';
-               WARNING ("hddtemp plugin: Message from hddtemp has been "
-                               "truncated.");
-       }
-       else if (buffer_fill == 0)
+       if (buffer_fill == 0)
        {
                WARNING ("hddtemp plugin: Peer has unexpectedly shut down "
                                "the socket. Buffer: `%s'", buffer);
                close (fd);
-               return (-1);
+               free (buffer);
+               return (NULL);
        }
 
+       assert (buffer_fill < buffer_size);
+       buffer[buffer_fill] = '\0';
        close (fd);
-       return (0);
+       return (buffer);
 }
 
 static int hddtemp_config (const char *key, const char *value)
@@ -226,14 +254,10 @@ static int hddtemp_config (const char *key, const char *value)
 
 static void hddtemp_submit (char *type_instance, double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "hddtemp", sizeof (vl.plugin));
        sstrncpy (vl.type, "temperature", sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
@@ -243,54 +267,46 @@ static void hddtemp_submit (char *type_instance, double value)
 
 static int hddtemp_read (void)
 {
-       char buf[1024];
-       char *fields[128];
+       char *buf;
        char *ptr;
        char *saveptr;
-       int num_fields;
-       int num_disks;
+       char *name;
+       char *model;
+       char *temperature;
+       char *mode;
 
        /* get data from daemon */
-       if (hddtemp_query_daemon (buf, sizeof (buf)) < 0)
+       buf = hddtemp_query_daemon ();
+       if (buf == NULL)
                return (-1);
 
        /* NB: strtok_r will eat up "||" and leading "|"'s */
-       num_fields = 0;
        ptr = buf;
        saveptr = NULL;
-       while ((fields[num_fields] = strtok_r (ptr, "|", &saveptr)) != NULL)
+       while ((name = strtok_r (ptr, "|", &saveptr)) != NULL &&
+              (model = strtok_r (NULL, "|", &saveptr)) != NULL &&
+              (temperature = strtok_r (NULL, "|", &saveptr)) != NULL &&
+              (mode = strtok_r (NULL, "|", &saveptr)) != NULL)
        {
-               ptr = NULL;
-               num_fields++;
+               double temperature_value;
 
-               if (num_fields >= 128)
-                       break;
-       }
-
-       num_disks = num_fields / 4;
-
-       for (int i = 0; i < num_disks; i++)
-       {
-               char *name;
-               double temperature;
-               char *mode;
-
-               mode = fields[4*i + 3];
-               name = basename (fields[4*i + 0]);
+               ptr = NULL;
 
                /* Skip non-temperature information */
                if (mode[0] != 'C' && mode[0] != 'F')
                        continue;
 
-               temperature = atof (fields[4*i + 2]);
+               name = basename (name);
+               temperature_value = atof (temperature);
 
                /* Convert farenheit to celsius */
                if (mode[0] == 'F')
-                       temperature = (temperature - 32.0) * 5.0 / 9.0;
+                       temperature_value = (temperature_value - 32.0) * 5.0 / 9.0;
 
-               hddtemp_submit (name, temperature);
+               hddtemp_submit (name, temperature_value);
        }
        
+       free (buf);
        return (0);
 } /* int hddtemp_read */
 
diff --git a/src/hugepages.c b/src/hugepages.c
new file mode 100644 (file)
index 0000000..1eb8b0c
--- /dev/null
@@ -0,0 +1,277 @@
+/*-
+ * collectd - src/hugepages.c
+ * MIT License
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Jaroslav Safka <jaroslavx.safka@intel.com>
+ *   Kim-Marie Jones <kim-marie.jones@intel.com>
+ *   Florian Forster <octo at collectd.org>
+ */
+
+#include "collectd.h"
+
+#include "common.h" /* auxiliary functions */
+#include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
+
+static const char g_plugin_name[] = "hugepages";
+
+static _Bool g_flag_rpt_numa = 1;
+static _Bool g_flag_rpt_mm = 1;
+
+static _Bool g_values_pages = 1;
+static _Bool g_values_bytes = 0;
+static _Bool g_values_percent = 0;
+
+#define HP_HAVE_NR 0x01
+#define HP_HAVE_SURPLUS 0x02
+#define HP_HAVE_FREE 0x04
+#define HP_HAVE_ALL 0x07
+
+struct entry_info {
+  char *d_name;
+  const char *node;
+  size_t page_size_kb;
+
+  gauge_t nr;
+  gauge_t surplus;
+  gauge_t free;
+  uint8_t flags;
+};
+
+static int hp_config(oconfig_item_t *ci) {
+  for (int i = 0; i < ci->children_num; i++) {
+    oconfig_item_t *child = ci->children + i;
+    if (strcasecmp("ReportPerNodeHP", child->key) == 0)
+      cf_util_get_boolean(child, &g_flag_rpt_numa);
+    else if (strcasecmp("ReportRootHP", child->key) == 0)
+      cf_util_get_boolean(child, &g_flag_rpt_mm);
+    else if (strcasecmp("ValuesPages", child->key) == 0)
+      cf_util_get_boolean(child, &g_values_pages);
+    else if (strcasecmp("ValuesBytes", child->key) == 0)
+      cf_util_get_boolean(child, &g_values_bytes);
+    else if (strcasecmp("ValuesPercentage", child->key) == 0)
+      cf_util_get_boolean(child, &g_values_percent);
+    else
+      ERROR("%s: Invalid configuration option: \"%s\".", g_plugin_name,
+            child->key);
+  }
+
+  return (0);
+}
+
+static void submit_hp(const struct entry_info *info) {
+  value_list_t vl = VALUE_LIST_INIT;
+
+  vl.values = &(value_t) { .gauge = NAN };
+  vl.values_len = 1;
+
+  sstrncpy(vl.plugin, g_plugin_name, sizeof(vl.plugin));
+  if (info->node) {
+    ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%zuKb",
+              info->node, info->page_size_kb);
+  } else {
+    ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%zuKb",
+              info->page_size_kb);
+  }
+
+  /* ensure all metrics have the same timestamp */
+  vl.time = cdtime();
+
+  gauge_t free = info->free;
+  gauge_t used = (info->nr + info->surplus) - info->free;
+
+  if (g_values_pages) {
+    sstrncpy(vl.type, "vmpage_number", sizeof(vl.type));
+    plugin_dispatch_multivalue(&vl, /* store_percentage = */ 0, DS_TYPE_GAUGE,
+                               "free", free, "used", used, NULL);
+  }
+  if (g_values_bytes) {
+    gauge_t page_size = (gauge_t)(1024 * info->page_size_kb);
+    sstrncpy(vl.type, "memory", sizeof(vl.type));
+    plugin_dispatch_multivalue(&vl, /* store_percentage = */ 0, DS_TYPE_GAUGE,
+                               "free", free * page_size, "used",
+                               used * page_size, NULL);
+  }
+  if (g_values_percent) {
+    sstrncpy(vl.type, "percent", sizeof(vl.type));
+    plugin_dispatch_multivalue(&vl, /* store_percentage = */ 1, DS_TYPE_GAUGE,
+                               "free", free, "used", used, NULL);
+  }
+}
+
+static int read_hugepage_entry(const char *path, const char *entry,
+                               void *e_info) {
+  char path2[PATH_MAX];
+  struct entry_info *info = e_info;
+  double value;
+
+  ssnprintf(path2, sizeof(path2), "%s/%s", path, entry);
+
+  FILE *fh = fopen(path2, "rt");
+  if (fh == NULL) {
+    ERROR("%s: cannot open %s", g_plugin_name, path2);
+    return -1;
+  }
+
+  if (fscanf(fh, "%lf", &value) != 1) {
+    ERROR("%s: cannot parse file %s", g_plugin_name, path2);
+    fclose(fh);
+    return -1;
+  }
+  fclose(fh);
+
+  if (strcmp(entry, "nr_hugepages") == 0) {
+    info->nr = value;
+    info->flags |= HP_HAVE_NR;
+  } else if (strcmp(entry, "surplus_hugepages") == 0) {
+    info->surplus = value;
+    info->flags |= HP_HAVE_SURPLUS;
+  } else if (strcmp(entry, "free_hugepages") == 0) {
+    info->free = value;
+    info->flags |= HP_HAVE_FREE;
+  }
+
+  if (info->flags != HP_HAVE_ALL) {
+    return 0;
+  }
+
+  submit_hp(info);
+
+  /* Reset flags so subsequent calls don't submit again. */
+  info->flags = 0;
+  return 0;
+}
+
+static int read_syshugepages(const char *path, const char *node) {
+  static const char hugepages_dir[] = "hugepages-";
+  DIR *dir;
+  struct dirent *result;
+  char path2[PATH_MAX];
+
+  dir = opendir(path);
+  if (dir == NULL) {
+    ERROR("%s: cannot open directory %s", g_plugin_name, path);
+    return -1;
+  }
+
+  /* read "hugepages-XXXXXkB" entries */
+  while ((result = readdir(dir)) != NULL) {
+    if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir) - 1)) {
+      /* not node dir */
+      errno = 0;
+      continue;
+    }
+
+    long page_size = strtol(result->d_name + strlen(hugepages_dir),
+                            /* endptr = */ NULL, /* base = */ 10);
+    if (errno != 0) {
+      char errbuf[1024];
+      ERROR("%s: failed to determine page size from directory name \"%s\": %s",
+            g_plugin_name, result->d_name,
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+      continue;
+    }
+
+    /* /sys/devices/system/node/node?/hugepages/ */
+    ssnprintf(path2, sizeof(path2), "%s/%s", path, result->d_name);
+
+    walk_directory(path2, read_hugepage_entry,
+                   &(struct entry_info){
+                       .d_name = result->d_name,
+                       .node = node,
+                       .page_size_kb = (size_t)page_size,
+                   },
+                   /* hidden = */ 0);
+    errno = 0;
+  }
+
+  /* Check if NULL return from readdir() was an error */
+  if (errno != 0) {
+    ERROR("%s: readdir failed", g_plugin_name);
+    closedir(dir);
+    return -1;
+  }
+
+  closedir(dir);
+  return 0;
+}
+
+static int read_nodes(void) {
+  static const char sys_node[] = "/sys/devices/system/node";
+  static const char node_string[] = "node";
+  static const char sys_node_hugepages[] =
+      "/sys/devices/system/node/%s/hugepages";
+  DIR *dir;
+  struct dirent *result;
+  char path[PATH_MAX];
+
+  dir = opendir(sys_node);
+  if (dir == NULL) {
+    ERROR("%s: cannot open directory %s", g_plugin_name, sys_node);
+    return -1;
+  }
+
+  while ((result = readdir(dir)) != NULL) {
+    if (strncmp(result->d_name, node_string, sizeof(node_string) - 1)) {
+      /* not node dir */
+      errno = 0;
+      continue;
+    }
+
+    ssnprintf(path, sizeof(path), sys_node_hugepages, result->d_name);
+    read_syshugepages(path, result->d_name);
+    errno = 0;
+  }
+
+  /* Check if NULL return from readdir() was an error */
+  if (errno != 0) {
+    ERROR("%s: readdir failed", g_plugin_name);
+    closedir(dir);
+    return -1;
+  }
+
+  closedir(dir);
+  return 0;
+}
+
+static int huge_read(void) {
+  static const char sys_mm_hugepages[] = "/sys/kernel/mm/hugepages";
+
+  if (g_flag_rpt_mm) {
+    if (read_syshugepages(sys_mm_hugepages, "mm") != 0) {
+      return -1;
+    }
+  }
+  if (g_flag_rpt_numa) {
+    if (read_nodes() != 0) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+void module_register(void) {
+  plugin_register_complex_config(g_plugin_name, hp_config);
+  plugin_register_read(g_plugin_name, huge_read);
+}
diff --git a/src/intel_rdt.c b/src/intel_rdt.c
new file mode 100644 (file)
index 0000000..21f3a20
--- /dev/null
@@ -0,0 +1,676 @@
+/**
+ * collectd - src/intel_rdt.c
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Serhiy Pshyk <serhiyx.pshyk@intel.com>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+
+#include <pqos.h>
+
+#define RDT_PLUGIN "intel_rdt"
+
+#define RDT_MAX_SOCKETS 8
+#define RDT_MAX_SOCKET_CORES 64
+#define RDT_MAX_CORES (RDT_MAX_SOCKET_CORES * RDT_MAX_SOCKETS)
+
+struct rdt_core_group_s {
+  char *desc;
+  size_t num_cores;
+  unsigned *cores;
+  enum pqos_mon_event events;
+};
+typedef struct rdt_core_group_s rdt_core_group_t;
+
+struct rdt_ctx_s {
+  rdt_core_group_t cgroups[RDT_MAX_CORES];
+  struct pqos_mon_data *pgroups[RDT_MAX_CORES];
+  size_t num_groups;
+  const struct pqos_cpuinfo *pqos_cpu;
+  const struct pqos_cap *pqos_cap;
+  const struct pqos_capability *cap_mon;
+};
+typedef struct rdt_ctx_s rdt_ctx_t;
+
+static rdt_ctx_t *g_rdt = NULL;
+
+static int isdup(const uint64_t *nums, size_t size, uint64_t val) {
+  for (size_t i = 0; i < size; i++)
+    if (nums[i] == val)
+      return 1;
+  return 0;
+}
+
+static int strtouint64(const char *s, uint64_t *n) {
+  char *endptr = NULL;
+
+  assert(s != NULL);
+  assert(n != NULL);
+
+  *n = strtoull(s, &endptr, 0);
+
+  if (!(*s != '\0' && *endptr == '\0')) {
+    DEBUG(RDT_PLUGIN ": Error converting '%s' to unsigned number.", s);
+    return (-EINVAL);
+  }
+
+  return (0);
+}
+
+/*
+ * NAME
+ *   strlisttonums
+ *
+ * DESCRIPTION
+ *   Converts string of characters representing list of numbers into array of
+ *   numbers. Allowed formats are:
+ *     0,1,2,3
+ *     0-10,20-18
+ *     1,3,5-8,10,0x10-12
+ *
+ *   Numbers can be in decimal or hexadecimal format.
+ *
+ * PARAMETERS
+ *   `s'         String representing list of unsigned numbers.
+ *   `nums'      Array to put converted numeric values into.
+ *   `max'       Maximum number of elements that nums can accommodate.
+ *
+ * RETURN VALUE
+ *    Number of elements placed into nums.
+ */
+static size_t strlisttonums(char *s, uint64_t *nums, size_t max) {
+  int ret;
+  size_t index = 0;
+  char *saveptr = NULL;
+
+  if (s == NULL || nums == NULL || max == 0)
+    return index;
+
+  for (;;) {
+    char *p = NULL;
+    char *token = NULL;
+
+    token = strtok_r(s, ",", &saveptr);
+    if (token == NULL)
+      break;
+
+    s = NULL;
+
+    while (isspace(*token))
+      token++;
+    if (*token == '\0')
+      continue;
+
+    p = strchr(token, '-');
+    if (p != NULL) {
+      uint64_t n, start, end;
+      *p = '\0';
+      ret = strtouint64(token, &start);
+      if (ret < 0)
+        return (0);
+      ret = strtouint64(p + 1, &end);
+      if (ret < 0)
+        return (0);
+      if (start > end) {
+        return (0);
+      }
+      for (n = start; n <= end; n++) {
+        if (!(isdup(nums, index, n))) {
+          nums[index] = n;
+          index++;
+        }
+        if (index >= max)
+          return index;
+      }
+    } else {
+      uint64_t val;
+
+      ret = strtouint64(token, &val);
+      if (ret < 0)
+        return (0);
+
+      if (!(isdup(nums, index, val))) {
+        nums[index] = val;
+        index++;
+      }
+      if (index >= max)
+        return index;
+    }
+  }
+
+  return index;
+}
+
+/*
+ * NAME
+ *   cgroup_cmp
+ *
+ * DESCRIPTION
+ *   Function to compare cores in 2 core groups.
+ *
+ * PARAMETERS
+ *   `cg_a'      Pointer to core group a.
+ *   `cg_b'      Pointer to core group b.
+ *
+ * RETURN VALUE
+ *    1 if both groups contain the same cores
+ *    0 if none of their cores match
+ *    -1 if some but not all cores match
+ */
+static int cgroup_cmp(const rdt_core_group_t *cg_a,
+                      const rdt_core_group_t *cg_b) {
+  int found = 0;
+
+  assert(cg_a != NULL);
+  assert(cg_b != NULL);
+
+  const int sz_a = cg_a->num_cores;
+  const int sz_b = cg_b->num_cores;
+  const unsigned *tab_a = cg_a->cores;
+  const unsigned *tab_b = cg_b->cores;
+
+  for (int i = 0; i < sz_a; i++) {
+    for (int j = 0; j < sz_b; j++)
+      if (tab_a[i] == tab_b[j])
+        found++;
+  }
+  /* if no cores are the same */
+  if (!found)
+    return 0;
+  /* if group contains same cores */
+  if (sz_a == sz_b && sz_b == found)
+    return 1;
+  /* if not all cores are the same */
+  return -1;
+}
+
+static int cgroup_set(rdt_core_group_t *cg, char *desc, uint64_t *cores,
+                      size_t num_cores) {
+  assert(cg != NULL);
+  assert(desc != NULL);
+  assert(cores != NULL);
+  assert(num_cores > 0);
+
+  cg->cores = calloc(num_cores, sizeof(unsigned));
+  if (cg->cores == NULL) {
+    ERROR(RDT_PLUGIN ": Error allocating core group table");
+    return (-ENOMEM);
+  }
+  cg->num_cores = num_cores;
+  cg->desc = strdup(desc);
+  if (cg->desc == NULL) {
+    ERROR(RDT_PLUGIN ": Error allocating core group description");
+    sfree(cg->cores);
+    return (-ENOMEM);
+  }
+
+  for (size_t i = 0; i < num_cores; i++)
+    cg->cores[i] = (unsigned)cores[i];
+
+  return 0;
+}
+
+/*
+ * NAME
+ *   oconfig_to_cgroups
+ *
+ * DESCRIPTION
+ *   Function to set the descriptions and cores for each core group.
+ *   Takes a config option containing list of strings that are used to set
+ *   core group values.
+ *
+ * PARAMETERS
+ *   `item'        Config option containing core groups.
+ *   `groups'      Table of core groups to set values in.
+ *   `max_groups'  Maximum number of core groups allowed.
+ *   `max_core'    Maximum allowed core value.
+ *
+ * RETURN VALUE
+ *   On success, the number of core groups set up. On error, appropriate
+ *   negative error value.
+ */
+static int oconfig_to_cgroups(oconfig_item_t *item, rdt_core_group_t *groups,
+                              size_t max_groups, uint64_t max_core) {
+  int index = 0;
+
+  assert(groups != NULL);
+  assert(max_groups > 0);
+  assert(item != NULL);
+
+  for (int j = 0; j < item->values_num; j++) {
+    int ret;
+    size_t n;
+    uint64_t cores[RDT_MAX_CORES] = {0};
+    char value[DATA_MAX_NAME_LEN];
+
+    if ((item->values[j].value.string == NULL) ||
+        (strlen(item->values[j].value.string) == 0))
+      continue;
+
+    sstrncpy(value, item->values[j].value.string, sizeof(value));
+
+    n = strlisttonums(value, cores, STATIC_ARRAY_SIZE(cores));
+    if (n == 0) {
+      ERROR(RDT_PLUGIN ": Error parsing core group (%s)",
+            item->values[j].value.string);
+      return (-EINVAL);
+    }
+
+    for (int i = 0; i < n; i++) {
+      if (cores[i] > max_core) {
+        ERROR(RDT_PLUGIN ": Core group (%s) contains invalid core id (%d)",
+              item->values[j].value.string, (int)cores[i]);
+        return (-EINVAL);
+      }
+    }
+
+    /* set core group info */
+    ret = cgroup_set(&groups[index], item->values[j].value.string, cores, n);
+    if (ret < 0)
+      return ret;
+
+    index++;
+
+    if (index >= max_groups) {
+      WARNING(RDT_PLUGIN ": Too many core groups configured");
+      return index;
+    }
+  }
+
+  return index;
+}
+
+#if COLLECT_DEBUG
+static void rdt_dump_cgroups(void) {
+  char cores[RDT_MAX_CORES * 4];
+
+  if (g_rdt == NULL)
+    return;
+
+  DEBUG(RDT_PLUGIN ": Core Groups Dump");
+  DEBUG(RDT_PLUGIN ":  groups count: %zu", g_rdt->num_groups);
+
+  for (int i = 0; i < g_rdt->num_groups; i++) {
+
+    memset(cores, 0, sizeof(cores));
+    for (int j = 0; j < g_rdt->cgroups[i].num_cores; j++) {
+      snprintf(cores + strlen(cores), sizeof(cores) - strlen(cores) - 1, " %d",
+               g_rdt->cgroups[i].cores[j]);
+    }
+
+    DEBUG(RDT_PLUGIN ":  group[%d]:", i);
+    DEBUG(RDT_PLUGIN ":    description: %s", g_rdt->cgroups[i].desc);
+    DEBUG(RDT_PLUGIN ":    cores: %s", cores);
+    DEBUG(RDT_PLUGIN ":    events: 0x%X", g_rdt->cgroups[i].events);
+  }
+
+  return;
+}
+
+static inline double bytes_to_kb(const double bytes) { return bytes / 1024.0; }
+
+static inline double bytes_to_mb(const double bytes) {
+  return bytes / (1024.0 * 1024.0);
+}
+
+static void rdt_dump_data(void) {
+  /*
+   * CORE - monitored group of cores
+   * RMID - Resource Monitoring ID associated with the monitored group
+   * LLC - last level cache occupancy
+   * MBL - local memory bandwidth
+   * MBR - remote memory bandwidth
+   */
+  DEBUG("  CORE     RMID    LLC[KB]   MBL[MB]    MBR[MB]");
+  for (int i = 0; i < g_rdt->num_groups; i++) {
+
+    const struct pqos_event_values *pv = &g_rdt->pgroups[i]->values;
+
+    double llc = bytes_to_kb(pv->llc);
+    double mbr = bytes_to_mb(pv->mbm_remote_delta);
+    double mbl = bytes_to_mb(pv->mbm_local_delta);
+
+    DEBUG(" [%s] %8u %10.1f %10.1f %10.1f", g_rdt->cgroups[i].desc,
+          g_rdt->pgroups[i]->poll_ctx[0].rmid, llc, mbl, mbr);
+  }
+}
+#endif /* COLLECT_DEBUG */
+
+static void rdt_free_cgroups(void) {
+  for (int i = 0; i < RDT_MAX_CORES; i++) {
+    sfree(g_rdt->cgroups[i].desc);
+
+    sfree(g_rdt->cgroups[i].cores);
+    g_rdt->cgroups[i].num_cores = 0;
+
+    sfree(g_rdt->pgroups[i]);
+  }
+}
+
+static int rdt_default_cgroups(void) {
+  int ret;
+
+  /* configure each core in separate group */
+  for (unsigned i = 0; i < g_rdt->pqos_cpu->num_cores; i++) {
+    char desc[DATA_MAX_NAME_LEN];
+    uint64_t core = i;
+
+    ssnprintf(desc, sizeof(desc), "%d", g_rdt->pqos_cpu->cores[i].lcore);
+
+    /* set core group info */
+    ret = cgroup_set(&g_rdt->cgroups[i], desc, &core, 1);
+    if (ret < 0)
+      return ret;
+  }
+
+  return g_rdt->pqos_cpu->num_cores;
+}
+
+static int rdt_config_cgroups(oconfig_item_t *item) {
+  int n = 0;
+  enum pqos_mon_event events = 0;
+
+  if (item == NULL) {
+    DEBUG(RDT_PLUGIN ": cgroups_config: Invalid argument.");
+    return (-EINVAL);
+  }
+
+  DEBUG(RDT_PLUGIN ": Core groups [%d]:", item->values_num);
+  for (int j = 0; j < item->values_num; j++) {
+    if (item->values[j].type != OCONFIG_TYPE_STRING) {
+      ERROR(RDT_PLUGIN ": given core group value is not a string [idx=%d]", j);
+      return (-EINVAL);
+    }
+    DEBUG(RDT_PLUGIN ":  [%d]: %s", j, item->values[j].value.string);
+  }
+
+  n = oconfig_to_cgroups(item, g_rdt->cgroups, RDT_MAX_CORES,
+                         g_rdt->pqos_cpu->num_cores - 1);
+  if (n < 0) {
+    rdt_free_cgroups();
+    ERROR(RDT_PLUGIN ": Error parsing core groups configuration.");
+    return (-EINVAL);
+  }
+
+  if (n == 0) {
+    /* create default core groups if "Cores" config option is empty */
+    n = rdt_default_cgroups();
+    if (n < 0) {
+      rdt_free_cgroups();
+      ERROR(RDT_PLUGIN ": Error creating default core groups configuration.");
+      return n;
+    }
+    INFO(RDT_PLUGIN
+         ": No core groups configured. Default core groups created.");
+  }
+
+  /* Get all available events on this platform */
+  for (int i = 0; i < g_rdt->cap_mon->u.mon->num_events; i++)
+    events |= g_rdt->cap_mon->u.mon->events[i].type;
+
+  events &= ~(PQOS_PERF_EVENT_LLC_MISS);
+
+  DEBUG(RDT_PLUGIN ": Number of cores in the system: %u",
+        g_rdt->pqos_cpu->num_cores);
+  DEBUG(RDT_PLUGIN ": Available events to monitor: %#x", events);
+
+  g_rdt->num_groups = n;
+  for (int i = 0; i < n; i++) {
+    for (int j = 0; j < i; j++) {
+      int found = 0;
+      found = cgroup_cmp(&g_rdt->cgroups[j], &g_rdt->cgroups[i]);
+      if (found != 0) {
+        rdt_free_cgroups();
+        ERROR(RDT_PLUGIN ": Cannot monitor same cores in different groups.");
+        return (-EINVAL);
+      }
+    }
+
+    g_rdt->cgroups[i].events = events;
+    g_rdt->pgroups[i] = calloc(1, sizeof(*g_rdt->pgroups[i]));
+    if (g_rdt->pgroups[i] == NULL) {
+      rdt_free_cgroups();
+      ERROR(RDT_PLUGIN ": Failed to allocate memory for monitoring data.");
+      return (-ENOMEM);
+    }
+  }
+
+  return (0);
+}
+
+static int rdt_preinit(void) {
+  int ret;
+
+  if (g_rdt != NULL) {
+    /* already initialized if config callback was called before init callback */
+    return (0);
+  }
+
+  g_rdt = calloc(1, sizeof(*g_rdt));
+  if (g_rdt == NULL) {
+    ERROR(RDT_PLUGIN ": Failed to allocate memory for rdt context.");
+    return (-ENOMEM);
+  }
+
+  /* In case previous instance of the application was not closed properly
+   * call fini and ignore return code. */
+  pqos_fini();
+
+  /* TODO:
+   * stdout should not be used here. Will be reworked when support of log
+   * callback is added to PQoS library.
+  */
+  ret = pqos_init(&(struct pqos_config){.fd_log = STDOUT_FILENO});
+  if (ret != PQOS_RETVAL_OK) {
+    ERROR(RDT_PLUGIN ": Error initializing PQoS library!");
+    goto rdt_preinit_error1;
+  }
+
+  ret = pqos_cap_get(&g_rdt->pqos_cap, &g_rdt->pqos_cpu);
+  if (ret != PQOS_RETVAL_OK) {
+    ERROR(RDT_PLUGIN ": Error retrieving PQoS capabilities.");
+    goto rdt_preinit_error2;
+  }
+
+  ret = pqos_cap_get_type(g_rdt->pqos_cap, PQOS_CAP_TYPE_MON, &g_rdt->cap_mon);
+  if (ret == PQOS_RETVAL_PARAM) {
+    ERROR(RDT_PLUGIN ": Error retrieving monitoring capabilities.");
+    goto rdt_preinit_error2;
+  }
+
+  if (g_rdt->cap_mon == NULL) {
+    ERROR(
+        RDT_PLUGIN
+        ": Monitoring capability not detected. Nothing to do for the plugin.");
+    goto rdt_preinit_error2;
+  }
+
+  return (0);
+
+rdt_preinit_error2:
+  pqos_fini();
+
+rdt_preinit_error1:
+
+  sfree(g_rdt);
+
+  return (-1);
+}
+
+static int rdt_config(oconfig_item_t *ci) {
+  int ret = 0;
+
+  ret = rdt_preinit();
+  if (ret != 0)
+    return ret;
+
+  for (int i = 0; i < ci->children_num; i++) {
+    oconfig_item_t *child = ci->children + i;
+
+    if (strcasecmp("Cores", child->key) == 0) {
+
+      ret = rdt_config_cgroups(child);
+      if (ret != 0)
+        return ret;
+
+#if COLLECT_DEBUG
+      rdt_dump_cgroups();
+#endif /* COLLECT_DEBUG */
+
+    } else {
+      ERROR(RDT_PLUGIN ": Unknown configuration parameter \"%s\".", child->key);
+    }
+  }
+
+  return (0);
+}
+
+static void rdt_submit_derive(char *cgroup, char *type, char *type_instance,
+                              derive_t value) {
+  value_list_t vl = VALUE_LIST_INIT;
+
+  vl.values = &(value_t){.derive = value};
+  vl.values_len = 1;
+
+  sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
+  snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s", cgroup);
+  sstrncpy(vl.type, type, sizeof(vl.type));
+  if (type_instance)
+    sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
+
+  plugin_dispatch_values(&vl);
+}
+
+static void rdt_submit_gauge(char *cgroup, char *type, char *type_instance,
+                             gauge_t value) {
+  value_list_t vl = VALUE_LIST_INIT;
+
+  vl.values = &(value_t){.gauge = value};
+  vl.values_len = 1;
+
+  sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
+  snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s", cgroup);
+  sstrncpy(vl.type, type, sizeof(vl.type));
+  if (type_instance)
+    sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
+
+  plugin_dispatch_values(&vl);
+}
+
+static int rdt_read(__attribute__((unused)) user_data_t *ud) {
+  int ret;
+
+  if (g_rdt == NULL) {
+    ERROR(RDT_PLUGIN ": rdt_read: plugin not initialized.");
+    return (-EINVAL);
+  }
+
+  ret = pqos_mon_poll(&g_rdt->pgroups[0], (unsigned)g_rdt->num_groups);
+  if (ret != PQOS_RETVAL_OK) {
+    ERROR(RDT_PLUGIN ": Failed to poll monitoring data.");
+    return (-1);
+  }
+
+#if COLLECT_DEBUG
+  rdt_dump_data();
+#endif /* COLLECT_DEBUG */
+
+  for (int i = 0; i < g_rdt->num_groups; i++) {
+    enum pqos_mon_event mbm_events =
+        (PQOS_MON_EVENT_LMEM_BW | PQOS_MON_EVENT_TMEM_BW |
+         PQOS_MON_EVENT_RMEM_BW);
+
+    const struct pqos_event_values *pv = &g_rdt->pgroups[i]->values;
+
+    /* Submit only monitored events data */
+
+    if (g_rdt->cgroups[i].events & PQOS_MON_EVENT_L3_OCCUP)
+      rdt_submit_gauge(g_rdt->cgroups[i].desc, "bytes", "llc", pv->llc);
+
+    if (g_rdt->cgroups[i].events & PQOS_PERF_EVENT_IPC)
+      rdt_submit_gauge(g_rdt->cgroups[i].desc, "ipc", NULL, pv->ipc);
+
+    if (g_rdt->cgroups[i].events & mbm_events) {
+      rdt_submit_derive(g_rdt->cgroups[i].desc, "memory_bandwidth", "local",
+                        pv->mbm_local_delta);
+      rdt_submit_derive(g_rdt->cgroups[i].desc, "memory_bandwidth", "remote",
+                        pv->mbm_remote_delta);
+    }
+  }
+
+  return (0);
+}
+
+static int rdt_init(void) {
+  int ret;
+
+  ret = rdt_preinit();
+  if (ret != 0)
+    return ret;
+
+  /* Start monitoring */
+  for (int i = 0; i < g_rdt->num_groups; i++) {
+    rdt_core_group_t *cg = &g_rdt->cgroups[i];
+
+    ret = pqos_mon_start(cg->num_cores, cg->cores, cg->events, (void *)cg->desc,
+                         g_rdt->pgroups[i]);
+
+    if (ret != PQOS_RETVAL_OK)
+      ERROR(RDT_PLUGIN ": Error starting monitoring group %s (pqos status=%d)",
+            cg->desc, ret);
+  }
+
+  return (0);
+}
+
+static int rdt_shutdown(void) {
+  int ret;
+
+  DEBUG(RDT_PLUGIN ": rdt_shutdown.");
+
+  if (g_rdt == NULL)
+    return (0);
+
+  /* Stop monitoring */
+  for (int i = 0; i < g_rdt->num_groups; i++) {
+    pqos_mon_stop(g_rdt->pgroups[i]);
+  }
+
+  ret = pqos_fini();
+  if (ret != PQOS_RETVAL_OK)
+    ERROR(RDT_PLUGIN ": Error shutting down PQoS library.");
+
+  rdt_free_cgroups();
+  sfree(g_rdt);
+
+  return (0);
+}
+
+void module_register(void) {
+  plugin_register_init(RDT_PLUGIN, rdt_init);
+  plugin_register_complex_config(RDT_PLUGIN, rdt_config);
+  plugin_register_complex_read(NULL, RDT_PLUGIN, rdt_read, 0, NULL);
+  plugin_register_shutdown(RDT_PLUGIN, rdt_shutdown);
+}
index b8ed6e402bf564b2185b11a1c2dee1416fef36b6..c0021d336c807b26084c94de70f40fde5cfb147c 100644 (file)
@@ -168,18 +168,17 @@ static void if_submit (const char *dev, const char *type,
                derive_t rx,
                derive_t tx)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
+       value_t values[] = {
+               { .derive = rx },
+               { .derive = tx },
+       };
 
        if (ignorelist_match (ignorelist, dev) != 0)
                return;
 
-       values[0].derive = rx;
-       values[1].derive = tx;
-
        vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values_len = STATIC_ARRAY_SIZE (values);
        sstrncpy (vl.plugin, "interface", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
index b164cdf72b517da03de6847a4e7c68f4f6e5608e..7f909e26dabad189fc383ab2ff7603ffdcb8bc88 100644 (file)
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -97,14 +97,10 @@ static void ipc_submit_g (const char *plugin_instance,
                           const char *type_instance,
                           gauge_t value) /* {{{ */
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "ipc", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, type, sizeof (vl.type));
index ad62299e3390bba91aedf9c5656f711643962e44..3267275dadac14d21f24a592658cd952cd829188 100644 (file)
@@ -115,7 +115,6 @@ static void sensor_read_handler (ipmi_sensor_t *sensor,
     ipmi_states_t __attribute__((unused)) *states,
     void *user_data)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
   c_ipmi_sensor_list_t *list_item = (c_ipmi_sensor_list_t *)user_data;
@@ -214,12 +213,9 @@ static void sensor_read_handler (ipmi_sensor_t *sensor,
     return;
   }
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
 
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "ipmi", sizeof (vl.plugin));
   sstrncpy (vl.type, list_item->sensor_type, sizeof (vl.type));
   sstrncpy (vl.type_instance, list_item->sensor_name, sizeof (vl.type_instance));
index f6911221df8739f31d77710eb59802a4d9fff1d4..657b6ba0a5c340ca9ace0e8ff6de9c9b93bc0eff 100644 (file)
@@ -242,7 +242,6 @@ static int submit6_match (const struct ip6t_entry_match *match,
                           int rule_num)
 {
     int status;
-    value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
 
     /* Select the rules to collect */
@@ -260,9 +259,6 @@ static int submit6_match (const struct ip6t_entry_match *match,
             return (0);
     }
 
-    vl.values = values;
-    vl.values_len = 1;
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "ip6tables", sizeof (vl.plugin));
 
     status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
@@ -285,16 +281,16 @@ static int submit6_match (const struct ip6t_entry_match *match,
     }
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
-    values[0].derive = (derive_t) entry->counters.bcnt;
+    vl.values = &(value_t) { .derive = (derive_t) entry->counters.bcnt };
+    vl.values_len = 1;
     plugin_dispatch_values (&vl);
 
     sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
-    values[0].derive = (derive_t) entry->counters.pcnt;
+    vl.values = &(value_t) { .derive = (derive_t) entry->counters.pcnt };
     plugin_dispatch_values (&vl);
 
     return (0);
-} /* int submit_match */
-
+} /* int submit6_match */
 
 /* This needs to return `int' for IPT_MATCH_ITERATE to work. */
 static int submit_match (const struct ipt_entry_match *match,
@@ -303,7 +299,6 @@ static int submit_match (const struct ipt_entry_match *match,
                          int rule_num)
 {
     int status;
-    value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
 
     /* Select the rules to collect */
@@ -321,9 +316,6 @@ static int submit_match (const struct ipt_entry_match *match,
             return (0);
     }
 
-    vl.values = values;
-    vl.values_len = 1;
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "iptables", sizeof (vl.plugin));
 
     status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
@@ -346,11 +338,12 @@ static int submit_match (const struct ipt_entry_match *match,
     }
 
     sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
-    values[0].derive = (derive_t) entry->counters.bcnt;
+    vl.values = &(value_t) { .derive = (derive_t) entry->counters.bcnt };
+    vl.values_len = 1;
     plugin_dispatch_values (&vl);
 
     sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
-    values[0].derive = (derive_t) entry->counters.pcnt;
+    vl.values = &(value_t) { .derive = (derive_t) entry->counters.pcnt };
     plugin_dispatch_values (&vl);
 
     return (0);
index 92690e88e0098635a8cc56fe9c6191116b81082e..6bd868eb5b75c4700d68513c8c6088fa52b49c4b 100644 (file)
@@ -228,15 +228,11 @@ static int get_ti (struct ip_vs_dest_entry *de, char *ti, size_t size)
 static void cipvs_submit_connections (const char *pi, const char *ti,
                derive_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].derive = value;
-
-       vl.values     = values;
+       vl.values     = &(value_t) { .derive = value };
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, "connections", sizeof (vl.type));
@@ -250,16 +246,15 @@ static void cipvs_submit_connections (const char *pi, const char *ti,
 static void cipvs_submit_if (const char *pi, const char *t, const char *ti,
                derive_t rx, derive_t tx)
 {
-       value_t values[2];
+       value_t values[] = {
+               { .derive = rx },
+               { .derive = tx },
+       };
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].derive = rx;
-       values[1].derive = tx;
-
        vl.values     = values;
-       vl.values_len = 2;
+       vl.values_len = STATIC_ARRAY_SIZE (values);
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, t, sizeof (vl.type));
index 0f1d3f0ce50954ffd7d4524a52cd36d5bd884744..06c50ff3ab0962efa55ab8e9165edcb36b511ca3 100644 (file)
--- a/src/irq.c
+++ b/src/irq.c
@@ -72,17 +72,13 @@ static int irq_config (const char *key, const char *value)
 
 static void irq_submit (const char *irq_name, derive_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
        if (ignorelist_match (ignorelist, irq_name) != 0)
                return;
 
-       values[0].derive = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .derive = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "irq", sizeof (vl.plugin));
        sstrncpy (vl.type, "irq", sizeof (vl.type));
        sstrncpy (vl.type_instance, irq_name, sizeof (vl.type_instance));
index 67740ac8dae78c6da33a4d47891c9824fa04096a..cd173c5890ae122dbe6db94dda4dead5699a1152 100644 (file)
@@ -1425,13 +1425,11 @@ static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new read callback: %s", cbi->name);
 
-  user_data_t ud = {
-    .data = cbi,
-    .free_func = cjni_callback_info_destroy
-  };
-
   plugin_register_complex_read (/* group = */ NULL, cbi->name, cjni_read,
-      /* interval = */ 0, &ud);
+      /* interval = */ 0, &(user_data_t) {
+        .data = cbi,
+        .free_func = cjni_callback_info_destroy,
+      });
 
   (*jvm_env)->DeleteLocalRef (jvm_env, o_read);
 
@@ -1449,12 +1447,10 @@ static jint JNICALL cjni_api_register_write (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new write callback: %s", cbi->name);
 
-  user_data_t ud = {
-    .data = cbi,
-    .free_func = cjni_callback_info_destroy
-  };
-
-  plugin_register_write (cbi->name, cjni_write, &ud);
+  plugin_register_write (cbi->name, cjni_write, &(user_data_t) {
+        .data = cbi,
+        .free_func = cjni_callback_info_destroy,
+      });
 
   (*jvm_env)->DeleteLocalRef (jvm_env, o_write);
 
@@ -1472,12 +1468,10 @@ static jint JNICALL cjni_api_register_flush (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new flush callback: %s", cbi->name);
 
-  user_data_t ud = {
-    .data = cbi,
-    .free_func = cjni_callback_info_destroy
-  };
-
-  plugin_register_flush (cbi->name, cjni_flush, &ud);
+  plugin_register_flush (cbi->name, cjni_flush, &(user_data_t) {
+        .data = cbi,
+        .free_func = cjni_callback_info_destroy,
+      });
 
   (*jvm_env)->DeleteLocalRef (jvm_env, o_flush);
 
@@ -1502,12 +1496,10 @@ static jint JNICALL cjni_api_register_log (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new log callback: %s", cbi->name);
 
-  user_data_t ud = {
-    .data = cbi,
-    .free_func = cjni_callback_info_destroy
-  };
-
-  plugin_register_log (cbi->name, cjni_log, &ud);
+  plugin_register_log (cbi->name, cjni_log, &(user_data_t) {
+        .data = cbi,
+        .free_func = cjni_callback_info_destroy,
+      });
 
   (*jvm_env)->DeleteLocalRef (jvm_env, o_log);
 
@@ -1526,12 +1518,10 @@ static jint JNICALL cjni_api_register_notification (JNIEnv *jvm_env, /* {{{ */
 
   DEBUG ("java plugin: Registering new notification callback: %s", cbi->name);
 
-  user_data_t ud = {
-    .data = cbi,
-    .free_func = cjni_callback_info_destroy
-  };
-
-  plugin_register_notification (cbi->name, cjni_notification, &ud);
+  plugin_register_notification (cbi->name, cjni_notification, &(user_data_t) {
+        .data = cbi,
+        .free_func = cjni_callback_info_destroy,
+      });
 
   (*jvm_env)->DeleteLocalRef (jvm_env, o_notification);
 
index cc3be37e03fa4e508ccd3f067f109fbef8dd88cf..53854d148868d0e16f87e3c5f6b2c5653417e6da 100644 (file)
@@ -78,8 +78,6 @@ static int load_config (const char *key, const char *value)
 }
 static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
 {
-       value_t values[3];
-       value_list_t vl = VALUE_LIST_INIT;
         int cores = 0;
         char errbuf[1024];
 
@@ -97,14 +95,16 @@ static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
                lnum /= cores;
        }
 
-       values[0].gauge = snum;
-       values[1].gauge = mnum;
-       values[2].gauge = lnum;
+       value_list_t vl = VALUE_LIST_INIT;
+       value_t values[] = {
+               { .gauge = snum },
+               { .gauge = mnum },
+               { .gauge = lnum },
+       };
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "load", sizeof (vl.plugin));
        sstrncpy (vl.type, "load", sizeof (vl.type));
 
index 5b0bd13d0cd1ea5881d2da1477311189664dc3e2..69a56e1cdea3e9508c0b3bc14ab5aace5a622deb 100644 (file)
@@ -114,22 +114,15 @@ static int lpar_init (void)
 
 static void lpar_submit (const char *type_instance, double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = (gauge_t)value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
        if (report_by_serial)
        {
                sstrncpy (vl.host, serial, sizeof (vl.host));
                sstrncpy (vl.plugin_instance, hostname_g, sizeof (vl.plugin));
        }
-       else
-       {
-               sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       }
        sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
        sstrncpy (vl.type, "vcpu", sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
index 351b8c685fefdfe03f475ec3b40e7b36889fd871..45fd7d5a36fab1a76a8dd524ba56aad4ee0b0602 100644 (file)
--- a/src/lua.c
+++ b/src/lua.c
@@ -303,15 +303,13 @@ static int lua_cb_register_read(lua_State *L) /* {{{ */
   cb->lua_function_name = strdup(function_name);
   pthread_mutex_init(&cb->lock, NULL);
 
-  user_data_t ud = {
-    .data = cb
-  };
-
   int status = plugin_register_complex_read(/* group = */ "lua",
                                             /* name      = */ function_name,
                                             /* callback  = */ clua_read,
                                             /* interval  = */ 0,
-                                            /* user_data = */ &ud);
+                                            &(user_data_t) {
+                                              .data = cb,
+                                            });
 
   if (status != 0)
     return luaL_error(L, "%s", "plugin_register_complex_read failed");
@@ -349,13 +347,11 @@ static int lua_cb_register_write(lua_State *L) /* {{{ */
   cb->lua_function_name = strdup(function_name);
   pthread_mutex_init(&cb->lock, NULL);
 
-  user_data_t ud = {
-    .data = cb
-  };
-
   int status = plugin_register_write(/* name = */ function_name,
                                     /* callback  = */ clua_write,
-                                    /* user_data = */ &ud);
+                                    &(user_data_t) {
+                                      .data = cb,
+                                    });
 
   if (status != 0)
     return luaL_error(L, "%s", "plugin_register_write failed");
index 6b9a0317c2124eb78fe4c81ed485a319b85f8336..5e130d80c75c145289d1d853902176a3da05c9ba 100644 (file)
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -18,7 +18,7 @@
  *
  * Authors:
  *   Chad Malfait <malfaitc at yahoo.com>
- *   Benjamin Gilbert <bgilbert at cs.cmu.edu>
+ *   Benjamin Gilbert <bgilbert at backtick.net>
  **/
 
 #include <lvm2app.h>
@@ -55,15 +55,11 @@ static char const *get_lv_property_string(lv_t lv, char const *property)
 static void lvm_submit (char const *plugin_instance, char const *type_instance,
         uint64_t ivalue)
 {
-    value_t v;
     value_list_t vl = VALUE_LIST_INIT;
 
-    v.gauge = (gauge_t) ivalue;
-
-    vl.values = &v;
+    vl.values = &(value_t) { .gauge = (gauge_t) ivalue };
     vl.values_len = 1;
 
-    sstrncpy(vl.host, hostname_g, sizeof (vl.host));
     sstrncpy(vl.plugin, "lvm", sizeof (vl.plugin));
     sstrncpy(vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
     sstrncpy(vl.type, "df_complex", sizeof (vl.type));
index 053bd7fa2c7a47851c33ae1e19e5c5b38d058132..82c7e2faaae071cd0d108a9838e9325e0decc4ec 100644 (file)
@@ -538,13 +538,12 @@ static int madwifi_config (const char *key, const char *value)
 
 
 static void submit (const char *dev, const char *type, const char *ti1,
-                       const char *ti2, value_t *val, int len)
+                       const char *ti2, value_t *val, size_t len)
 {
        value_list_t vl = VALUE_LIST_INIT;
 
        vl.values = val;
        vl.values_len = len;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "madwifi", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@ -558,28 +557,26 @@ static void submit (const char *dev, const char *type, const char *ti1,
 }
 
 static void submit_derive (const char *dev, const char *type, const char *ti1,
-                               const char *ti2, derive_t val)
+                               const char *ti2, derive_t value)
 {
-       value_t item;
-       item.derive = val;
-       submit (dev, type, ti1, ti2, &item, 1);
+       submit (dev, type, ti1, ti2, &(value_t) { .derive = value }, 1);
 }
 
 static void submit_derive2 (const char *dev, const char *type, const char *ti1,
                                const char *ti2, derive_t val1, derive_t val2)
 {
-       value_t items[2];
-       items[0].derive = val1;
-       items[1].derive = val2;
-       submit (dev, type, ti1, ti2, items, 2);
+       value_t values[] = {
+          { .derive = val1 },
+          { .derive = val2 },
+        };
+
+       submit (dev, type, ti1, ti2, values, STATIC_ARRAY_SIZE (values));
 }
 
 static void submit_gauge (const char *dev, const char *type, const char *ti1,
-                               const char *ti2, gauge_t val)
+                               const char *ti2, gauge_t value)
 {
-       value_t item;
-       item.gauge = val;
-       submit (dev, type, ti1, ti2, &item, 1);
+       submit (dev, type, ti1, ti2, &(value_t) { .gauge = value }, 1);
 }
 
 static void submit_antx (const char *dev, const char *name,
index cd6301673a1a3673b8912375554da3a32bfd8bb1..dd8319eae36fd42605826e738339ebdf6faf2d4c 100644 (file)
 
 #include "collectd.h"
 
+#include "common.h"
 #include "filter_chain.h"
+#include "meta_data.h"
+#include "utils_llist.h"
 
 #include <sys/types.h>
 #include <regex.h>
@@ -64,6 +67,7 @@ struct mr_match_s
        mr_regex_t *plugin_instance;
        mr_regex_t *type;
        mr_regex_t *type_instance;
+       llist_t *meta;  /* Maps each meta key into mr_regex_t* */
        _Bool invert;
 };
 
@@ -77,7 +81,7 @@ static void mr_free_regex (mr_regex_t *r) /* {{{ */
 
        regfree (&r->re);
        memset (&r->re, 0, sizeof (r->re));
-       free (r->re_str);
+       sfree (r->re_str);
 
        if (r->next != NULL)
                mr_free_regex (r->next);
@@ -93,8 +97,14 @@ static void mr_free_match (mr_match_t *m) /* {{{ */
        mr_free_regex (m->plugin_instance);
        mr_free_regex (m->type);
        mr_free_regex (m->type_instance);
+       for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next)
+       {
+               sfree (e->key);
+               mr_free_regex ((mr_regex_t *) e->value);
+       }
+       llist_destroy (m->meta);
 
-       free (m);
+       sfree (m);
 } /* }}} void mr_free_match */
 
 static int mr_match_regexen (mr_regex_t *re_head, /* {{{ */
@@ -127,31 +137,25 @@ static int mr_match_regexen (mr_regex_t *re_head, /* {{{ */
        return (FC_MATCH_MATCHES);
 } /* }}} int mr_match_regexen */
 
-static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
-               oconfig_item_t *ci)
+static int mr_add_regex (mr_regex_t **re_head, const char *re_str, /* {{{ */
+               const char *option)
 {
        mr_regex_t *re;
        int status;
 
-       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
-       {
-               log_warn ("`%s' needs exactly one string argument.", ci->key);
-               return (-1);
-       }
-
        re = calloc (1, sizeof (*re));
        if (re == NULL)
        {
-               log_err ("mr_config_add_regex: calloc failed.");
+               log_err ("mr_add_regex: calloc failed.");
                return (-1);
        }
        re->next = NULL;
 
-       re->re_str = strdup (ci->values[0].value.string);
+       re->re_str = strdup (re_str);
        if (re->re_str == NULL)
        {
-               free (re);
-               log_err ("mr_config_add_regex: strdup failed.");
+               sfree (re);
+               log_err ("mr_add_regex: strdup failed.");
                return (-1);
        }
 
@@ -162,9 +166,9 @@ static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
                regerror (status, &re->re, errmsg, sizeof (errmsg));
                errmsg[sizeof (errmsg) - 1] = 0;
                log_err ("Compiling regex `%s' for `%s' failed: %s.",
-                               re->re_str, ci->key, errmsg);
-               free (re->re_str);
-               free (re);
+                               re->re_str, option, errmsg);
+               sfree (re->re_str);
+               sfree (re);
                return (-1);
        }
 
@@ -184,8 +188,78 @@ static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
        }
 
        return (0);
+} /* }}} int mr_add_regex */
+
+static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
+               oconfig_item_t *ci)
+{
+       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+       {
+               log_warn ("`%s' needs exactly one string argument.", ci->key);
+               return (-1);
+       }
+
+       return mr_add_regex (re_head, ci->values[0].value.string, ci->key);
 } /* }}} int mr_config_add_regex */
 
+static int mr_config_add_meta_regex (llist_t **meta, /* {{{ */
+               oconfig_item_t *ci)
+{
+       char *meta_key;
+       llentry_t *entry;
+       mr_regex_t *re_head;
+       int status;
+       char buffer[1024];
+
+       if ((ci->values_num != 2)
+               || (ci->values[0].type != OCONFIG_TYPE_STRING)
+               || (ci->values[1].type != OCONFIG_TYPE_STRING))
+       {
+               log_warn ("`%s' needs exactly two string arguments.", ci->key);
+               return (-1);
+       }
+
+       if (*meta == NULL)
+       {
+               *meta = llist_create();
+               if (*meta == NULL)
+               {
+                       log_err ("mr_config_add_meta_regex: llist_create failed.");
+                       return (-1);
+               }
+       }
+
+       meta_key = ci->values[0].value.string;
+       entry = llist_search (*meta, meta_key);
+       if (entry == NULL)
+       {
+               meta_key = strdup (meta_key);
+               if (meta_key == NULL)
+               {
+                       log_err ("mr_config_add_meta_regex: strdup failed.");
+                       return (-1);
+               }
+               entry = llentry_create (meta_key, NULL);
+               if (entry == NULL)
+               {
+                       log_err ("mr_config_add_meta_regex: llentry_create failed.");
+                       sfree (meta_key);
+                       return (-1);
+               }
+               /* meta_key and entry will now be freed by mr_free_match(). */
+               llist_append (*meta, entry);
+       }
+
+       ssnprintf (buffer, sizeof (buffer), "%s `%s'", ci->key, meta_key);
+       /* Can't pass &entry->value into mr_add_regex, so copy in/out. */
+       re_head = entry->value;
+       status = mr_add_regex (&re_head, ci->values[1].value.string, buffer);
+       if (status == 0) {
+               entry->value = re_head;
+       }
+       return status;
+} /* }}} int mr_config_add_meta_regex */
+
 static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
 {
        mr_match_t *m;
@@ -216,6 +290,8 @@ static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
                        status = mr_config_add_regex (&m->type, child);
                else if (strcasecmp ("TypeInstance", child->key) == 0)
                        status = mr_config_add_regex (&m->type_instance, child);
+               else if (strcasecmp ("MetaData", child->key) == 0)
+                       status = mr_config_add_meta_regex (&m->meta, child);
                else if (strcasecmp ("Invert", child->key) == 0)
                        status = cf_util_get_boolean(child, &m->invert);
                else
@@ -236,7 +312,8 @@ static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
                                && (m->plugin == NULL)
                                && (m->plugin_instance == NULL)
                                && (m->type == NULL)
-                               && (m->type_instance == NULL))
+                               && (m->type_instance == NULL)
+                               && (m->meta == NULL))
                {
                        log_err ("No (valid) regular expressions have been configured. "
                                        "This match will be ignored.");
@@ -295,6 +372,25 @@ static int mr_match (const data_set_t __attribute__((unused)) *ds, /* {{{ */
        if (mr_match_regexen (m->type_instance,
                                vl->type_instance) == FC_MATCH_NO_MATCH)
                return (nomatch_value);
+       if (vl->meta != NULL)
+       {
+               for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next)
+               {
+                       mr_regex_t *meta_re = (mr_regex_t *) e->value;
+                       char *value;
+                       int status = meta_data_get_string (vl->meta, e->key, &value);
+                       if (status == (-ENOENT))  /* key is not present */
+                               return (nomatch_value);
+                       if (status != 0)  /* some other problem */
+                               continue;  /* error will have already been printed. */
+                       if (mr_match_regexen (meta_re, value) == FC_MATCH_NO_MATCH)
+                       {
+                               sfree (value);
+                               return (nomatch_value);
+                       }
+                       sfree (value);
+               }
+       }
 
        return (match_value);
 } /* }}} int mr_match */
index 9629b8960d67da5960f957d89f48bfd0c40f500c..87e54fa18406dd44a4d07a2822b00a90c79083fe 100644 (file)
@@ -218,14 +218,10 @@ static int mbmon_config (const char *key, const char *value)
 static void mbmon_submit (const char *type, const char *type_instance,
                double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "mbmon", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
index 44cad2edbeef32102cf7324fb73d5974c1159796..793b172281c3eb0c22e8f9be8ee221a7f3c93d77 100644 (file)
--- a/src/md.c
+++ b/src/md.c
@@ -72,14 +72,10 @@ static int md_config (const char *key, const char *value)
 static void md_submit (const int minor, const char *type_instance,
     gauge_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "md", sizeof (vl.plugin));
   ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
       "%i", minor);
index dff5546179f1bade7201718889e1669f87b96d77..766637b7f1a00a4c4003ec75dd59a73557b65ad2 100644 (file)
@@ -441,16 +441,12 @@ static int cmc_init (void) /* {{{ */
 } /* }}} int cmc_init */
 
 static void cmc_submit (const web_page_t *wp, const web_match_t *wm, /* {{{ */
-    const cu_match_value_t *mv)
+    value_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0] = mv->value;
-
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "memcachec", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, wm->type, sizeof (vl.type));
@@ -496,7 +492,7 @@ static int cmc_read_page (web_page_t *wp) /* {{{ */
       continue;
     }
 
-    cmc_submit (wp, wm, mv);
+    cmc_submit (wp, wm, mv->value);
     match_value_reset (mv);
   } /* for (wm = wp->matches; wm != NULL; wm = wm->next) */
 
index 9e6e725293d152561bd3287427f3e90dffb217f5..765a0fd3bcd501294abd2e23b02eb6a22365c34f 100644 (file)
 struct memcached_s
 {
   char *name;
-  char *socket;
   char *host;
-  char *port;
+  char *socket;
+  char *connhost;
+  char *connport;
 };
 typedef struct memcached_s memcached_t;
 
@@ -59,9 +60,10 @@ static void memcached_free (void *arg)
     return;
 
   sfree (st->name);
-  sfree (st->socket);
   sfree (st->host);
-  sfree (st->port);
+  sfree (st->socket);
+  sfree (st->connhost);
+  sfree (st->connport);
   sfree (st);
 }
 
@@ -98,29 +100,23 @@ static int memcached_connect_unix (memcached_t *st)
 
 static int memcached_connect_inet (memcached_t *st)
 {
-  const char *host;
-  const char *port;
-
   struct addrinfo *ai_list;
   int status;
   int fd = -1;
 
-  host = (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST;
-  port = (st->port != NULL) ? st->port : MEMCACHED_DEF_PORT;
-
   struct addrinfo ai_hints = {
     .ai_family = AF_UNSPEC,
     .ai_flags = AI_ADDRCONFIG,
     .ai_socktype = SOCK_STREAM
   };
 
-  status = getaddrinfo (host, port, &ai_hints, &ai_list);
+  status = getaddrinfo (st->connhost, st->connport, &ai_hints, &ai_list);
   if (status != 0)
   {
     char errbuf[1024];
     ERROR ("memcached plugin: memcached_connect_inet: "
         "getaddrinfo(%s,%s) failed: %s",
-        host, port,
+        st->connhost, st->connport,
         (status == EAI_SYSTEM)
         ? sstrerror (errno, errbuf, sizeof (errbuf))
         : gai_strerror (status));
@@ -239,36 +235,20 @@ static int memcached_query_daemon (char *buffer, size_t buffer_size, memcached_t
 
 static void memcached_init_vl (value_list_t *vl, memcached_t const *st)
 {
-  char const *host = st->host;
-
-  /* Set vl->host to hostname_g, if:
-   * - Legacy mode is used.
-   * - "Socket" option is given (doc: "Host option is ignored").
-   * - "Host" option is not provided.
-   * - "Host" option is set to "localhost" or "127.0.0.1". */
-  if ((strcmp (st->name, "__legacy__") == 0)
-      || (st->socket != NULL)
-      || (st->host == NULL)
-      || (strcmp ("127.0.0.1", st->host) == 0)
-      || (strcmp ("localhost", st->host) == 0))
-    host = hostname_g;
-
   sstrncpy (vl->plugin, "memcached", sizeof (vl->plugin));
-  sstrncpy (vl->host, host, sizeof (vl->host));
-  if (strcmp (st->name, "__legacy__") != 0)
+  if (st->host != NULL)
+    sstrncpy (vl->host, st->host, sizeof (vl->host));
+  if (st->name != NULL)
     sstrncpy (vl->plugin_instance, st->name, sizeof (vl->plugin_instance));
 }
 
 static void submit_derive (const char *type, const char *type_inst,
     derive_t value, memcached_t *st)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
-  memcached_init_vl (&vl, st);
-
-  values[0].derive = value;
 
-  vl.values = values;
+  memcached_init_vl (&vl, st);
+  vl.values = &(value_t) { .derive = value };
   vl.values_len = 1;
   sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_inst != NULL)
@@ -280,15 +260,15 @@ static void submit_derive (const char *type, const char *type_inst,
 static void submit_derive2 (const char *type, const char *type_inst,
     derive_t value0, derive_t value1, memcached_t *st)
 {
-  value_t values[2];
   value_list_t vl = VALUE_LIST_INIT;
-  memcached_init_vl (&vl, st);
-
-  values[0].derive = value0;
-  values[1].derive = value1;
+  value_t values[] = {
+    { .derive = value0 },
+    { .derive = value1 },
+  };
 
+  memcached_init_vl (&vl, st);
   vl.values = values;
-  vl.values_len = 2;
+  vl.values_len = STATIC_ARRAY_SIZE (values);
   sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_inst != NULL)
     sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
@@ -299,13 +279,10 @@ static void submit_derive2 (const char *type, const char *type_inst,
 static void submit_gauge (const char *type, const char *type_inst,
     gauge_t value, memcached_t *st)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
-  memcached_init_vl (&vl, st);
-
-  values[0].gauge = value;
 
-  vl.values = values;
+  memcached_init_vl (&vl, st);
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
   sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_inst != NULL)
@@ -317,15 +294,15 @@ static void submit_gauge (const char *type, const char *type_inst,
 static void submit_gauge2 (const char *type, const char *type_inst,
     gauge_t value0, gauge_t value1, memcached_t *st)
 {
-  value_t values[2];
   value_list_t vl = VALUE_LIST_INIT;
-  memcached_init_vl (&vl, st);
-
-  values[0].gauge = value0;
-  values[1].gauge = value1;
+  value_t values[] = {
+    { .gauge = value0 },
+    { .gauge = value1 },
+  };
 
+  memcached_init_vl (&vl, st);
   vl.values = values;
-  vl.values_len = 2;
+  vl.values_len = STATIC_ARRAY_SIZE (values);
   sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_inst != NULL)
     sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
@@ -551,19 +528,59 @@ static int memcached_add_read_callback (memcached_t *st)
   char callback_name[3*DATA_MAX_NAME_LEN];
   int status;
 
-  assert (st->name != NULL);
-  ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
+  ssnprintf (callback_name, sizeof (callback_name), "memcached/%s",
+      (st->name != NULL) ? st->name : "__legacy__");
+
+  /* If no <Address> used then:
+   * - Connect to the destination specified by <Host>, if present.
+   *   If not, use the default address.
+   * - Use the default hostname (set st->host to NULL), if
+   *    - Legacy mode is used (no configuration options at all), or
+   *    - "Host" option is not provided, or
+   *    - "Host" option is set to "localhost" or "127.0.0.1".
+   *
+   * If <Address> used then host may be set to "localhost" or "127.0.0.1"
+   * explicitly.
+   */
+  if (st->connhost == NULL)
+  {
+    if (st->host)
+    {
+      st->connhost = strdup(st->host);
+      if (st->connhost == NULL)
+        return (ENOMEM);
 
-  user_data_t ud = {
-    .data = st,
-    .free_func = memcached_free
-  };
+      if ((strcmp ("127.0.0.1", st->host) == 0)
+          || (strcmp ("localhost", st->host) == 0))
+        sfree(st->host);
+    }
+    else
+    {
+      st->connhost = strdup(MEMCACHED_DEF_HOST);
+      if (st->connhost == NULL)
+        return (ENOMEM);
+    }
+  }
+
+  if (st->connport == NULL)
+  {
+      st->connport = strdup(MEMCACHED_DEF_PORT);
+      if (st->connport == NULL)
+        return (ENOMEM);
+  }
+
+  assert (st->connhost != NULL);
+  assert (st->connport != NULL);
 
   status = plugin_register_complex_read (/* group = */ "memcached",
       /* name      = */ callback_name,
       /* callback  = */ memcached_read,
       /* interval  = */ 0,
-      /* user_data = */ &ud);
+      &(user_data_t) {
+        .data = st,
+        .free_func = memcached_free,
+      });
+
   return (status);
 } /* int memcached_add_read_callback */
 
@@ -571,6 +588,7 @@ static int memcached_add_read_callback (memcached_t *st)
  * <Plugin memcached>
  *   <Instance "instance_name">
  *     Host foo.zomg.com
+ *     Address 1.2.3.4
  *     Port "1234"
  *   </Instance>
  * </Plugin>
@@ -587,24 +605,23 @@ static int config_add_instance(oconfig_item_t *ci)
   if (st == NULL)
   {
     ERROR ("memcached plugin: calloc failed.");
-    return (-1);
+    return (ENOMEM);
   }
 
   st->name = NULL;
-  st->socket = NULL;
   st->host = NULL;
-  st->port = NULL;
+  st->socket = NULL;
+  st->connhost = NULL;
+  st->connport = NULL;
 
-  if (strcasecmp (ci->key, "Plugin") == 0) /* default instance */
-    st->name = sstrdup ("__legacy__");
-  else /* <Instance /> block */
+  if (strcasecmp (ci->key, "Instance") == 0)
     status = cf_util_get_string (ci, &st->name);
+
   if (status != 0)
   {
     sfree (st);
     return (status);
   }
-  assert (st->name != NULL);
 
   for (int i = 0; i < ci->children_num; i++)
   {
@@ -614,8 +631,10 @@ static int config_add_instance(oconfig_item_t *ci)
       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 ("Address", child->key) == 0)
+      status = cf_util_get_string (child, &st->connhost);
     else if (strcasecmp ("Port", child->key) == 0)
-      status = cf_util_get_service (child, &st->port);
+      status = cf_util_get_service (child, &st->connport);
     else
     {
       WARNING ("memcached plugin: Option `%s' not allowed here.",
@@ -682,10 +701,11 @@ static int memcached_init (void)
   st = calloc (1, sizeof (*st));
   if (st == NULL)
     return (ENOMEM);
-  st->name = sstrdup ("__legacy__");
-  st->socket = NULL;
+  st->name = NULL;
   st->host = NULL;
-  st->port = NULL;
+  st->socket = NULL;
+  st->connhost = NULL;
+  st->connport = NULL;
 
   status = memcached_add_read_callback (st);
   if (status == 0)
index 16b8e09fbac720d6c32f7a919bf2f46cc793713e..55e7de16e4af6de4a571ec6897353d9af5ff70e5 100644 (file)
@@ -527,7 +527,6 @@ static int memory_read (void) /* {{{ */
 
        vl.values = v;
        vl.values_len = STATIC_ARRAY_SIZE (v);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "memory", sizeof (vl.plugin));
        sstrncpy (vl.type, "memory", sizeof (vl.type));
        vl.time = cdtime ();
index 3e31889fe83f560d89a09ce20df0d26c55d95dc6..51e677598d51ab8bf174e7e9990bec99b2afffbc 100644 (file)
--- a/src/mic.c
+++ b/src/mic.c
@@ -150,19 +150,16 @@ static int mic_config (const char *key, const char *value) {
        return (0);
 }
 
-static void mic_submit_memory_use(int micnumber, const char *type_instance, U32 val)
+static void mic_submit_memory_use(int micnumber, const char *type_instance, U32 value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
        /* MicAccessAPI reports KB's of memory, adjust for this */
-       DEBUG("mic plugin: Memory Value Report; %u %lf",val,((gauge_t)val)*1024.0);
-       values[0].gauge = ((gauge_t)val)*1024.0;
+       DEBUG("mic plugin: Memory Value Report; %u %lf",value,((gauge_t)value)*1024.0);
 
-       vl.values=values;
-       vl.values_len=1;
+       vl.values = &(value_t) { .gauge = ((gauge_t)value) * 1024.0 };
+       vl.values_len = 1;
 
-       strncpy (vl.host, hostname_g, sizeof (vl.host));
        strncpy (vl.plugin, "mic", sizeof (vl.plugin));
        ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "%i", micnumber);
        strncpy (vl.type, "memory", sizeof (vl.type));
@@ -190,15 +187,12 @@ static int mic_read_memory(int mic)
        return (0);
 }
 
-static void mic_submit_temp(int micnumber, const char *type, gauge_t val)
+static void mic_submit_temp(int micnumber, const char *type, gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = val;
-
-       vl.values=values;
-       vl.values_len=1;
+       vl.values = &(value_t) { .gauge = value };
+       vl.values_len = 1;
 
        strncpy (vl.host, hostname_g, sizeof (vl.host));
        strncpy (vl.plugin, "mic", sizeof (vl.plugin));
@@ -237,15 +231,12 @@ static int mic_read_temps(int mic)
 }
 
 static void mic_submit_cpu(int micnumber, const char *type_instance,
-               int core, derive_t val)
+               int core, derive_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].derive = val;
-
-       vl.values=values;
-       vl.values_len=1;
+       vl.values = &(value_t) { .derive = value };
+       vl.values_len = 1;
 
        strncpy (vl.host, hostname_g, sizeof (vl.host));
        strncpy (vl.plugin, "mic", sizeof (vl.plugin));
@@ -296,15 +287,12 @@ static int mic_read_cpu(int mic)
        return (0);
 }
 
-static void mic_submit_power(int micnumber, const char *type, const char *type_instance, gauge_t val)
+static void mic_submit_power(int micnumber, const char *type, const char *type_instance, gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = val;
-
-       vl.values=values;
-       vl.values_len=1;
+       vl.values = &(value_t) { .gauge = value };
+       vl.values_len = 1;
 
        strncpy (vl.host, hostname_g, sizeof (vl.host));
        strncpy (vl.plugin, "mic", sizeof (vl.plugin));
@@ -358,13 +346,13 @@ static int mic_read (void)
        U32 ret;
        int error;
 
-       error=0;
-       for (int i=0;i<num_mics;i++) {
+       error = 0;
+       for (int i = 0;i<num_mics;i++) {
                ret = MicInitAdapter(&mic_handle,&mics[i]);
                if (ret != MIC_ACCESS_API_SUCCESS) {
                        ERROR("mic plugin: Problem initializing MicAdapter: %s",
                                        MicGetErrorString(ret));
-                       error=1;
+                       error = 1;
                }
 
                if (error == 0 && show_memory)
@@ -383,12 +371,12 @@ static int mic_read (void)
                if (ret != MIC_ACCESS_API_SUCCESS) {
                        ERROR("mic plugin: Problem closing MicAdapter: %s",
                                        MicGetErrorString(ret));
-                       error=2;
+                       error = 2;
                        break;
                }
        }
        if (num_mics==0)
-               error=3;
+               error = 3;
        return error;
 }
 
index 93fd54a5184f36752fd0fa7365710e3a397a8114..a7d1b582c76fb27a3007aaad27a83abc60bd0616 100644 (file)
@@ -470,11 +470,11 @@ static int mb_read_data (mb_host_t *host, mb_slave_t *slave, /* {{{ */
   }
   else if (host->conntype == MBCONN_TCP)
   {
-    struct sockaddr sockaddr;
-    socklen_t saddrlen = sizeof (sockaddr);
-
+    /* getpeername() is used only to determine if the socket is connected, not
+     * because we're really interested in the peer's IP address. */
     status = getpeername (modbus_get_socket (host->connection),
-        &sockaddr, &saddrlen);
+        (struct sockaddr *) &(struct sockaddr_storage) { 0 },
+        &(socklen_t) { sizeof (struct sockaddr_storage) });
     if (status != 0)
       status = errno;
   }
@@ -1003,18 +1003,17 @@ static int mb_config_add_host (oconfig_item_t *ci) /* {{{ */
 
   if (status == 0)
   {
-    user_data_t ud;
     char name[1024];
 
-    ud.data = host;
-    ud.free_func = host_free;
-
     ssnprintf (name, sizeof (name), "modbus-%s", host->host);
 
     plugin_register_complex_read (/* group = */ NULL, name,
         /* callback = */ mb_read,
         /* interval = */ host->interval,
-        &ud);
+        &(user_data_t) {
+          .data = host,
+          .free_func = host_free,
+        });
   }
   else
   {
index ad889953a1127a561234af42463fc040cba2bf7c..c08fd29ed2842cde90572f6dac5cbed817e3ba83 100644 (file)
@@ -631,11 +631,9 @@ static int mqtt_config_publisher (oconfig_item_t *ci)
     }
 
     ssnprintf (cb_name, sizeof (cb_name), "mqtt/%s", conf->name);
-    user_data_t user_data = {
-        .data = conf
-    };
-
-    plugin_register_write (cb_name, mqtt_write, &user_data);
+    plugin_register_write (cb_name, mqtt_write, &(user_data_t) {
+                .data = conf,
+            });
     return (0);
 } /* mqtt_config_publisher */
 
index 02fe1ad312f4be22a58982bb91f5ce033e29dd3f..9321daf8e9176831903ec89e1aee70def9f5cd3a 100644 (file)
@@ -193,14 +193,10 @@ static int multimeter_init (void)
 
 static void multimeter_submit (double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "multimeter", sizeof (vl.plugin));
        sstrncpy (vl.type, "multimeter", sizeof (vl.type));
 
index 32b72e286a0b0d08a4f8202ad17ac8296601504a..a64b0e5bc96a6125757abb17da6548a1b13473fe 100644 (file)
@@ -233,14 +233,11 @@ static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
                else
                        sstrncpy (cb_name, "mysql", sizeof (cb_name));
 
-               user_data_t ud = {
-                       .data = db,
-                       .free_func = mysql_database_free
-               };
-
                plugin_register_complex_read (/* group = */ NULL, cb_name,
-                                             mysql_read,
-                                             /* interval = */ 0, &ud);
+                               mysql_read, /* interval = */ 0, &(user_data_t) {
+                                       .data = db,
+                                       .free_func = mysql_database_free,
+                               });
        }
        else
        {
@@ -368,39 +365,24 @@ static void submit (const char *type, const char *type_instance,
        plugin_dispatch_values (&vl);
 } /* submit */
 
-static void counter_submit (const char *type, const char *type_instance,
-               derive_t value, mysql_database_t *db)
-{
-       value_t values[1];
-
-       values[0].derive = value;
-       submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
-} /* void counter_submit */
-
 static void gauge_submit (const char *type, const char *type_instance,
                gauge_t value, mysql_database_t *db)
 {
-       value_t values[1];
-
-       values[0].gauge = value;
-       submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
+       submit (type, type_instance, &(value_t) { .gauge = value }, 1, db);
 } /* void gauge_submit */
 
 static void derive_submit (const char *type, const char *type_instance,
                derive_t value, mysql_database_t *db)
 {
-       value_t values[1];
-
-       values[0].derive = value;
-       submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
+       submit (type, type_instance, &(value_t) { .derive = value }, 1, db);
 } /* void derive_submit */
 
 static void traffic_submit (derive_t rx, derive_t tx, mysql_database_t *db)
 {
-       value_t values[2];
-
-       values[0].derive = rx;
-       values[1].derive = tx;
+       value_t values[] = {
+               { .derive = rx },
+               { .derive = tx },
+       };
 
        submit ("mysql_octets", NULL, values, STATIC_ARRAY_SIZE (values), db);
 } /* void traffic_submit */
@@ -465,7 +447,7 @@ static int mysql_read_master_stats (mysql_database_t *db, MYSQL *con)
        }
 
        position = atoll (row[1]);
-       counter_submit ("mysql_log_position", "master-bin", position, db);
+       derive_submit ("mysql_log_position", "master-bin", position, db);
 
        row = mysql_fetch_row (res);
        if (row != NULL)
@@ -523,10 +505,10 @@ static int mysql_read_slave_stats (mysql_database_t *db, MYSQL *con)
                double gauge;
 
                counter = atoll (row[READ_MASTER_LOG_POS_IDX]);
-               counter_submit ("mysql_log_position", "slave-read", counter, db);
+               derive_submit ("mysql_log_position", "slave-read", counter, db);
 
                counter = atoll (row[EXEC_MASTER_LOG_POS_IDX]);
-               counter_submit ("mysql_log_position", "slave-exec", counter, db);
+               derive_submit ("mysql_log_position", "slave-exec", counter, db);
 
                if (row[SECONDS_BEHIND_MASTER_IDX] != NULL)
                {
@@ -676,7 +658,7 @@ static int mysql_read_innodb_stats (mysql_database_t *db, MYSQL *con)
 
                switch (metrics[i].ds_type) {
                        case DS_TYPE_COUNTER:
-                               counter_submit(metrics[i].type, key, (counter_t)val, db);
+                               derive_submit(metrics[i].type, key, (counter_t)val, db);
                                break;
                        case DS_TYPE_GAUGE:
                                gauge_submit(metrics[i].type, key, (gauge_t)val, db);
@@ -839,7 +821,7 @@ static int mysql_read (user_data_t *ud)
 
                        /* Ignore `prepared statements' */
                        if (strncmp (key, "Com_stmt_", strlen ("Com_stmt_")) != 0)
-                               counter_submit ("mysql_commands",
+                               derive_submit ("mysql_commands",
                                                key + strlen ("Com_"),
                                                val, db);
                }
@@ -849,7 +831,7 @@ static int mysql_read (user_data_t *ud)
                        if (val == 0ULL)
                                continue;
 
-                       counter_submit ("mysql_handler",
+                       derive_submit ("mysql_handler",
                                        key + strlen ("Handler_"),
                                        val, db);
                }
@@ -890,7 +872,7 @@ static int mysql_read (user_data_t *ud)
                else if (strncmp (key, "Table_locks_",
                                        strlen ("Table_locks_")) == 0)
                {
-                       counter_submit ("mysql_locks",
+                       derive_submit ("mysql_locks",
                                        key + strlen ("Table_locks_"),
                                        val, db);
                }
@@ -902,7 +884,7 @@ static int mysql_read (user_data_t *ud)
                        else if (strcmp (key, "Innodb_buffer_pool_pages_dirty") == 0)
                                gauge_submit ("mysql_bpool_pages", "dirty", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_pages_flushed") == 0)
-                               counter_submit ("mysql_bpool_counters", "pages_flushed", val, db);
+                               derive_submit ("mysql_bpool_counters", "pages_flushed", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_pages_free") == 0)
                                gauge_submit ("mysql_bpool_pages", "free", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_pages_misc") == 0)
@@ -910,19 +892,19 @@ static int mysql_read (user_data_t *ud)
                        else if (strcmp (key, "Innodb_buffer_pool_pages_total") == 0)
                                gauge_submit ("mysql_bpool_pages", "total", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_read_ahead_rnd") == 0)
-                               counter_submit ("mysql_bpool_counters", "read_ahead_rnd", val, db);
+                               derive_submit ("mysql_bpool_counters", "read_ahead_rnd", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_read_ahead") == 0)
-                               counter_submit ("mysql_bpool_counters", "read_ahead", val, db);
+                               derive_submit ("mysql_bpool_counters", "read_ahead", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_read_ahead_evicted") == 0)
-                               counter_submit ("mysql_bpool_counters", "read_ahead_evicted", val, db);
+                               derive_submit ("mysql_bpool_counters", "read_ahead_evicted", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_read_requests") == 0)
-                               counter_submit ("mysql_bpool_counters", "read_requests", val, db);
+                               derive_submit ("mysql_bpool_counters", "read_requests", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_reads") == 0)
-                               counter_submit ("mysql_bpool_counters", "reads", val, db);
+                               derive_submit ("mysql_bpool_counters", "reads", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_wait_free") == 0)
-                               counter_submit ("mysql_bpool_counters", "wait_free", val, db);
+                               derive_submit ("mysql_bpool_counters", "wait_free", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_write_requests") == 0)
-                               counter_submit ("mysql_bpool_counters", "write_requests", val, db);
+                               derive_submit ("mysql_bpool_counters", "write_requests", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_bytes_data") == 0)
                                gauge_submit ("mysql_bpool_bytes", "data", val, db);
                        else if (strcmp (key, "Innodb_buffer_pool_bytes_dirty") == 0)
@@ -930,80 +912,80 @@ static int mysql_read (user_data_t *ud)
 
                        /* data */
                        if (strcmp (key, "Innodb_data_fsyncs") == 0)
-                               counter_submit ("mysql_innodb_data", "fsyncs", val, db);
+                               derive_submit ("mysql_innodb_data", "fsyncs", val, db);
                        else if (strcmp (key, "Innodb_data_read") == 0)
-                               counter_submit ("mysql_innodb_data", "read", val, db);
+                               derive_submit ("mysql_innodb_data", "read", val, db);
                        else if (strcmp (key, "Innodb_data_reads") == 0)
-                               counter_submit ("mysql_innodb_data", "reads", val, db);
+                               derive_submit ("mysql_innodb_data", "reads", val, db);
                        else if (strcmp (key, "Innodb_data_writes") == 0)
-                               counter_submit ("mysql_innodb_data", "writes", val, db);
+                               derive_submit ("mysql_innodb_data", "writes", val, db);
                        else if (strcmp (key, "Innodb_data_written") == 0)
-                               counter_submit ("mysql_innodb_data", "written", val, db);
+                               derive_submit ("mysql_innodb_data", "written", val, db);
 
                        /* double write */
                        else if (strcmp (key, "Innodb_dblwr_writes") == 0)
-                               counter_submit ("mysql_innodb_dblwr", "writes", val, db);
+                               derive_submit ("mysql_innodb_dblwr", "writes", val, db);
                        else if (strcmp (key, "Innodb_dblwr_pages_written") == 0)
-                               counter_submit ("mysql_innodb_dblwr", "written", val, db);
+                               derive_submit ("mysql_innodb_dblwr", "written", val, db);
                        else if (strcmp (key, "Innodb_dblwr_page_size") == 0)
                                gauge_submit ("mysql_innodb_dblwr", "page_size", val, db);
 
                        /* log */
                        else if (strcmp (key, "Innodb_log_waits") == 0)
-                               counter_submit ("mysql_innodb_log", "waits", val, db);
+                               derive_submit ("mysql_innodb_log", "waits", val, db);
                        else if (strcmp (key, "Innodb_log_write_requests") == 0)
-                               counter_submit ("mysql_innodb_log", "write_requests", val, db);
+                               derive_submit ("mysql_innodb_log", "write_requests", val, db);
                        else if (strcmp (key, "Innodb_log_writes") == 0)
-                               counter_submit ("mysql_innodb_log", "writes", val, db);
+                               derive_submit ("mysql_innodb_log", "writes", val, db);
                        else if (strcmp (key, "Innodb_os_log_fsyncs") == 0)
-                               counter_submit ("mysql_innodb_log", "fsyncs", val, db);
+                               derive_submit ("mysql_innodb_log", "fsyncs", val, db);
                        else if (strcmp (key, "Innodb_os_log_written") == 0)
-                               counter_submit ("mysql_innodb_log", "written", val, db);
+                               derive_submit ("mysql_innodb_log", "written", val, db);
 
                        /* pages */
                        else if (strcmp (key, "Innodb_pages_created") == 0)
-                               counter_submit ("mysql_innodb_pages", "created", val, db);
+                               derive_submit ("mysql_innodb_pages", "created", val, db);
                        else if (strcmp (key, "Innodb_pages_read") == 0)
-                               counter_submit ("mysql_innodb_pages", "read", val, db);
+                               derive_submit ("mysql_innodb_pages", "read", val, db);
                        else if (strcmp (key, "Innodb_pages_written") == 0)
-                               counter_submit ("mysql_innodb_pages", "written", val, db);
+                               derive_submit ("mysql_innodb_pages", "written", val, db);
 
                        /* row lock */
                        else if (strcmp (key, "Innodb_row_lock_time") == 0)
-                               counter_submit ("mysql_innodb_row_lock", "time", val, db);
+                               derive_submit ("mysql_innodb_row_lock", "time", val, db);
                        else if (strcmp (key, "Innodb_row_lock_waits") == 0)
-                               counter_submit ("mysql_innodb_row_lock", "waits", val, db);
+                               derive_submit ("mysql_innodb_row_lock", "waits", val, db);
 
                        /* rows */
                        else if (strcmp (key, "Innodb_rows_deleted") == 0)
-                               counter_submit ("mysql_innodb_rows", "deleted", val, db);
+                               derive_submit ("mysql_innodb_rows", "deleted", val, db);
                        else if (strcmp (key, "Innodb_rows_inserted") == 0)
-                               counter_submit ("mysql_innodb_rows", "inserted", val, db);
+                               derive_submit ("mysql_innodb_rows", "inserted", val, db);
                        else if (strcmp (key, "Innodb_rows_read") == 0)
-                               counter_submit ("mysql_innodb_rows", "read", val, db);
+                               derive_submit ("mysql_innodb_rows", "read", val, db);
                        else if (strcmp (key, "Innodb_rows_updated") == 0)
-                               counter_submit ("mysql_innodb_rows", "updated", val, db);
+                               derive_submit ("mysql_innodb_rows", "updated", val, db);
                }
                else if (strncmp (key, "Select_", strlen ("Select_")) == 0)
                {
-                       counter_submit ("mysql_select", key + strlen ("Select_"),
+                       derive_submit ("mysql_select", key + strlen ("Select_"),
                                        val, db);
                }
                else if (strncmp (key, "Sort_", strlen ("Sort_")) == 0)
                {
                        if (strcmp (key, "Sort_merge_passes") == 0)
-                               counter_submit ("mysql_sort_merge_passes", NULL, val, db);
+                               derive_submit ("mysql_sort_merge_passes", NULL, val, db);
                        else if (strcmp (key, "Sort_rows") == 0)
-                               counter_submit ("mysql_sort_rows", NULL, val, db);
+                               derive_submit ("mysql_sort_rows", NULL, val, db);
                        else if (strcmp (key, "Sort_range") == 0)
-                               counter_submit ("mysql_sort", "range", val, db);
+                               derive_submit ("mysql_sort", "range", val, db);
                        else if (strcmp (key, "Sort_scan") == 0)
-                               counter_submit ("mysql_sort", "scan", val, db);
+                               derive_submit ("mysql_sort", "scan", val, db);
 
                }
                else if (strncmp (key, "Slow_queries", strlen ("Slow_queries")) == 0)
                {
-                       counter_submit ("mysql_slow_queries", NULL , val, db);
+                       derive_submit ("mysql_slow_queries", NULL , val, db);
                }
        }
        mysql_free_result (res); res = NULL;
index d73969646f7ca9be74c966fcd3da03d2754cc0a0..c532062645b97b2292df079e9fbd2150eb75efa0 100644 (file)
@@ -617,7 +617,7 @@ static data_volume_perf_t *get_volume_perf (cfg_volume_perf_t *cvp, /* {{{ */
 static int submit_values (const char *host, /* {{{ */
                const char *plugin_inst,
                const char *type, const char *type_inst,
-               value_t *values, int values_len,
+               value_t *values, size_t values_len,
                cdtime_t timestamp, cdtime_t interval)
 {
        value_list_t vl = VALUE_LIST_INIT;
@@ -633,8 +633,6 @@ static int submit_values (const char *host, /* {{{ */
 
        if (host != NULL)
                sstrncpy (vl.host, host, sizeof (vl.host));
-       else
-               sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "netapp", sizeof (vl.plugin));
        if (plugin_inst != NULL)
                sstrncpy (vl.plugin_instance, plugin_inst, sizeof (vl.plugin_instance));
@@ -649,50 +647,42 @@ static int submit_two_derive (const char *host, const char *plugin_inst, /* {{{
                const char *type, const char *type_inst, derive_t val0, derive_t val1,
                cdtime_t timestamp, cdtime_t interval)
 {
-       value_t values[2];
-
-       values[0].derive = val0;
-       values[1].derive = val1;
+       value_t values[] = {
+               { .derive = val0 },
+               { .derive = val1 },
+       };
 
        return (submit_values (host, plugin_inst, type, type_inst,
-                               values, 2, timestamp, interval));
+                               values, STATIC_ARRAY_SIZE (values), timestamp, interval));
 } /* }}} int submit_two_derive */
 
 static int submit_derive (const char *host, const char *plugin_inst, /* {{{ */
                const char *type, const char *type_inst, derive_t counter,
                cdtime_t timestamp, cdtime_t interval)
 {
-       value_t v;
-
-       v.derive = counter;
-
        return (submit_values (host, plugin_inst, type, type_inst,
-                               &v, 1, timestamp, interval));
+                               &(value_t) { .derive = counter }, 1, timestamp, interval));
 } /* }}} int submit_derive */
 
 static int submit_two_gauge (const char *host, const char *plugin_inst, /* {{{ */
                const char *type, const char *type_inst, gauge_t val0, gauge_t val1,
                cdtime_t timestamp, cdtime_t interval)
 {
-       value_t values[2];
-
-       values[0].gauge = val0;
-       values[1].gauge = val1;
+       value_t values[] = {
+               { .gauge = val0 },
+               { .gauge = val1 },
+       };
 
        return (submit_values (host, plugin_inst, type, type_inst,
-                               values, 2, timestamp, interval));
+                               values, STATIC_ARRAY_SIZE (values), timestamp, interval));
 } /* }}} int submit_two_gauge */
 
 static int submit_double (const char *host, const char *plugin_inst, /* {{{ */
                const char *type, const char *type_inst, double d,
                cdtime_t timestamp, cdtime_t interval)
 {
-       value_t v;
-
-       v.gauge = (gauge_t) d;
-
        return (submit_values (host, plugin_inst, type, type_inst,
-                               &v, 1, timestamp, interval));
+                               &(value_t) { .gauge = counter }, 1, timestamp, interval));
 } /* }}} int submit_uint64 */
 
 /* Calculate hit ratio from old and new counters and submit the resulting
@@ -707,7 +697,7 @@ static int submit_cache_ratio (const char *host, /* {{{ */
                cdtime_t timestamp,
                cdtime_t interval)
 {
-       value_t v;
+       value_t v = { .gauge = NAN };
 
        if ((new_hits >= old_hits) && (new_misses >= old_misses)) {
                uint64_t hits;
@@ -717,8 +707,6 @@ static int submit_cache_ratio (const char *host, /* {{{ */
                misses = new_misses - old_misses;
 
                v.gauge = 100.0 * ((gauge_t) hits) / ((gauge_t) (hits + misses));
-       } else {
-               v.gauge = NAN;
        }
 
        return (submit_values (host, plugin_inst, "cache_ratio", type_inst,
@@ -2879,15 +2867,13 @@ static int cna_register_host (host_config_t *host) /* {{{ */
        else
                ssnprintf (cb_name, sizeof (cb_name), "netapp-%s", host->name);
 
-       user_data_t ud = {
-               .data = host,
-               .free_func = (void (*) (void *)) free_host_config
-       };
-
        plugin_register_complex_read (/* group = */ NULL, cb_name,
                        /* callback  = */ cna_read,
                        /* interval  = */ host->interval,
-                       /* user data = */ &ud);
+                       &(user_data_t) {
+                               .data = host,
+                               .free_func = (void *) free_host_config,
+                       });
 
        return (0);
 } /* }}} int cna_register_host */
index cfca46f7494084de4939288f72a95632c2fcdd44..70c10c9dc88bbc69428b43faa962db6f5532cd43 100644 (file)
@@ -194,14 +194,10 @@ static int check_ignorelist (const char *dev,
 static void submit_one (const char *dev, const char *type,
     const char *type_instance, derive_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].derive = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .derive = value };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, type, sizeof (vl.type));
@@ -216,15 +212,14 @@ static void submit_two (const char *dev, const char *type,
     const char *type_instance,
     derive_t rx, derive_t tx)
 {
-  value_t values[2];
   value_list_t vl = VALUE_LIST_INIT;
-
-  values[0].derive = rx;
-  values[1].derive = tx;
+  value_t values[] = {
+    { .derive = rx },
+    { .derive = tx },
+  };
 
   vl.values = values;
-  vl.values_len = 2;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  vl.values_len = STATIC_ARRAY_SIZE (values);
   sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, type, sizeof (vl.type));
index 9a0f429aad88b64bca940484f107978c0f8d0016..484e610053bc3d4248c127de9e82a32dcd693f52 100644 (file)
@@ -303,7 +303,7 @@ static char            *send_buffer;
 static char            *send_buffer_ptr;
 static int              send_buffer_fill;
 static cdtime_t         send_buffer_last_update;
-static value_list_t     send_buffer_vl = VALUE_LIST_STATIC;
+static value_list_t     send_buffer_vl = VALUE_LIST_INIT;
 static pthread_mutex_t  send_buffer_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /* XXX: These counters are incremented from one place only. The spot in which
@@ -3386,7 +3386,6 @@ static int network_stats_read (void) /* {{{ */
        vl.values = values;
        vl.values_len = 2;
        vl.time = 0;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "network", sizeof (vl.plugin));
 
        /* Octets received / sent */
index c128c8173fea1a494333da877765ab8f9bf208fb..d080cd6e55b4ee782f6704d19a19cdb34a267c9f 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
@@ -386,7 +386,6 @@ static void nfs_procedures_submit (const char *plugin_instance,
        value_list_t vl = VALUE_LIST_INIT;
 
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
index 16ce3d5f6ba33d5207b0cbf44f0e0673ea539925..08c24f9a5b8fb93e6d2a3d0eb00e4bd4818b4f0d 100644 (file)
@@ -139,7 +139,7 @@ static int init (void)
 #else
     static char credentials[1024];
     int status = ssnprintf (credentials, sizeof (credentials),
-       "%s:%s", user, pass == NULL ? "" : pass);
+        "%s:%s", user, pass == NULL ? "" : pass);
     if ((status < 0) || ((size_t) status >= sizeof (credentials)))
     {
       ERROR ("nginx plugin: Credentials would have been truncated.");
@@ -210,10 +210,8 @@ static void submit (const char *type, const char *inst, long long value)
     return;
 
   vl.values = values;
-  vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  vl.values_len = STATIC_ARRAY_SIZE (values);
   sstrncpy (vl.plugin, "nginx", sizeof (vl.plugin));
-  sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
   sstrncpy (vl.type, type, sizeof (vl.type));
 
   if (inst != NULL)
@@ -258,39 +256,43 @@ static int nginx_read (void)
   /*
    * Active connections: 291
    * server accepts handled requests
-   *  16630948 16630948 31070465
+   *  101059015 100422216 347910649
    * Reading: 6 Writing: 179 Waiting: 106
    */
   for (int i = 0; i < lines_num; i++)
   {
     fields_num = strsplit (lines[i], fields,
-       (sizeof (fields) / sizeof (fields[0])));
+        (sizeof (fields) / sizeof (fields[0])));
 
     if (fields_num == 3)
     {
       if ((strcmp (fields[0], "Active") == 0)
-         && (strcmp (fields[1], "connections:") == 0))
+          && (strcmp (fields[1], "connections:") == 0))
       {
-       submit ("nginx_connections", "active", atoll (fields[2]));
+        submit ("nginx_connections", "active", atoll (fields[2]));
       }
       else if ((atoll (fields[0]) != 0)
-         && (atoll (fields[1]) != 0)
-         && (atoll (fields[2]) != 0))
+          && (atoll (fields[1]) != 0)
+          && (atoll (fields[2]) != 0))
       {
-       submit ("connections", "accepted", atoll (fields[0]));
-       submit ("connections", "handled", atoll (fields[1]));
-       submit ("nginx_requests", NULL, atoll (fields[2]));
+        submit ("connections", "accepted", atoll (fields[0]));
+        /* TODO: The legacy metric "handled", which is the sum of "accepted" and
+         * "failed", is reported for backwards compatibility only. Remove in the
+         * next major version. */
+        submit ("connections", "handled", atoll (fields[1]));
+        submit ("connections", "failed", (atoll(fields[0]) - atoll (fields[1])));
+        submit ("nginx_requests", NULL, atoll (fields[2]));
       }
     }
     else if (fields_num == 6)
     {
       if ((strcmp (fields[0], "Reading:") == 0)
-         && (strcmp (fields[2], "Writing:") == 0)
-         && (strcmp (fields[4], "Waiting:") == 0))
+          && (strcmp (fields[2], "Writing:") == 0)
+          && (strcmp (fields[4], "Waiting:") == 0))
       {
-       submit ("nginx_connections", "reading", atoll (fields[1]));
-       submit ("nginx_connections", "writing", atoll (fields[3]));
-       submit ("nginx_connections", "waiting", atoll (fields[5]));
+        submit ("nginx_connections", "reading", atoll (fields[1]));
+        submit ("nginx_connections", "writing", atoll (fields[3]));
+        submit ("nginx_connections", "waiting", atoll (fields[5]));
       }
     }
   }
index 30f29c97dbfcef7f50afbb8daa1a5d2b67f305e8..7f6f982aac824cc3ef63255bf01b809c3226ea70 100644 (file)
@@ -313,16 +313,11 @@ static int ntpd_config (const char *key, const char *value)
 
 static void ntpd_submit (const char *type, const char *type_inst, gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "ntpd", sizeof (vl.plugin));
-       sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
 
index 8f5bf4803821c9fe40be370f4c5c5ee0d4cd4520..e16538324f98aaa881b52c5e8d611a16340e1a28 100644 (file)
@@ -47,7 +47,6 @@ static void numa_dispatch_value (int node, /* {{{ */
   vl.values = &v;
   vl.values_len = 1;
 
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "numa", sizeof (vl.plugin));
   ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "node%i", node);
   sstrncpy (vl.type, "vmpage_action", sizeof (vl.type));
index b5c6b41b6522142aba73716ed36b5a05e4886608..29074c4ea10fc90adbdd7ecf3d2adbd9e3a21296 100644 (file)
--- a/src/nut.c
+++ b/src/nut.c
@@ -120,13 +120,10 @@ static int nut_config (const char *key, const char *value)
 static void nut_submit (nut_ups_t *ups, const char *type,
     const char *type_instance, gauge_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
-  vl.values_len = STATIC_ARRAY_SIZE (values);
+  vl.values = &(value_t) { .gauge = value };
+  vl.values_len = 1;
   sstrncpy (vl.host,
       (strcasecmp (ups->hostname, "localhost") == 0)
       ? hostname_g
index 899ad3e8f2ef4e565cb782c4290f8cfbf08f39cf..3a36723d6770b212691c696810620f88332957c5 100644 (file)
@@ -216,15 +216,11 @@ __attribute__ ((nonnull(2)))
 static void olsrd_submit (const char *plugin_instance, /* {{{ */
     const char *type, const char *type_instance, gauge_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
 
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "olsrd", sizeof (vl.plugin));
   if (plugin_instance != NULL)
     sstrncpy (vl.plugin_instance, plugin_instance,
index 235eff80a8d4663b5e479627db39f3183f99aa21..c333fead4455b9e84e0d0653c5712c8fc8d2667d 100644 (file)
@@ -336,7 +336,6 @@ static int cow_load_config (const char *key, const char *value)
 static int cow_read_values (const char *path, const char *name,
     const ow_family_features_t *family_info)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
   int success = 0;
 
@@ -347,10 +346,6 @@ static int cow_read_values (const char *path, const char *name,
       return 0;
   }
 
-  vl.values = values;
-  vl.values_len = 1;
-
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, name, sizeof (vl.plugin_instance));
 
@@ -359,6 +354,7 @@ static int cow_read_values (const char *path, const char *name,
     char *buffer;
     size_t buffer_size;
     int status;
+    char errbuf[1024];
 
     char file[4096];
     char *endptr;
@@ -373,14 +369,14 @@ static int cow_read_values (const char *path, const char *name,
     status = OW_get (file, &buffer, &buffer_size);
     if (status < 0)
     {
-      ERROR ("onewire plugin: OW_get (%s/%s) failed. status = %#x;",
-          path, family_info->features[i].filename, status);
+      ERROR ("onewire plugin: OW_get (%s/%s) failed. error = %s;",
+          path, family_info->features[i].filename, sstrerror(errno, errbuf, sizeof (errbuf)));
       return (-1);
     }
     DEBUG ("Read onewire device %s as %s", file, buffer);
 
     endptr = NULL;
-    values[0].gauge = strtod (buffer, &endptr);
+    gauge_t g = strtod (buffer, &endptr);
     if (endptr == NULL)
     {
       ERROR ("onewire plugin: Buffer is not a number: %s", buffer);
@@ -391,6 +387,9 @@ static int cow_read_values (const char *path, const char *name,
     sstrncpy (vl.type_instance, family_info->features[i].type_instance,
         sizeof (vl.type_instance));
 
+    vl.values = &(value_t) { .gauge = g };
+    vl.values_len = 1;
+
     plugin_dispatch_values (&vl);
     success++;
 
@@ -430,6 +429,7 @@ static int cow_read_bus (const char *path)
   char *buffer;
   size_t buffer_size;
   int status;
+  char errbuf[1024];
 
   char *buffer_ptr;
   char *dummy;
@@ -439,8 +439,8 @@ static int cow_read_bus (const char *path)
   status = OW_get (path, &buffer, &buffer_size);
   if (status < 0)
   {
-    ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;",
-        path, status);
+    ERROR ("onewire plugin: OW_get (%s) failed. error = %s;",
+        path, sstrerror(errno, errbuf, sizeof (errbuf)));
     return (-1);
   }
   DEBUG ("onewire plugin: OW_get (%s) returned: %s",
@@ -493,37 +493,32 @@ static int cow_read_bus (const char *path)
 
 static int cow_simple_read (void)
 {
-  value_t      values[1];
   value_list_t vl = VALUE_LIST_INIT;
   char        *buffer;
   size_t       buffer_size;
   int          status;
+  char         errbuf[1024];
   char        *endptr;
   direct_access_element_t *traverse;
 
   /* traverse list and check entries */
   for (traverse = direct_list; traverse != NULL; traverse = traverse->next)
   {
-      vl.values = values;
-      vl.values_len = 1;
-
-      sstrncpy (vl.host, hostname_g, sizeof (vl.host));
       sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin));
       sstrncpy (vl.plugin_instance, traverse->address, sizeof (vl.plugin_instance));
 
       status = OW_get (traverse->path, &buffer, &buffer_size);
       if (status < 0)
       {
-          ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;",
+          ERROR ("onewire plugin: OW_get (%s) failed. status = %s;",
                  traverse->path,
-                 status);
+                 sstrerror(errno, errbuf, sizeof (errbuf)));
           return (-1);
       }
       DEBUG ("onewire plugin: Read onewire device %s as %s", traverse->path, buffer);
 
-
       endptr = NULL;
-      values[0].gauge = strtod (buffer, &endptr);
+      gauge_t g = strtod (buffer, &endptr);
       if (endptr == NULL)
       {
           ERROR ("onewire plugin: Buffer is not a number: %s", buffer);
@@ -533,6 +528,9 @@ static int cow_simple_read (void)
       sstrncpy (vl.type, traverse->file, sizeof (vl.type));
       sstrncpy (vl.type_instance, "",   sizeof (""));
 
+      vl.values = &(value_t) { .gauge = g };
+      vl.values_len = 1;
+
       plugin_dispatch_values (&vl);
       free (buffer);
   } /* for (traverse) */
@@ -590,6 +588,7 @@ static int cow_shutdown (void)
 static int cow_init (void)
 {
   int status;
+  char errbuf[1024];
 
   if (device_g == NULL)
   {
@@ -601,7 +600,7 @@ static int cow_init (void)
   status = (int) OW_init (device_g);
   if (status != 0)
   {
-    ERROR ("onewire plugin: OW_init(%s) failed: %i.", device_g, status);
+    ERROR ("onewire plugin: OW_init(%s) failed: %s.", device_g, sstrerror(errno, errbuf, sizeof (errbuf)));
     return (1);
   }
 
index d424cb457557fe563ebc4cf997604d42a19ada53..d5e58b1a67d0f9b2295097a7b5705188b517b6dd 100644 (file)
@@ -169,11 +169,7 @@ static void cldap_submit_value (const char *type, const char *type_instance, /*
        vl.values     = &value;
        vl.values_len = 1;
 
-       if ((st->host == NULL)
-                       || (strcmp ("", st->host) == 0)
-                       || (strcmp ("localhost", st->host) == 0))
-               sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-       else
+       if ((st->host != NULL) && (strcmp ("localhost", st->host) != 0))
                sstrncpy (vl.host, st->host, sizeof (vl.host));
 
        sstrncpy (vl.plugin, "openldap", sizeof (vl.plugin));
@@ -192,17 +188,13 @@ static void cldap_submit_value (const char *type, const char *type_instance, /*
 static void cldap_submit_derive (const char *type, const char *type_instance, /* {{{ */
                derive_t d, cldap_t *st)
 {
-       value_t v;
-       v.derive = d;
-       cldap_submit_value (type, type_instance, v, st);
+       cldap_submit_value (type, type_instance, (value_t) { .derive = d }, st);
 } /* }}} void cldap_submit_derive */
 
 static void cldap_submit_gauge (const char *type, const char *type_instance, /* {{{ */
                gauge_t g, cldap_t *st)
 {
-       value_t v;
-       v.gauge = g;
-       cldap_submit_value (type, type_instance, v, st);
+       cldap_submit_value (type, type_instance, (value_t) { .gauge = g }, st);
 } /* }}} void cldap_submit_gauge */
 
 static int cldap_read_host (user_data_t *ud) /* {{{ */
@@ -663,15 +655,13 @@ static int cldap_config_add (oconfig_item_t *ci) /* {{{ */
                                        (st->host != NULL) ? st->host : hostname_g,
                                        (st->name != NULL) ? st->name : "default");
 
-                       user_data_t ud = {
-                               .data = st
-                       };
-
                        status = plugin_register_complex_read (/* group = */ NULL,
                                        /* name      = */ callback_name,
                                        /* callback  = */ cldap_read_host,
                                        /* interval  = */ 0,
-                                       /* user_data = */ &ud);
+                                       &(user_data_t) {
+                                               .data = st,
+                                       });
                }
        }
 
index 00ae736ad4b01c70555f509c0b3580afb8fa8329..1310c00ba45c14f6f8718d34b36b8bdd51254bba 100644 (file)
@@ -99,14 +99,10 @@ static int openvpn_strsplit (char *string, char **fields, size_t size)
 static void numusers_submit (const char *pinst, const char *tinst,
                gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
-       vl.values_len = STATIC_ARRAY_SIZE (values);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values = &(value_t) { .gauge = value };
+       vl.values_len = 1;
        sstrncpy (vl.plugin, "openvpn", sizeof (vl.plugin));
        sstrncpy (vl.type, "users", sizeof (vl.type));
        if (pinst != NULL)
@@ -122,11 +118,11 @@ static void numusers_submit (const char *pinst, const char *tinst,
 static void iostats_submit (const char *pinst, const char *tinst,
                derive_t rx, derive_t tx)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = rx;
-       values[1].derive = tx;
+       value_t values[] = {
+    { .derive = rx },
+    { .derive = tx },
+  };
 
        /* NOTE ON THE NEW NAMING SCHEMA:
         *       using plugin_instance to identify each vpn config (and
@@ -136,7 +132,6 @@ static void iostats_submit (const char *pinst, const char *tinst,
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "openvpn", sizeof (vl.plugin));
        if (pinst != NULL)
                sstrncpy (vl.plugin_instance, pinst,
@@ -152,15 +147,14 @@ static void iostats_submit (const char *pinst, const char *tinst,
 static void compression_submit (const char *pinst, const char *tinst,
                derive_t uncompressed, derive_t compressed)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = uncompressed;
-       values[1].derive = compressed;
+       value_t values[] = {
+    { .derive = uncompressed },
+    { .derive = compressed },
+  };
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "openvpn", sizeof (vl.plugin));
        if (pinst != NULL)
                sstrncpy (vl.plugin_instance, pinst,
index 9eef6c1ad1c88c99798cb2b8e8857c77e42658eb..4a11d6c127c505c2e4b9852aed2f31baac05cc3c 100644 (file)
@@ -22,6 +22,7 @@
  *
  * Authors:
  *   Sebastian Harl <sh at tokkee.org>
+ *   Pavel Rochnyak <pavel2000 ngs.ru>
  **/
 
 /*
@@ -77,8 +78,9 @@
 #define PLUGIN_LOG      4
 #define PLUGIN_NOTIF    5
 #define PLUGIN_FLUSH    6
+#define PLUGIN_FLUSH_ALL 7  /* For collectd-5.6 only */
 
-#define PLUGIN_TYPES    7
+#define PLUGIN_TYPES    8
 
 #define PLUGIN_CONFIG   254
 #define PLUGIN_DATASET  255
 /* this is defined in DynaLoader.a */
 void boot_DynaLoader (PerlInterpreter *, CV *);
 
+static XS (Collectd_plugin_register_read);
+static XS (Collectd_plugin_register_write);
+static XS (Collectd_plugin_register_log);
+static XS (Collectd_plugin_register_notification);
+static XS (Collectd_plugin_register_flush);
+static XS (Collectd_plugin_unregister_read);
+static XS (Collectd_plugin_unregister_write);
+static XS (Collectd_plugin_unregister_log);
+static XS (Collectd_plugin_unregister_notification);
+static XS (Collectd_plugin_unregister_flush);
 static XS (Collectd_plugin_register_ds);
 static XS (Collectd_plugin_unregister_ds);
 static XS (Collectd_plugin_dispatch_values);
@@ -113,6 +125,14 @@ static XS (Collectd_plugin_log);
 static XS (Collectd__fc_register);
 static XS (Collectd_call_by_name);
 
+static int perl_read (user_data_t *ud);
+static int perl_write (const data_set_t *ds, const value_list_t *vl,
+               user_data_t *user_data);
+static void perl_log (int level, const char *msg, user_data_t *user_data);
+static int perl_notify (const notification_t *notif, user_data_t *user_data);
+static int perl_flush (cdtime_t timeout, const char *identifier,
+               user_data_t *user_data);
+
 /*
  * private data types
  */
@@ -165,6 +185,8 @@ extern char **environ;
  * private variables
  */
 
+static _Bool register_legacy_flush = 1;
+
 /* if perl_threads != NULL perl_threads->head must
  * point to the "base" thread */
 static c_ithread_list_t *perl_threads = NULL;
@@ -182,6 +204,18 @@ static struct {
        XS ((*f));
 } api[] =
 {
+       { "Collectd::plugin_register_read",       Collectd_plugin_register_read },
+       { "Collectd::plugin_register_write",      Collectd_plugin_register_write },
+       { "Collectd::plugin_register_log",        Collectd_plugin_register_log },
+       { "Collectd::plugin_register_notification",
+               Collectd_plugin_register_notification },
+       { "Collectd::plugin_register_flush",       Collectd_plugin_register_flush },
+       { "Collectd::plugin_unregister_read",     Collectd_plugin_unregister_read },
+       { "Collectd::plugin_unregister_write",    Collectd_plugin_unregister_write },
+       { "Collectd::plugin_unregister_log",      Collectd_plugin_unregister_log },
+       { "Collectd::plugin_unregister_notification",
+               Collectd_plugin_unregister_notification },
+       { "Collectd::plugin_unregister_flush",    Collectd_plugin_unregister_flush },
        { "Collectd::plugin_register_data_set",   Collectd_plugin_register_ds },
        { "Collectd::plugin_unregister_data_set", Collectd_plugin_unregister_ds },
        { "Collectd::plugin_dispatch_values",     Collectd_plugin_dispatch_values },
@@ -1010,7 +1044,7 @@ static int call_pv_locked (pTHX_ const char* sub_name)
                return 0;
        }
 
-       ret = call_pv (sub_name, G_SCALAR);
+       ret = call_pv (sub_name, G_SCALAR|G_EVAL);
 
        t->running = old_running;
        return ret;
@@ -1019,12 +1053,13 @@ static int call_pv_locked (pTHX_ const char* sub_name)
 /*
  * Call all working functions of the given type.
  */
-static int pplugin_call_all (pTHX_ int type, ...)
+static int pplugin_call (pTHX_ int type, ...)
 {
        int retvals = 0;
 
        va_list ap;
        int ret = 0;
+       char *subname;
 
        dSP;
 
@@ -1038,9 +1073,17 @@ static int pplugin_call_all (pTHX_ int type, ...)
 
        PUSHMARK (SP);
 
-       XPUSHs (sv_2mortal (newSViv ((IV)type)));
+       if (PLUGIN_READ == type) {
+               subname = va_arg(ap, char *);
+       }
+       else if (PLUGIN_WRITE == type) {
+               data_set_t   *ds;
+               value_list_t *vl;
 
-       if (PLUGIN_WRITE == type) {
+               AV *pds = newAV ();
+               HV *pvl = newHV ();
+
+               subname = va_arg(ap, char *);
                /*
                 * $_[0] = $plugin_type;
                 *
@@ -1066,12 +1109,6 @@ static int pplugin_call_all (pTHX_ int type, ...)
                 *   type_instance   => $type_instance
                 * };
                 */
-               data_set_t   *ds;
-               value_list_t *vl;
-
-               AV *pds = newAV ();
-               HV *pvl = newHV ();
-
                ds = va_arg (ap, data_set_t *);
                vl = va_arg (ap, value_list_t *);
 
@@ -1094,6 +1131,7 @@ static int pplugin_call_all (pTHX_ int type, ...)
                XPUSHs (sv_2mortal (newRV_noinc ((SV *)pvl)));
        }
        else if (PLUGIN_LOG == type) {
+               subname = va_arg(ap, char *);
                /*
                 * $_[0] = $level;
                 *
@@ -1103,6 +1141,10 @@ static int pplugin_call_all (pTHX_ int type, ...)
                XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
        }
        else if (PLUGIN_NOTIF == type) {
+               notification_t *n;
+               HV *notif = newHV ();
+
+               subname = va_arg(ap, char *);
                /*
                 * $_[0] =
                 * {
@@ -1116,9 +1158,6 @@ static int pplugin_call_all (pTHX_ int type, ...)
                 *   type_instance   => $type_instance
                 * };
                 */
-               notification_t *n;
-               HV *notif = newHV ();
-
                n = va_arg (ap, notification_t *);
 
                if (-1 == notification2hv (aTHX_ n, notif)) {
@@ -1132,23 +1171,53 @@ static int pplugin_call_all (pTHX_ int type, ...)
        }
        else if (PLUGIN_FLUSH == type) {
                cdtime_t timeout;
+               subname = va_arg(ap, char *);
+               /*
+                * $_[0] = $timeout;
+                * $_[1] = $identifier;
+                */
+               timeout = va_arg (ap, cdtime_t);
 
+               XPUSHs (sv_2mortal (newSVnv (CDTIME_T_TO_DOUBLE (timeout))));
+               XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
+       }
+       else if (PLUGIN_FLUSH_ALL == type) {
+               cdtime_t timeout;
+               subname = "Collectd::plugin_call_all";
                /*
                 * $_[0] = $timeout;
                 * $_[1] = $identifier;
                 */
                timeout = va_arg (ap, cdtime_t);
 
+               XPUSHs (sv_2mortal (newSViv ((IV)PLUGIN_FLUSH)));
                XPUSHs (sv_2mortal (newSVnv (CDTIME_T_TO_DOUBLE (timeout))));
                XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
        }
+       else if (PLUGIN_INIT == type) {
+               subname = "Collectd::plugin_call_all";
+               XPUSHs (sv_2mortal (newSViv ((IV)type)));
+       }
+       else if (PLUGIN_SHUTDOWN == type) {
+               subname = "Collectd::plugin_call_all";
+               XPUSHs (sv_2mortal (newSViv ((IV)type)));
+       }
+       else { /* Unknown type. Run 'plugin_call_all' and make compiler happy */
+               subname = "Collectd::plugin_call_all";
+               XPUSHs (sv_2mortal (newSViv ((IV)type)));
+       }
 
        PUTBACK;
 
-       retvals = call_pv_locked (aTHX_ "Collectd::plugin_call_all");
+       retvals = call_pv_locked (aTHX_ subname);
 
        SPAGAIN;
-       if (0 < retvals) {
+       if (SvTRUE(ERRSV)) {
+               if (PLUGIN_LOG != type)
+                       ERROR ("perl: %s error: %s", subname, SvPV_nolen(ERRSV));
+               ret = -1;
+       }
+       else if (0 < retvals) {
                SV *tmp = POPs;
                if (! SvTRUE (tmp))
                        ret = -1;
@@ -1160,7 +1229,7 @@ static int pplugin_call_all (pTHX_ int type, ...)
 
        va_end (ap);
        return ret;
-} /* static int pplugin_call_all (int, ...) */
+} /* static int pplugin_call (int, ...) */
 
 /*
  * collectd's Perl interpreter based thread implementation.
@@ -1176,6 +1245,10 @@ static void c_ithread_destroy (c_ithread_t *ithread)
        assert (NULL != perl_threads);
 
        PERL_SET_CONTEXT (aTHX);
+       /* Mark as running to avoid deadlock:
+          c_ithread_destroy -> log_debug -> perl_log()
+       */
+       ithread->running = 1;
        log_debug ("Shutting down Perl interpreter %p...", aTHX);
 
 #if COLLECT_DEBUG
@@ -1399,7 +1472,11 @@ static int fc_call (pTHX_ int type, int cb_type, pfc_user_data_t *data, ...)
        }
 
        SPAGAIN;
-       if (0 < retvals) {
+       if (SvTRUE(ERRSV)) {
+               ERROR ("perl: Collectd::fc_call error: %s", SvPV_nolen(ERRSV));
+               ret = -1;
+       }
+       else if (0 < retvals) {
                SV *tmp = POPs;
 
                /* the exec callbacks return a status, while
@@ -1568,6 +1645,173 @@ static target_proc_t ptarget = {
  * Exported Perl API.
  */
 
+static void _plugin_register_generic_userdata (pTHX, int type, const char *desc)
+{
+       int ret   = 0;
+       user_data_t userdata;
+       char *pluginname;
+
+       dXSARGS;
+
+       if (2 != items) {
+               log_err ("Usage: Collectd::plugin_register_%s(pluginname, subname)",
+                                       desc);
+               XSRETURN_EMPTY;
+       }
+
+       if (! SvOK (ST (0))) {
+               log_err ("Collectd::plugin_register_%s(pluginname, subname): "
+                        "Invalid pluginname", desc);
+               XSRETURN_EMPTY;
+       }
+       if (! SvOK (ST (1))) {
+               log_err ("Collectd::plugin_register_%s(pluginname, subname): "
+                        "Invalid subname", desc);
+               XSRETURN_EMPTY;
+       }
+
+       /* Use pluginname as-is to allow flush a single perl plugin */
+       pluginname = SvPV_nolen (ST (0));
+
+       log_debug ("Collectd::plugin_register_%s: "
+                       "plugin = \"%s\", sub = \"%s\"",
+                       desc, pluginname, SvPV_nolen (ST (1)));
+
+       memset(&userdata, 0, sizeof(userdata));
+       userdata.data = strdup(SvPV_nolen (ST (1)));
+       userdata.free_func = free;
+
+       if (PLUGIN_READ == type) {
+               ret = plugin_register_complex_read(
+                       "perl",                /* group */
+                       pluginname,
+                       perl_read,
+                       plugin_get_interval(), /* Default interval */
+                       &userdata);
+       }
+       else if (PLUGIN_WRITE == type) {
+               ret = plugin_register_write(pluginname, perl_write, &userdata);
+       }
+       else if (PLUGIN_LOG == type) {
+               ret = plugin_register_log(pluginname, perl_log, &userdata);
+       }
+       else if (PLUGIN_NOTIF == type) {
+               ret = plugin_register_notification(pluginname, perl_notify, &userdata);
+       }
+       else if (PLUGIN_FLUSH == type) {
+               if (1 == register_legacy_flush) { /* For collectd-5.7 only, #1731 */
+                       register_legacy_flush = 0;
+                       ret = plugin_register_flush("perl", perl_flush, /* user_data = */ NULL);
+               }
+
+               if (0 == ret)
+                       ret = plugin_register_flush(pluginname, perl_flush, &userdata);
+       }
+       else {
+               ret = -1;
+       }
+
+       if (0 == ret)
+               XSRETURN_YES;
+       else {
+               free (userdata.data);
+               XSRETURN_EMPTY;
+       }
+} /* static void _plugin_register_generic_userdata ( ... ) */
+
+/*
+ * Collectd::plugin_register_TYPE (pluginname, subname).
+ *
+ * pluginname:
+ *   name of the perl plugin
+ *
+ * subname:
+ *   name of the plugin's subroutine that does the work
+ */
+
+static XS (Collectd_plugin_register_read) {
+       return _plugin_register_generic_userdata(aTHX, PLUGIN_READ, "read");
+}
+
+static XS (Collectd_plugin_register_write) {
+       return _plugin_register_generic_userdata(aTHX, PLUGIN_WRITE, "write");
+}
+
+static XS (Collectd_plugin_register_log) {
+       return _plugin_register_generic_userdata(aTHX, PLUGIN_LOG, "log");
+}
+
+static XS (Collectd_plugin_register_notification) {
+       return _plugin_register_generic_userdata(aTHX, PLUGIN_NOTIF, "notification");
+}
+
+static XS (Collectd_plugin_register_flush) {
+       return _plugin_register_generic_userdata(aTHX, PLUGIN_FLUSH, "flush");
+}
+
+typedef int perl_unregister_function_t(const char *name);
+
+static void _plugin_unregister_generic (pTHX,
+                               perl_unregister_function_t *unreg, const char *desc)
+{
+       dXSARGS;
+
+       if (1 != items) {
+               log_err ("Usage: Collectd::plugin_unregister_%s(pluginname)", desc);
+               XSRETURN_EMPTY;
+       }
+
+       if (! SvOK (ST (0))) {
+               log_err ("Collectd::plugin_unregister_%s(pluginname): "
+                        "Invalid pluginname", desc);
+               XSRETURN_EMPTY;
+       }
+
+       log_debug ("Collectd::plugin_unregister_%s: plugin = \"%s\"",
+                       desc, SvPV_nolen (ST (0)));
+
+       unreg(SvPV_nolen (ST (0)));
+
+       XSRETURN_EMPTY;
+
+       return;
+} /* static void _plugin_unregister_generic ( ... ) */
+
+/*
+ * Collectd::plugin_unregister_TYPE (pluginname).
+ *
+ * TYPE:
+ *   type of callback to be unregistered: read, write, log, notification, flush
+ *
+ * pluginname:
+ *   name of the perl plugin
+ */
+
+static XS (Collectd_plugin_unregister_read) {
+       return _plugin_unregister_generic(aTHX,
+                               plugin_unregister_read, "read");
+}
+
+static XS (Collectd_plugin_unregister_write) {
+       return _plugin_unregister_generic(aTHX,
+                               plugin_unregister_write, "write");
+}
+
+static XS (Collectd_plugin_unregister_log) {
+       return _plugin_unregister_generic(aTHX,
+                               plugin_unregister_log, "log");
+}
+
+static XS (Collectd_plugin_unregister_notification) {
+       return _plugin_unregister_generic(aTHX,
+                               plugin_unregister_notification, "notification");
+}
+
+static XS (Collectd_plugin_unregister_flush) {
+       return _plugin_unregister_generic(aTHX,
+                               plugin_unregister_flush, "flush");
+}
+
 /*
  * Collectd::plugin_register_data_set (type, dataset).
  *
@@ -1955,14 +2199,14 @@ static int perl_init (void)
        assert (aTHX == perl_threads->head->interp);
        pthread_mutex_lock (&perl_threads->mutex);
 
-       status = pplugin_call_all (aTHX_ PLUGIN_INIT);
+       status = pplugin_call (aTHX_ PLUGIN_INIT);
 
        pthread_mutex_unlock (&perl_threads->mutex);
 
        return status;
 } /* static int perl_init (void) */
 
-static int perl_read (void)
+static int perl_read (user_data_t *user_data)
 {
        dTHX;
 
@@ -1986,11 +2230,12 @@ static int perl_read (void)
 
        log_debug ("perl_read: c_ithread: interp = %p (active threads: %i)",
                        aTHX, perl_threads->number_of_threads);
-       return pplugin_call_all (aTHX_ PLUGIN_READ);
-} /* static int perl_read (void) */
+
+       return pplugin_call (aTHX_ PLUGIN_READ, user_data->data);
+} /* static int perl_read (user_data_t *user_data) */
 
 static int perl_write (const data_set_t *ds, const value_list_t *vl,
-               user_data_t __attribute__((unused)) *user_data)
+               user_data_t *user_data)
 {
        int status;
        dTHX;
@@ -2016,7 +2261,7 @@ static int perl_write (const data_set_t *ds, const value_list_t *vl,
 
        log_debug ("perl_write: c_ithread: interp = %p (active threads: %i)",
                        aTHX, perl_threads->number_of_threads);
-       status = pplugin_call_all (aTHX_ PLUGIN_WRITE, ds, vl);
+       status = pplugin_call (aTHX_ PLUGIN_WRITE, user_data->data, ds, vl);
 
        if (aTHX == perl_threads->head->interp)
                pthread_mutex_unlock (&perl_threads->mutex);
@@ -2025,7 +2270,7 @@ static int perl_write (const data_set_t *ds, const value_list_t *vl,
 } /* static int perl_write (const data_set_t *, const value_list_t *) */
 
 static void perl_log (int level, const char *msg,
-               user_data_t __attribute__((unused)) *user_data)
+               user_data_t *user_data)
 {
        dTHX;
 
@@ -2050,7 +2295,7 @@ static void perl_log (int level, const char *msg,
        if (aTHX == perl_threads->head->interp)
                pthread_mutex_lock (&perl_threads->mutex);
 
-       pplugin_call_all (aTHX_ PLUGIN_LOG, level, msg);
+       pplugin_call (aTHX_ PLUGIN_LOG, user_data->data, level, msg);
 
        if (aTHX == perl_threads->head->interp)
                pthread_mutex_unlock (&perl_threads->mutex);
@@ -2058,8 +2303,7 @@ static void perl_log (int level, const char *msg,
        return;
 } /* static void perl_log (int, const char *) */
 
-static int perl_notify (const notification_t *notif,
-               user_data_t __attribute__((unused)) *user_data)
+static int perl_notify (const notification_t *notif, user_data_t *user_data)
 {
        dTHX;
 
@@ -2075,11 +2319,11 @@ static int perl_notify (const notification_t *notif,
 
                aTHX = t->interp;
        }
-       return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
+       return pplugin_call (aTHX_ PLUGIN_NOTIF, user_data->data, notif);
 } /* static int perl_notify (const notification_t *) */
 
 static int perl_flush (cdtime_t timeout, const char *identifier,
-               user_data_t __attribute__((unused)) *user_data)
+               user_data_t *user_data)
 {
        dTHX;
 
@@ -2095,7 +2339,12 @@ static int perl_flush (cdtime_t timeout, const char *identifier,
 
                aTHX = t->interp;
        }
-       return pplugin_call_all (aTHX_ PLUGIN_FLUSH, timeout, identifier);
+
+       /* For collectd-5.6 only, #1731 */
+       if (user_data == NULL || user_data->data == NULL)
+               return pplugin_call (aTHX_ PLUGIN_FLUSH_ALL, timeout, identifier);
+
+       return pplugin_call (aTHX_ PLUGIN_FLUSH, user_data->data, timeout, identifier);
 } /* static int perl_flush (const int) */
 
 static int perl_shutdown (void)
@@ -2106,6 +2355,7 @@ static int perl_shutdown (void)
        dTHX;
 
        plugin_unregister_complex_config ("perl");
+       plugin_unregister_read_group ("perl");
 
        if (NULL == perl_threads)
                return 0;
@@ -2121,14 +2371,10 @@ static int perl_shutdown (void)
        log_debug ("perl_shutdown: c_ithread: interp = %p (active threads: %i)",
                        aTHX, perl_threads->number_of_threads);
 
-       plugin_unregister_log ("perl");
-       plugin_unregister_notification ("perl");
        plugin_unregister_init ("perl");
-       plugin_unregister_read ("perl");
-       plugin_unregister_write ("perl");
-       plugin_unregister_flush ("perl");
+       plugin_unregister_flush ("perl"); /* For collectd-5.6 only, #1731 */
 
-       ret = pplugin_call_all (aTHX_ PLUGIN_SHUTDOWN);
+       ret = pplugin_call (aTHX_ PLUGIN_SHUTDOWN);
 
        pthread_mutex_lock (&perl_threads->mutex);
        t = perl_threads->tail;
@@ -2338,15 +2584,7 @@ static int init_pi (int argc, char **argv)
 
        perl_run (aTHX);
 
-       plugin_register_log ("perl", perl_log, /* user_data = */ NULL);
-       plugin_register_notification ("perl", perl_notify,
-                       /* user_data = */ NULL);
        plugin_register_init ("perl", perl_init);
-
-       plugin_register_read ("perl", perl_read);
-
-       plugin_register_write ("perl", perl_write, /* user_data = */ NULL);
-       plugin_register_flush ("perl", perl_flush, /* user_data = */ NULL);
        plugin_register_shutdown ("perl", perl_shutdown);
        return 0;
 } /* static int init_pi (const char **, const int) */
@@ -2568,6 +2806,8 @@ static int perl_config (oconfig_item_t *ci)
                        current_status = perl_config_includedir (aTHX_ c);
                else if (0 == strcasecmp (c->key, "Plugin"))
                        current_status = perl_config_plugin (aTHX_ c);
+               else if (0 == strcasecmp (c->key, "RegisterLegacyFlush"))
+                       cf_util_get_boolean (c, &register_legacy_flush);
                else
                {
                        log_warn ("Ignoring unknown config key \"%s\".", c->key);
index d7a5a15cff11b4cd3d2baf07297161fcc56867f3..ecaa869c0658c6a549899288ce18c2e05566b953 100644 (file)
--- a/src/pf.c
+++ b/src/pf.c
@@ -70,7 +70,6 @@ static void pf_submit (char const *type, char const *type_instance,
 
        vl.values = values;
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "pf", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof(vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof(vl.type_instance));
index 8a0902aa9c0136a0b6b4dce87498bd55f67b087e..5571ff2600b3cd98c5f1c236323fe97d50db26c5 100644 (file)
@@ -677,38 +677,35 @@ static int plugin_shutdown (void) /* {{{ */
 
 static int plugin_submit (const pinba_statnode_t *res) /* {{{ */
 {
-  value_t value;
   value_list_t vl = VALUE_LIST_INIT;
 
-  vl.values = &value;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "pinba", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, res->name, sizeof (vl.plugin_instance));
 
-  value.derive = res->req_count;
+  vl.values = &(value_t) { .derive = res->req_count };
   sstrncpy (vl.type, "total_requests", sizeof (vl.type));
   plugin_dispatch_values (&vl);
 
-  value.derive = float_counter_get (&res->req_time, /* factor = */ 1000);
+  vl.values = &(value_t) { .derive = float_counter_get (&res->req_time, /* factor = */ 1000) };
   sstrncpy (vl.type, "total_time_in_ms", sizeof (vl.type));
   plugin_dispatch_values (&vl);
 
-  value.derive = res->doc_size;
+  vl.values = &(value_t) { .derive = res->doc_size };
   sstrncpy (vl.type, "total_bytes", sizeof (vl.type));
   plugin_dispatch_values (&vl);
 
-  value.derive = float_counter_get (&res->ru_utime, /* factor = */ 100);
+  vl.values = &(value_t) { .derive = float_counter_get (&res->ru_utime, /* factor = */ 100) };
   sstrncpy (vl.type, "cpu", sizeof (vl.type));
   sstrncpy (vl.type_instance, "user", sizeof (vl.type_instance));
   plugin_dispatch_values (&vl);
 
-  value.derive = float_counter_get (&res->ru_stime, /* factor = */ 100);
+  vl.values = &(value_t) { .derive = float_counter_get (&res->ru_stime, /* factor = */ 100) };
   sstrncpy (vl.type, "cpu", sizeof (vl.type));
   sstrncpy (vl.type_instance, "system", sizeof (vl.type_instance));
   plugin_dispatch_values (&vl);
 
-  value.gauge = res->mem_peak;
+  vl.values = &(value_t) { .gauge = res->mem_peak };
   sstrncpy (vl.type, "memory", sizeof (vl.type));
   sstrncpy (vl.type_instance, "peak", sizeof (vl.type_instance));
   plugin_dispatch_values (&vl);
index 5f66aab341f552cadb2d786bde09784d2272b2be..64408491d410c71b7d4f6322b60de8175139660c 100644 (file)
@@ -615,16 +615,11 @@ static int ping_config (const char *key, const char *value) /* {{{ */
 static void submit (const char *host, const char *type, /* {{{ */
     gauge_t value)
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0].gauge = value;
-
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = value };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "ping", sizeof (vl.plugin));
-  sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
   sstrncpy (vl.type_instance, host, sizeof (vl.type_instance));
   sstrncpy (vl.type, type, sizeof (vl.type));
 
index 084eae453393a3bb86c0766966d2e45b5a514e5f..8b6094923c448b3a1060a7f1752bd8f4e7f4bca2 100644 (file)
@@ -833,7 +833,7 @@ static int c_psql_write (const data_set_t *ds, const value_list_t *vl,
        assert (db->database != NULL);
        assert (db->writers != NULL);
 
-       if (rfc3339nano (time_str, sizeof (time_str), vl->time) != 0) {
+       if (rfc3339nano_local (time_str, sizeof (time_str), vl->time) != 0) {
                log_err ("c_psql_write: Failed to convert time to RFC 3339 format");
                return -1;
        }
index f907d006ed6172a5cf9129ba374e0bffd41a0d4c..d7aa4e9dbe8ea8d94ca739baa2750b1d2026a707 100644 (file)
@@ -43,6 +43,7 @@
 # define UNIX_PATH_MAX sizeof (((struct sockaddr_un *)0)->sun_path)
 #endif
 #define FUNC_ERROR(func) do { char errbuf[1024]; ERROR ("powerdns plugin: %s failed: %s", func, sstrerror (errno, errbuf, sizeof (errbuf))); } while (0)
+#define SOCK_ERROR(func, sockpath) do { char errbuf[1024]; ERROR ("powerdns plugin: Socket `%s` %s failed: %s", sockpath, func, sstrerror (errno, errbuf, sizeof (errbuf))); } while (0)
 
 #define SERVER_SOCKET  LOCALSTATEDIR"/run/pdns.controlsocket"
 #define SERVER_COMMAND "SHOW * \n"
@@ -300,10 +301,10 @@ static char *local_sockpath = NULL;
 
 /* <https://doc.powerdns.com/md/recursor/stats/> */
 static void submit (const char *plugin_instance, /* {{{ */
-    const char *pdns_type, const char *value)
+    const char *pdns_type, const char *value_str)
 {
   value_list_t vl = VALUE_LIST_INIT;
-  value_t values[1];
+  value_t value;
 
   const char *type = NULL;
   const char *type_instance = NULL;
@@ -318,7 +319,7 @@ static void submit (const char *plugin_instance, /* {{{ */
   if (i >= lookup_table_length)
   {
     INFO ("powerdns plugin: submit: Not found in lookup table: %s = %s;",
-        pdns_type, value);
+        pdns_type, value_str);
     return;
   }
 
@@ -345,16 +346,15 @@ static void submit (const char *plugin_instance, /* {{{ */
     return;
   }
 
-  if (0 != parse_value (value, &values[0], ds->ds[0].type))
+  if (0 != parse_value (value_str, &value, ds->ds[0].type))
   {
     ERROR ("powerdns plugin: Cannot convert `%s' "
-        "to a number.", value);
+        "to a number.", value_str);
     return;
   }
 
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "powerdns", sizeof (vl.plugin));
   sstrncpy (vl.type, type, sizeof (vl.type));
   if (type_instance != NULL)
@@ -395,7 +395,7 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
   status = unlink (sa_unix.sun_path);
   if ((status != 0) && (errno != ENOENT))
   {
-    FUNC_ERROR ("unlink");
+    SOCK_ERROR ("unlink", sa_unix.sun_path);
     close (sd);
     return (-1);
   }
@@ -407,7 +407,7 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
     status = bind (sd, (struct sockaddr *) &sa_unix, sizeof (sa_unix));
     if (status != 0)
     {
-      FUNC_ERROR ("bind");
+      SOCK_ERROR ("bind", sa_unix.sun_path);
       break;
     }
 
@@ -415,7 +415,7 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
     status = chmod (sa_unix.sun_path, 0666);
     if (status != 0)
     {
-      FUNC_ERROR ("chmod");
+      SOCK_ERROR ("chmod", sa_unix.sun_path);
       break;
     }
 
@@ -428,7 +428,7 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
     status = setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO, &stv_timeout, sizeof (stv_timeout));
     if (status != 0)
     {
-      FUNC_ERROR ("setsockopt");
+      SOCK_ERROR ("setsockopt", sa_unix.sun_path);
       break;
     }
 
@@ -436,21 +436,21 @@ static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
         sizeof (item->sockaddr));
     if (status != 0)
     {
-      FUNC_ERROR ("connect");
+      SOCK_ERROR ("connect", sa_unix.sun_path);
       break;
     }
 
     status = send (sd, item->command, strlen (item->command), 0);
     if (status < 0)
     {
-      FUNC_ERROR ("send");
+      SOCK_ERROR ("send", sa_unix.sun_path);
       break;
     }
 
     status = recv (sd, temp, sizeof (temp), /* flags = */ 0);
     if (status < 0)
     {
-      FUNC_ERROR ("recv");
+      SOCK_ERROR ("recv", sa_unix.sun_path);
       break;
     }
     buffer_size = status + 1;
@@ -513,7 +513,7 @@ static int powerdns_get_data_stream (list_item_t *item, /* {{{ */
       sizeof (item->sockaddr));
   if (status != 0)
   {
-    FUNC_ERROR ("connect");
+    SOCK_ERROR ("connect", item->sockaddr.sun_path);
     close (sd);
     return (-1);
   }
@@ -523,7 +523,7 @@ static int powerdns_get_data_stream (list_item_t *item, /* {{{ */
       /* flags = */ 0);
   if (status < 0)
   {
-    FUNC_ERROR ("send");
+    SOCK_ERROR ("send", item->sockaddr.sun_path);
     close (sd);
     return (-1);
   }
@@ -535,7 +535,7 @@ static int powerdns_get_data_stream (list_item_t *item, /* {{{ */
     status = recv (sd, temp, sizeof (temp), /* flags = */ 0);
     if (status < 0)
     {
-      FUNC_ERROR ("recv");
+      SOCK_ERROR ("recv", item->sockaddr.sun_path);
       break;
     }
     else if (status == 0)
index 0513a156a999d4330ca63599b176abc31b68682d..e1660c55455e63c4fe29ce040d8a45ec1652681b 100644 (file)
@@ -170,13 +170,9 @@ typedef struct procstat_entry_s
        unsigned long vmem_code;
        unsigned long stack_size;
 
-       unsigned long vmem_minflt;
-       unsigned long vmem_majflt;
        derive_t      vmem_minflt_counter;
        derive_t      vmem_majflt_counter;
 
-       unsigned long cpu_user;
-       unsigned long cpu_system;
        derive_t      cpu_user_counter;
        derive_t      cpu_system_counter;
 
@@ -185,9 +181,11 @@ typedef struct procstat_entry_s
        derive_t io_wchar;
        derive_t io_syscr;
        derive_t io_syscw;
+       _Bool    has_io;
 
        derive_t cswitch_vol;
        derive_t cswitch_invol;
+       _Bool    has_cswitch;
 
        struct procstat_entry_s *next;
 } procstat_entry_t;
@@ -229,6 +227,7 @@ typedef struct procstat
 
 static procstat_t *list_head_g = NULL;
 
+static _Bool want_init = 1;
 static _Bool report_ctx_switch = 0;
 
 #if HAVE_THREAD_INFO
@@ -241,6 +240,7 @@ static mach_msg_type_number_t     pset_list_len;
 
 #elif KERNEL_LINUX
 static long pagesize_g;
+static void ps_fill_details (const procstat_t *ps, procstat_entry_t *entry);
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
@@ -366,25 +366,24 @@ static int ps_list_match (const char *name, const char *cmdline, procstat_t *ps)
        return (0);
 } /* int ps_list_match */
 
-static void ps_update_counter (_Bool init, derive_t *group_counter,
-                               derive_t *curr_counter, unsigned long *curr_value,
-                               derive_t new_counter, unsigned long new_value)
+static void ps_update_counter (derive_t *group_counter,
+                               derive_t *curr_counter, derive_t new_counter)
 {
-       if (init)
+       unsigned long curr_value;
+       
+       if (want_init)
        {
-               *curr_value = new_value;
-               *curr_counter += new_value;
-               *group_counter += new_value;
+               *curr_counter = new_counter;
                return;
        }
 
        if (new_counter < *curr_counter)
-               *curr_value = new_counter + (ULONG_MAX - *curr_counter);
+               curr_value = new_counter + (ULONG_MAX - *curr_counter);
        else
-               *curr_value = new_counter - *curr_counter;
+               curr_value = new_counter - *curr_counter;
 
        *curr_counter = new_counter;
-       *group_counter += *curr_value;
+       *group_counter += curr_value;
 }
 
 /* add process entry to 'instances' of process 'name' (or refresh it) */
@@ -397,11 +396,13 @@ static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t
 
        for (procstat_t *ps = list_head_g; ps != NULL; ps = ps->next)
        {
-               _Bool want_init;
-
                if ((ps_list_match (name, cmdline, ps)) == 0)
                        continue;
 
+#if KERNEL_LINUX
+               ps_fill_details(ps, entry);
+#endif
+
                for (pse = ps->instances; pse != NULL; pse = pse->next)
                        if ((pse->id == entry->id) || (pse->next == NULL))
                                break;
@@ -454,27 +455,23 @@ static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t
                ps->cswitch_vol   += ((pse->cswitch_vol == -1)?0:pse->cswitch_vol);
                ps->cswitch_invol += ((pse->cswitch_invol == -1)?0:pse->cswitch_invol);
 
-               want_init = (entry->vmem_minflt_counter == 0)
-                               && (entry->vmem_majflt_counter == 0);
-               ps_update_counter (want_init,
+               ps_update_counter (
                                &ps->vmem_minflt_counter,
-                               &pse->vmem_minflt_counter, &pse->vmem_minflt,
-                               entry->vmem_minflt_counter, entry->vmem_minflt);
-               ps_update_counter (want_init,
+                               &pse->vmem_minflt_counter,
+                               entry->vmem_minflt_counter);
+               ps_update_counter (
                                &ps->vmem_majflt_counter,
-                               &pse->vmem_majflt_counter, &pse->vmem_majflt,
-                               entry->vmem_majflt_counter, entry->vmem_majflt);
+                               &pse->vmem_majflt_counter,
+                               entry->vmem_majflt_counter);
 
-               want_init = (entry->cpu_user_counter == 0)
-                               && (entry->cpu_system_counter == 0);
-               ps_update_counter (want_init,
+               ps_update_counter (
                                &ps->cpu_user_counter,
-                               &pse->cpu_user_counter, &pse->cpu_user,
-                               entry->cpu_user_counter, entry->cpu_user);
-               ps_update_counter (want_init,
+                               &pse->cpu_user_counter,
+                               entry->cpu_user_counter);
+               ps_update_counter (
                                &ps->cpu_system_counter,
-                               &pse->cpu_system_counter, &pse->cpu_system,
-                               entry->cpu_system_counter, entry->cpu_system);
+                               &pse->cpu_system_counter,
+                               entry->cpu_system_counter);
        }
 }
 
@@ -660,14 +657,10 @@ static int ps_init (void)
 /* submit global state (e.g.: qty of zombies, running, etc..) */
 static void ps_submit_state (const char *state, double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        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, "ps_state", sizeof (vl.type));
@@ -679,12 +672,10 @@ static void ps_submit_state (const char *state, double value)
 /* submit info about specific process (e.g.: memory taken, cpu usage, etc..) */
 static void ps_submit_proc_list (procstat_t *ps)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
+       value_t values[2];
 
        vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance));
 
@@ -784,14 +775,10 @@ static void ps_submit_proc_list (procstat_t *ps)
 #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 = &(value_t) { .derive = value };
        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));
@@ -803,7 +790,7 @@ static void ps_submit_fork_rate (derive_t value)
 
 /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
 #if KERNEL_LINUX
-static procstat_t *ps_read_tasks_status (long pid, procstat_t *ps)
+static int ps_read_tasks_status (procstat_entry_t *ps)
 {
        char           dirname[64];
        DIR           *dh;
@@ -816,12 +803,12 @@ static procstat_t *ps_read_tasks_status (long pid, procstat_t *ps)
        char *fields[8];
        int numfields;
 
-       ssnprintf (dirname, sizeof (dirname), "/proc/%li/task", pid);
+       ssnprintf (dirname, sizeof (dirname), "/proc/%li/task", ps->id);
 
        if ((dh = opendir (dirname)) == NULL)
        {
                DEBUG ("Failed to open directory `%s'", dirname);
-               return (NULL);
+               return (-1);
        }
 
        while ((ent = readdir (dh)) != NULL)
@@ -833,7 +820,7 @@ static procstat_t *ps_read_tasks_status (long pid, procstat_t *ps)
 
                tpid = ent->d_name;
 
-               ssnprintf (filename, sizeof (filename), "/proc/%li/task/%s/status", pid, tpid);
+               ssnprintf (filename, sizeof (filename), "/proc/%li/task/%s/status", ps->id, tpid);
                if ((fh = fopen (filename, "r")) == NULL)
                {
                        DEBUG ("Failed to open file `%s'", filename);
@@ -883,7 +870,7 @@ static procstat_t *ps_read_tasks_status (long pid, procstat_t *ps)
        ps->cswitch_vol = cswitch_vol;
        ps->cswitch_invol = cswitch_invol;
 
-       return (ps);
+       return (0);
 } /* int *ps_read_tasks_status */
 
 /* Read data from /proc/pid/status */
@@ -957,7 +944,7 @@ static procstat_t *ps_read_status (long pid, procstat_t *ps)
        return (ps);
 } /* procstat_t *ps_read_vmem */
 
-static procstat_t *ps_read_io (long pid, procstat_t *ps)
+static int ps_read_io (procstat_entry_t *ps)
 {
        FILE *fh;
        char buffer[1024];
@@ -966,9 +953,9 @@ static procstat_t *ps_read_io (long pid, procstat_t *ps)
        char *fields[8];
        int numfields;
 
-       ssnprintf (filename, sizeof (filename), "/proc/%li/io", pid);
+       ssnprintf (filename, sizeof (filename), "/proc/%li/io", ps->id);
        if ((fh = fopen (filename, "r")) == NULL)
-               return (NULL);
+               return (-1);
 
        while (fgets (buffer, sizeof (buffer), fh) != NULL)
        {
@@ -1008,9 +995,36 @@ static procstat_t *ps_read_io (long pid, procstat_t *ps)
                WARNING ("processes: fclose: %s",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
        }
+       return (0);
+} /* int ps_read_io (...) */
 
-       return (ps);
-} /* procstat_t *ps_read_io */
+static void ps_fill_details (const procstat_t *ps, procstat_entry_t *entry)
+{
+       if ( entry->has_io == 0 && ps_read_io (entry) != 0 )
+       {
+               /* no io data */
+               entry->io_rchar = -1;
+               entry->io_wchar = -1;
+               entry->io_syscr = -1;
+               entry->io_syscw = -1;
+
+               DEBUG("ps_read_process: not get io data for pid %li", entry->id);
+       }
+       entry->has_io = 1;
+
+       if ( report_ctx_switch )
+       {
+               if ( entry->has_cswitch == 0 && ps_read_tasks_status(entry) != 0 )
+               {
+                       entry->cswitch_vol = -1;
+                       entry->cswitch_invol = -1;
+
+                       DEBUG("ps_read_tasks_status: not get context "
+                                       "switch data for pid %li", entry->id);
+               }
+               entry->has_cswitch = 1;
+       }
+} /* void ps_fill_details (...) */
 
 static int ps_read_process (long pid, procstat_t *ps, char *state)
 {
@@ -1143,29 +1157,6 @@ static int ps_read_process (long pid, procstat_t *ps, char *state)
        ps->vmem_rss = (unsigned long) vmem_rss;
        ps->stack_size = (unsigned long) stack_size;
 
-       if ( (ps_read_io (pid, ps)) == NULL)
-       {
-               /* no io data */
-               ps->io_rchar = -1;
-               ps->io_wchar = -1;
-               ps->io_syscr = -1;
-               ps->io_syscw = -1;
-
-               DEBUG("ps_read_process: not get io data for pid %li", pid);
-       }
-
-       if ( report_ctx_switch )
-       {
-               if ( (ps_read_tasks_status(pid, ps)) == NULL)
-               {
-                       ps->cswitch_vol = -1;
-                       ps->cswitch_invol = -1;
-
-                       DEBUG("ps_read_tasks_status: not get context "
-                                       "switch data for pid %li", pid);
-               }
-       }
-
        /* success */
        return (0);
 } /* int ps_read_process (...) */
@@ -1854,14 +1845,10 @@ static int ps_read (void)
                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;
@@ -1986,13 +1973,9 @@ static int ps_read (void)
                        pse.vmem_data = procs[i].ki_dsize * pagesize;
                        pse.vmem_code = procs[i].ki_tsize * pagesize;
                        pse.stack_size = procs[i].ki_ssize * pagesize;
-                       pse.vmem_minflt = 0;
                        pse.vmem_minflt_counter = procs[i].ki_rusage.ru_minflt;
-                       pse.vmem_majflt = 0;
                        pse.vmem_majflt_counter = procs[i].ki_rusage.ru_majflt;
 
-                       pse.cpu_user = 0;
-                       pse.cpu_system = 0;
                        pse.cpu_user_counter = 0;
                        pse.cpu_system_counter = 0;
                        /*
@@ -2132,13 +2115,9 @@ static int ps_read (void)
                        pse.vmem_code = procs[i].p_vm_tsize * pagesize;
                        pse.stack_size = procs[i].p_vm_ssize * pagesize;
                        pse.vmem_size = pse.stack_size + pse.vmem_code + pse.vmem_data;
-                       pse.vmem_minflt = 0;
                        pse.vmem_minflt_counter = procs[i].p_uru_minflt;
-                       pse.vmem_majflt = 0;
                        pse.vmem_majflt_counter = procs[i].p_uru_majflt;
 
-                       pse.cpu_user = 0;
-                       pse.cpu_system = 0;
                        pse.cpu_user_counter = procs[i].p_uutime_usec +
                                                (1000000lu * procs[i].p_uutime_sec);
                        pse.cpu_system_counter = procs[i].p_ustime_usec +
@@ -2270,7 +2249,6 @@ static int ps_read (void)
                                        break;
                        }
 
-                       pse.cpu_user = 0;
                        /* tv_usec is nanosec ??? */
                        pse.cpu_user_counter = procentry[i].pi_ru.ru_utime.tv_sec * 1000000 +
                                procentry[i].pi_ru.ru_utime.tv_usec / 1000;
@@ -2280,9 +2258,7 @@ static int ps_read (void)
                        pse.cpu_system_counter = procentry[i].pi_ru.ru_stime.tv_sec * 1000000 +
                                procentry[i].pi_ru.ru_stime.tv_usec / 1000;
 
-                       pse.vmem_minflt = 0;
                        pse.vmem_minflt_counter = procentry[i].pi_minflt;
-                       pse.vmem_majflt = 0;
                        pse.vmem_majflt_counter = procentry[i].pi_majflt;
 
                        pse.vmem_size = procentry[i].pi_tsize + procentry[i].pi_dvm * pagesize;
@@ -2380,14 +2356,10 @@ static int ps_read (void)
                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;
@@ -2432,6 +2404,8 @@ static int ps_read (void)
        read_fork_rate();
 #endif /* KERNEL_SOLARIS */
 
+       want_init = 0;
+
        return (0);
 } /* int ps_read */
 
index 208da8b20f41b9c89e6342c4d7bac71bc81dcfb5..f7fd256ba0dae662e06a313413363d7f10d99811 100644 (file)
@@ -55,11 +55,11 @@ static ignorelist_t *values_list = NULL;
 static void submit (const char *protocol_name,
     const char *str_key, const char *str_value)
 {
-  value_t values[1];
+  value_t value;
   value_list_t vl = VALUE_LIST_INIT;
   int status;
 
-  status = parse_value (str_value, values, DS_TYPE_DERIVE);
+  status = parse_value (str_value, &value, DS_TYPE_DERIVE);
   if (status != 0)
   {
     ERROR ("protocols plugin: Parsing string as integer failed: %s",
@@ -67,9 +67,8 @@ static void submit (const char *protocol_name,
     return;
   }
 
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "protocols", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, protocol_name, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, "protocol_counter", sizeof (vl.type));
index ec2317b3721d00149e68fdc1567f59340da2cf99..5274262bbd6b5826ca40b8ec6940a20a7ea297cb 100644 (file)
@@ -665,12 +665,11 @@ static PyObject *cpy_register_generic_userdata(void *reg, void *handler, PyObjec
        c->data = data;
        c->next = NULL;
 
-       user_data_t user_data = {
-               .data = c,
-               .free_func = cpy_destroy_user_data
-       };
+       register_function(buf, handler, &(user_data_t) {
+                               .data = c,
+                               .free_func = cpy_destroy_user_data,
+                       });
 
-       register_function(buf, handler, &user_data);
        ++cpy_num_callbacks;
        return cpy_string_to_unicode_or_bytes(buf);
 }
@@ -704,13 +703,12 @@ static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwd
        c->data = data;
        c->next = NULL;
 
-       user_data_t user_data = {
-               .data = c,
-               .free_func = cpy_destroy_user_data
-       };
-
        plugin_register_complex_read(/* group = */ "python", buf,
-                       cpy_read_callback, DOUBLE_TO_CDTIME_T (interval), &user_data);
+                       cpy_read_callback, DOUBLE_TO_CDTIME_T (interval),
+                       &(user_data_t) {
+                               .data = c,
+                               .free_func = cpy_destroy_user_data,
+                       });
        ++cpy_num_callbacks;
        return cpy_string_to_unicode_or_bytes(buf);
 }
index 5214eccc1e6efc39db7ae37579c6b7d6a5db897f..c3c8efa5c80cc790b8a88ba88f501d70a2512baa 100644 (file)
@@ -252,14 +252,10 @@ static void redis_submit (char *plugin_instance,
     const char *type, const char *type_instance,
     value_t value) /* {{{ */
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  values[0] = value;
-
-  vl.values = values;
+  vl.values = &value;
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "redis", sizeof (vl.plugin));
   if (plugin_instance != NULL)
     sstrncpy (vl.plugin_instance, plugin_instance,
index a270f484981dbde8a9e1ac2681a8205c445049ba..5e8a2943f762ff5b39b34e8928eb096b6b92a203 100644 (file)
@@ -52,11 +52,11 @@ typedef struct cr_data_s cr_data_t;
 static void cr_submit_io (cr_data_t *rd, const char *type, /* {{{ */
     const char *type_instance, derive_t rx, derive_t tx)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = rx;
-       values[1].derive = tx;
+       value_t values[] = {
+         { .derive = rx },
+         { .derive = tx },
+       };
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
@@ -325,7 +325,6 @@ static int cr_config_router (oconfig_item_t *ci) /* {{{ */
 {
   cr_data_t *router_data;
   char read_name[128];
-  user_data_t user_data;
   int status;
 
   router_data = calloc (1, sizeof (*router_data));
@@ -409,11 +408,12 @@ static int cr_config_router (oconfig_item_t *ci) /* {{{ */
   }
 
   ssnprintf (read_name, sizeof (read_name), "routeros/%s", router_data->node);
-  user_data.data = router_data;
-  user_data.free_func = (void *) cr_free_data;
   if (status == 0)
     status = plugin_register_complex_read (/* group = */ NULL, read_name,
-       cr_read, /* interval = */ 0, &user_data);
+        cr_read, /* interval = */ 0, &(user_data_t) {
+          .data = router_data,
+          .free_func = (void *) cr_free_data,
+        });
 
   if (status != 0)
     cr_free_data (router_data);
index 0b9040536ecc165f0b9a85ea7bacd1d5866358d6..6d45ac9fdf5287644edae598a4f2912a03686439 100644 (file)
@@ -313,8 +313,9 @@ static int rc_read (void)
   rrdc_stats_t *head;
   _Bool retried = 0;
 
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
+  vl.values = &(value_t) { .gauge = NAN };
+  vl.values_len = 1;
 
   if (daemon_address == NULL)
     return (-1);
@@ -322,13 +323,8 @@ static int rc_read (void)
   if (!config_collect_stats)
     return (-1);
 
-  vl.values = values;
-  vl.values_len = 1;
-
-  if ((strncmp ("unix:", daemon_address, strlen ("unix:")) == 0)
-      || (daemon_address[0] == '/'))
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-  else
+  if ((strncmp ("unix:", daemon_address, strlen ("unix:")) != 0)
+      && (daemon_address[0] != '/'))
     sstrncpy (vl.host, daemon_address, sizeof (vl.host));
   sstrncpy (vl.plugin, "rrdcached", sizeof (vl.plugin));
 
@@ -367,9 +363,9 @@ static int rc_read (void)
   for (rrdc_stats_t *ptr = head; ptr != NULL; ptr = ptr->next)
   {
     if (ptr->type == RRDC_STATS_TYPE_GAUGE)
-      values[0].gauge = (gauge_t) ptr->value.gauge;
+      vl.values[0].gauge = (gauge_t) ptr->value.gauge;
     else if (ptr->type == RRDC_STATS_TYPE_COUNTER)
-      values[0].counter = (counter_t) ptr->value.counter;
+      vl.values[0].counter = (counter_t) ptr->value.counter;
     else
       continue;
 
index 4f3d0d6032b33b6d3e13d11a3223bbf326efd33b..438cd7464ae09793eb8d52e038b6024519503960 100644 (file)
@@ -481,12 +481,11 @@ static int sensors_shutdown (void)
 
 static void sensors_submit (const char *plugin_instance,
                const char *type, const char *type_instance,
-               double val)
+               double value)
 {
        char match_key[1024];
        int status;
 
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
        status = ssnprintf (match_key, sizeof (match_key), "%s/%s-%s",
@@ -501,12 +500,9 @@ static void sensors_submit (const char *plugin_instance,
                        return;
        }
 
-       values[0].gauge = val;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "sensors", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
index cf7ad2a1ed9961d4c5ae254bf02b3371a87561e2..dc868fc2da3489558eb59ddcbcde29f07d6cdd47 100644 (file)
 static void serial_submit (const char *type_instance,
                derive_t rx, derive_t tx)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = rx;
-       values[1].derive = tx;
+       value_t values[] = {
+               { .derive = rx },
+               { .derive = tx },
+       };
 
        vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values_len = STATIC_ARRAY_SIZE (values);
        sstrncpy (vl.plugin, "serial", sizeof (vl.plugin));
        sstrncpy (vl.type, "serial_octets", sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance,
index 400645538d7d842f5d47f422f1347a2be5d7112d..78837cf825a18b57990726e3a84e5f44a1ce663e 100644 (file)
@@ -161,7 +161,6 @@ static void sigrok_feed_callback(const struct sr_dev_inst *sdi,
 {
        const struct sr_datafeed_analog *analog;
        struct config_device *cfdev;
-       value_t value;
        value_list_t vl = VALUE_LIST_INIT;
 
        /* Find this device's configuration. */
@@ -199,13 +198,10 @@ static void sigrok_feed_callback(const struct sr_dev_inst *sdi,
 
        /* Ignore all but the first sample on the first probe. */
        analog = packet->payload;
-       value.gauge = analog->data[0];
-       vl.values = &value;
+       vl.values = &(value_t) { .gauge = analog->data[0] };
        vl.values_len = 1;
-       sstrncpy(vl.host, hostname_g, sizeof(vl.host));
        sstrncpy(vl.plugin, "sigrok", sizeof(vl.plugin));
-       ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance),
-                       "%s", cfdev->name);
+       sstrncpy(vl.plugin_instance, cfdev->name, sizeof(vl.plugin_instance));
        sstrncpy(vl.type, sigrok_value_type(analog), sizeof(vl.type));
 
        plugin_dispatch_values(&vl);
index 752cb74cbe603baf47be59d482c0475983f063a6..285eb860e480d7c5944658e793ca9b0a25088768 100644 (file)
@@ -86,14 +86,10 @@ static int smart_config (const char *key, const char *value)
 static void smart_submit (const char *dev, const char *type,
                const char *type_inst, double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "smart", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
@@ -106,18 +102,20 @@ static void smart_handle_disk_attribute(SkDisk *d, const SkSmartAttributeParsedD
                                         void* userdata)
 {
   const char *dev = userdata;
-  value_t values[4];
-  value_list_t vl = VALUE_LIST_INIT;
 
-  if (!a->current_value_valid || !a->worst_value_valid) return;
-  values[0].gauge = a->current_value;
-  values[1].gauge = a->worst_value;
-  values[2].gauge = a->threshold_valid?a->threshold:0;
-  values[3].gauge = a->pretty_value;
+  if (!a->current_value_valid || !a->worst_value_valid)
+    return;
+
+  value_list_t vl = VALUE_LIST_INIT;
+  value_t values[] = {
+    { .gauge = a->current_value },
+    { .gauge = a->worst_value },
+    { .gauge = a->threshold_valid ? a->threshold : 0 },
+    { .gauge = a->pretty_value },
+  };
 
   vl.values = values;
-  vl.values_len = 4;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  vl.values_len = STATIC_ARRAY_SIZE (values);
   sstrncpy (vl.plugin, "smart", sizeof (vl.plugin));
   sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, "smart_attribute", sizeof (vl.type));
index abeda436795427f9597e281c30ce1e8ae656b519..d80ee9222615b6ff3a824376252d3ef65f352284 100644 (file)
@@ -764,13 +764,11 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
 
   ssnprintf (cb_name, sizeof (cb_name), "snmp-%s", hd->name);
 
-  user_data_t ud = {
-    .data = hd,
-    .free_func = csnmp_host_definition_destroy
-  };
-
   status = plugin_register_complex_read (/* group = */ NULL, cb_name,
-      csnmp_read_host, hd->interval, /* user_data = */ &ud);
+      csnmp_read_host, hd->interval, &(user_data_t) {
+        .data = hd,
+        .free_func = csnmp_host_definition_destroy,
+      });
   if (status != 0)
   {
     ERROR ("snmp plugin: Registering complex read function failed.");
index 9c138f978bb6dec71e600bf49a72682f62664ab4..491fe4239d35e4748a34c00931aed3643cc74aff 100644 (file)
@@ -752,12 +752,10 @@ static int statsd_metric_clear_set_unsafe (statsd_metric_t *metric) /* {{{ */
 /* Must hold metrics_lock when calling this function. */
 static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metric) /* {{{ */
 {
-  value_t values[1];
   value_list_t vl = VALUE_LIST_INIT;
 
-  vl.values = values;
+  vl.values = &(value_t) { .gauge = NAN };
   vl.values_len = 1;
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "statsd", sizeof (vl.plugin));
 
   if (metric->type == STATSD_GAUGE)
@@ -772,7 +770,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
   sstrncpy (vl.type_instance, name, sizeof (vl.type_instance));
 
   if (metric->type == STATSD_GAUGE)
-    values[0].gauge = (gauge_t) metric->value;
+    vl.values[0].gauge = (gauge_t) metric->value;
   else if (metric->type == STATSD_TIMER)
   {
     _Bool have_events = (metric->updates_num > 0);
@@ -782,7 +780,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
 
     ssnprintf (vl.type_instance, sizeof (vl.type_instance),
         "%s-average", name);
-    values[0].gauge = have_events
+    vl.values[0].gauge = have_events
       ? CDTIME_T_TO_DOUBLE (latency_counter_get_average (metric->latency))
       : NAN;
     plugin_dispatch_values (&vl);
@@ -790,7 +788,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
     if (conf_timer_lower) {
       ssnprintf (vl.type_instance, sizeof (vl.type_instance),
           "%s-lower", name);
-      values[0].gauge = have_events
+      vl.values[0].gauge = have_events
         ? CDTIME_T_TO_DOUBLE (latency_counter_get_min (metric->latency))
         : NAN;
       plugin_dispatch_values (&vl);
@@ -799,7 +797,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
     if (conf_timer_upper) {
       ssnprintf (vl.type_instance, sizeof (vl.type_instance),
           "%s-upper", name);
-      values[0].gauge = have_events
+      vl.values[0].gauge = have_events
         ? CDTIME_T_TO_DOUBLE (latency_counter_get_max (metric->latency))
         : NAN;
       plugin_dispatch_values (&vl);
@@ -808,7 +806,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
     if (conf_timer_sum) {
       ssnprintf (vl.type_instance, sizeof (vl.type_instance),
           "%s-sum", name);
-      values[0].gauge = have_events
+      vl.values[0].gauge = have_events
         ? CDTIME_T_TO_DOUBLE (latency_counter_get_sum (metric->latency))
         : NAN;
       plugin_dispatch_values (&vl);
@@ -818,7 +816,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
     {
       ssnprintf (vl.type_instance, sizeof (vl.type_instance),
           "%s-percentile-%.0f", name, conf_timer_percentile[i]);
-      values[0].gauge = have_events
+      vl.values[0].gauge = have_events
         ? CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (metric->latency, conf_timer_percentile[i]))
         : NAN;
       plugin_dispatch_values (&vl);
@@ -830,7 +828,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
       sstrncpy (vl.type, "gauge", sizeof (vl.type));
       ssnprintf (vl.type_instance, sizeof (vl.type_instance),
           "%s-count", name);
-      values[0].gauge = latency_counter_get_num (metric->latency);
+      vl.values[0].gauge = latency_counter_get_num (metric->latency);
       plugin_dispatch_values (&vl);
     }
 
@@ -840,9 +838,9 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
   else if (metric->type == STATSD_SET)
   {
     if (metric->set == NULL)
-      values[0].gauge = 0.0;
+      vl.values[0].gauge = 0.0;
     else
-      values[0].gauge = (gauge_t) c_avl_size (metric->set);
+      vl.values[0].gauge = (gauge_t) c_avl_size (metric->set);
   }
   else { /* STATSD_COUNTER */
     gauge_t delta = nearbyint (metric->value);
@@ -854,7 +852,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
     if (conf_counter_sum)
     {
       sstrncpy (vl.type, "count", sizeof (vl.type));
-      values[0].gauge = delta;
+      vl.values[0].gauge = delta;
       plugin_dispatch_values (&vl);
 
       /* restore vl.type */
@@ -866,7 +864,7 @@ static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metri
     metric->value   -= delta;
     metric->counter += (derive_t) delta;
 
-    values[0].derive = metric->counter;
+    vl.values[0].derive = metric->counter;
   }
 
   return (plugin_dispatch_values (&vl));
index 9c63e9bbb56ca82a7e4ce25de7219d79aa8040d2..403b148b3c2b8e38f15353251eccf86e44f46a83 100644 (file)
@@ -194,12 +194,10 @@ static void swap_submit_usage (char const *plugin_instance, /* {{{ */
                gauge_t used, gauge_t free,
                char const *other_name, gauge_t other_value)
 {
-       value_t v[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       vl.values = v;
-       vl.values_len = STATIC_ARRAY_SIZE (v);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values = &(value_t) { .gauge = NAN };
+       vl.values_len = 1;
        sstrncpy (vl.plugin, "swap", sizeof (vl.plugin));
        if (plugin_instance != NULL)
                sstrncpy (vl.plugin_instance, plugin_instance,
@@ -222,13 +220,9 @@ static void swap_submit_derive (char const *type_instance, /* {{{ */
                derive_t value)
 {
        value_list_t vl = VALUE_LIST_INIT;
-       value_t v[1];
 
-       v[0].derive = value;
-
-       vl.values = v;
-       vl.values_len = STATIC_ARRAY_SIZE (v);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values = &(value_t) { .derive = value };
+       vl.values_len = 1;
        sstrncpy (vl.plugin, "swap", sizeof (vl.plugin));
        sstrncpy (vl.type, "swap_io", sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
index 81e946145fd858c0031f3452629b1357ca58d484..7181795ed45c1e18ab3a2e6862e9e61e2fc300e7 100644 (file)
@@ -384,7 +384,6 @@ static int tbl_result_dispatch (tbl_t *tbl, tbl_result_t *res,
        vl.values     = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "table", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, tbl->instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, res->type, sizeof (vl.type));
index e8cde1edcd21a3cf27a1e9a8dea4ba9f7588e728..74fdf84aa35233110bed7a2315d677cb4830fbf3 100644 (file)
@@ -339,11 +339,10 @@ static int ctail_init (void)
   {
     ssnprintf(str, sizeof(str), "tail-%zu", i);
 
-    user_data_t ud = {
-     .data = tail_match_list[i]
-    };
-
-    plugin_register_complex_read (NULL, str, ctail_read, tail_match_list_intervals[i], &ud);
+    plugin_register_complex_read (NULL, str, ctail_read, tail_match_list_intervals[i],
+        &(user_data_t) {
+          .data = tail_match_list[i],
+        });
   }
 
   return (0);
index 206f1037fba03aef9c9af748b6122c10ce8cdb2e..0247387926738d0dc179cac871260e0d01cd0eca 100644 (file)
@@ -69,7 +69,6 @@ static int tcsv_submit (instance_definition_t *id,
     vl.values_len = 1;
     vl.values = &v;
 
-    sstrncpy(vl.host, hostname_g, sizeof (vl.host));
     sstrncpy(vl.plugin, "tail_csv", sizeof(vl.plugin));
     if (id->instance != NULL)
         sstrncpy(vl.plugin_instance, id->instance, sizeof(vl.plugin_instance));
@@ -482,13 +481,11 @@ static int tcsv_config_add_file(oconfig_item_t *ci)
 
     ssnprintf (cb_name, sizeof (cb_name), "tail_csv/%s", id->path);
 
-    user_data_t ud = {
-        .data = id,
-        .free_func = tcsv_instance_definition_destroy
-    };
-
-    status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval, &ud);
-
+    status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval,
+            &(user_data_t) {
+                .data = id,
+                .free_func = tcsv_instance_definition_destroy,
+            });
     if (status != 0){
         ERROR("tail_csv plugin: Registering complex read function failed.");
         tcsv_instance_definition_destroy(id);
index 52da2bc69db465a6e99bf97e529f43c56a0cd5c8..c7d56c736b4a1d1261b165517aede4b32ae7239a 100644 (file)
@@ -61,15 +61,14 @@ static void tape_submit (const char *plugin_instance,
                const char *type,
                derive_t read, derive_t write)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = read;
-       values[1].derive = write;
+       value_t values[] = {
+               { .derive = read },
+               { .derive = write },
+       };
 
        vl.values = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values_len = STATIC_ARRAY_SIZE (values);
        sstrncpy (vl.plugin, "tape", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
index 40a6fec992687466720d11abea95778fb5984aa2..dba3a8cf83b7ad6d18003c6efa982cad5da85dab 100644 (file)
@@ -38,11 +38,22 @@ struct tr_action_s
 {
   regex_t re;
   char *replacement;
-  int may_be_empty;
+  _Bool may_be_empty;
 
   tr_action_t *next;
 };
 
+struct tr_meta_data_action_s;
+typedef struct tr_meta_data_action_s tr_meta_data_action_t;
+struct tr_meta_data_action_s
+{
+  char *key;
+  regex_t re;
+  char *replacement;
+
+  tr_meta_data_action_t *next;
+};
+
 struct tr_data_s
 {
   tr_action_t *host;
@@ -50,6 +61,7 @@ struct tr_data_s
   tr_action_t *plugin_instance;
   /* tr_action_t *type; */
   tr_action_t *type_instance;
+  tr_meta_data_action_t *meta;
 };
 typedef struct tr_data_s tr_data_t;
 
@@ -85,8 +97,23 @@ static void tr_action_destroy (tr_action_t *act) /* {{{ */
   sfree (act);
 } /* }}} void tr_action_destroy */
 
+static void tr_meta_data_action_destroy (tr_meta_data_action_t *act) /* {{{ */
+{
+  if (act == NULL)
+    return;
+
+  sfree (act->key);
+  regfree (&act->re);
+  sfree (act->replacement);
+
+  if (act->next != NULL)
+    tr_meta_data_action_destroy (act->next);
+
+  sfree (act);
+} /* }}} void tr_meta_data_action_destroy */
+
 static int tr_config_add_action (tr_action_t **dest, /* {{{ */
-    const oconfig_item_t *ci, int may_be_empty)
+    const oconfig_item_t *ci, _Bool may_be_empty)
 {
   tr_action_t *act;
   int status;
@@ -131,8 +158,7 @@ static int tr_config_add_action (tr_action_t **dest, /* {{{ */
   if (act->replacement == NULL)
   {
     ERROR ("tr_config_add_action: tr_strdup failed.");
-    regfree (&act->re);
-    sfree (act);
+    tr_action_destroy (act);
     return (-ENOMEM);
   }
 
@@ -153,8 +179,108 @@ static int tr_config_add_action (tr_action_t **dest, /* {{{ */
   return (0);
 } /* }}} int tr_config_add_action */
 
+static int tr_config_add_meta_action (tr_meta_data_action_t **dest, /* {{{ */
+    const oconfig_item_t *ci, _Bool should_delete)
+{
+  tr_meta_data_action_t *act;
+  int status;
+
+  if (dest == NULL)
+    return (-EINVAL);
+
+  if (should_delete)
+  {
+    if ((ci->values_num != 2)
+        || (ci->values[0].type != OCONFIG_TYPE_STRING)
+        || (ci->values[1].type != OCONFIG_TYPE_STRING))
+    {
+      ERROR ("Target `replace': The `%s' option requires exactly two string "
+          "arguments.", ci->key);
+      return (-1);
+    }
+  }
+  else
+  {
+    if ((ci->values_num != 3)
+        || (ci->values[0].type != OCONFIG_TYPE_STRING)
+        || (ci->values[1].type != OCONFIG_TYPE_STRING)
+        || (ci->values[2].type != OCONFIG_TYPE_STRING))
+    {
+      ERROR ("Target `replace': The `%s' option requires exactly three string "
+          "arguments.", ci->key);
+      return (-1);
+    }
+  }
+
+  if (strlen (ci->values[0].value.string) == 0)
+  {
+    ERROR ("Target `replace': The `%s' option does not accept empty string as "
+        "first argument.", ci->key);
+    return (-1);
+  }
+
+  act = calloc (1, sizeof (*act));
+  if (act == NULL)
+  {
+    ERROR ("tr_config_add_meta_action: calloc failed.");
+    return (-ENOMEM);
+  }
+
+  act->key = NULL;
+  act->replacement = NULL;
+
+  status = regcomp (&act->re, ci->values[1].value.string, REG_EXTENDED);
+  if (status != 0)
+  {
+    char errbuf[1024] = "";
+
+    /* regerror assures null termination. */
+    regerror (status, &act->re, errbuf, sizeof (errbuf));
+    ERROR ("Target `replace': Compiling the regular expression `%s' "
+        "failed: %s.",
+        ci->values[1].value.string, errbuf);
+    sfree (act->key);
+    sfree (act);
+    return (-EINVAL);
+  }
+
+  act->key = tr_strdup (ci->values[0].value.string);
+  if (act->key == NULL)
+  {
+    ERROR ("tr_config_add_meta_action: tr_strdup failed.");
+    tr_meta_data_action_destroy (act);
+    return (-ENOMEM);
+  }
+
+  if (!should_delete) {
+    act->replacement = tr_strdup (ci->values[2].value.string);
+    if (act->replacement == NULL)
+    {
+      ERROR ("tr_config_add_meta_action: tr_strdup failed.");
+      tr_meta_data_action_destroy (act);
+      return (-ENOMEM);
+    }
+  }
+
+  /* Insert action at end of list. */
+  if (*dest == NULL)
+    *dest = act;
+  else
+  {
+    tr_meta_data_action_t *prev;
+
+    prev = *dest;
+    while (prev->next != NULL)
+      prev = prev->next;
+
+    prev->next = act;
+  }
+
+  return (0);
+} /* }}} int tr_config_add_meta_action */
+
 static int tr_action_invoke (tr_action_t *act_head, /* {{{ */
-    char *buffer_in, size_t buffer_in_size, int may_be_empty)
+    char *buffer_in, size_t buffer_in_size, _Bool may_be_empty)
 {
   int status;
   char buffer[DATA_MAX_NAME_LEN];
@@ -215,6 +341,119 @@ static int tr_action_invoke (tr_action_t *act_head, /* {{{ */
   return (0);
 } /* }}} int tr_action_invoke */
 
+static int tr_meta_data_action_invoke ( /* {{{ */
+    tr_meta_data_action_t *act_head, meta_data_t **dest)
+{
+  int status;
+  regmatch_t matches[8] = { [0] = { 0 } };
+
+  if (act_head == NULL)
+    return (-EINVAL);
+
+  if ((*dest) == NULL)  /* nothing to do */
+    return (0);
+
+  for (tr_meta_data_action_t *act = act_head; act != NULL; act = act->next)
+  {
+    char temp[DATA_MAX_NAME_LEN];
+    char *subst_status;
+    int value_type;
+    int meta_data_status;
+    char *value;
+    meta_data_t *result;
+
+    value_type = meta_data_type (*dest, act->key);
+    if (value_type == 0)  /* not found */
+      continue;
+    if (value_type != MD_TYPE_STRING)
+    {
+      WARNING ("Target `replace': Attempting replace on metadata key `%s', "
+          "which isn't a string.",
+          act->key);
+      continue;
+    }
+
+    meta_data_status = meta_data_get_string (*dest, act->key, &value);
+    if (meta_data_status != 0)
+    {
+      ERROR ("Target `replace': Unable to retrieve metadata value for `%s'.",
+          act->key);
+      return (meta_data_status);
+    }
+
+    DEBUG ("target_replace plugin: tr_meta_data_action_invoke: `%s' "
+        "old value = `%s'", act->key, value);
+
+    status = regexec (&act->re, value,
+        STATIC_ARRAY_SIZE (matches), matches,
+        /* flags = */ 0);
+    if (status == REG_NOMATCH)
+    {
+      sfree (value);
+      continue;
+    }
+    else if (status != 0)
+    {
+      char errbuf[1024] = "";
+
+      regerror (status, &act->re, errbuf, sizeof (errbuf));
+      ERROR ("Target `replace': Executing a regular expression failed: %s.",
+          errbuf);
+      sfree (value);
+      continue;
+    }
+
+    if (act->replacement == NULL)
+    {
+      /* no replacement; delete the key */
+      DEBUG ("target_replace plugin: tr_meta_data_action_invoke: "
+          "deleting `%s'", act->key);
+      meta_data_delete (*dest, act->key);
+      sfree (value);
+      continue;
+    }
+
+    subst_status = subst (temp, sizeof (temp), value,
+        (size_t) matches[0].rm_so, (size_t) matches[0].rm_eo, act->replacement);
+    if (subst_status == NULL)
+    {
+      ERROR ("Target `replace': subst (value = %s, start = %zu, end = %zu, "
+          "replacement = %s) failed.",
+          value, (size_t) matches[0].rm_so, (size_t) matches[0].rm_eo,
+          act->replacement);
+      sfree (value);
+      continue;
+    }
+
+    DEBUG ("target_replace plugin: tr_meta_data_action_invoke: `%s' "
+        "value `%s' -> `%s'", act->key, value, temp);
+
+    if ((result = meta_data_create()) == NULL)
+    {
+      ERROR ("Target `replace': failed to create metadata for `%s'.",
+          act->key);
+      sfree (value);
+      return (-ENOMEM);
+    }
+
+    meta_data_status = meta_data_add_string (result, act->key, temp);
+    if (meta_data_status != 0)
+    {
+      ERROR ("Target `replace': Unable to set metadata value for `%s'.",
+          act->key);
+      meta_data_destroy (result);
+      sfree (value);
+      return (meta_data_status);
+    }
+
+    meta_data_clone_merge (dest, result);
+    meta_data_destroy (result);
+    sfree (value);
+  } /* for (act = act_head; act != NULL; act = act->next) */
+
+  return (0);
+} /* }}} int tr_meta_data_action_invoke */
+
 static int tr_destroy (void **user_data) /* {{{ */
 {
   tr_data_t *data;
@@ -231,6 +470,7 @@ static int tr_destroy (void **user_data) /* {{{ */
   tr_action_destroy (data->plugin_instance);
   /* tr_action_destroy (data->type); */
   tr_action_destroy (data->type_instance);
+  tr_meta_data_action_destroy (data->meta);
   sfree (data);
 
   return (0);
@@ -253,6 +493,7 @@ static int tr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
   data->plugin_instance = NULL;
   /* data->type = NULL; */
   data->type_instance = NULL;
+  data->meta = NULL;
 
   status = 0;
   for (int i = 0; i < ci->children_num; i++)
@@ -277,6 +518,12 @@ static int tr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
     else if (strcasecmp ("TypeInstance", child->key) == 0)
       status = tr_config_add_action (&data->type_instance, child,
           /* may be empty = */ 1);
+    else if (strcasecmp ("MetaData", child->key) == 0)
+      status = tr_config_add_meta_action (&data->meta, child,
+          /* should delete = */ 0);
+    else if (strcasecmp ("DeleteMetaData", child->key) == 0)
+      status = tr_config_add_meta_action (&data->meta, child,
+          /* should delete = */ 1);
     else
     {
       ERROR ("Target `replace': The `%s' configuration option is not understood "
@@ -295,7 +542,8 @@ static int tr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
         && (data->plugin == NULL)
         && (data->plugin_instance == NULL)
         /* && (data->type == NULL) */
-        && (data->type_instance == NULL))
+        && (data->type_instance == NULL)
+        && (data->meta == NULL))
     {
       ERROR ("Target `replace': You need to set at least one of `Host', "
           "`Plugin', `PluginInstance' or `TypeInstance'.");
@@ -330,13 +578,18 @@ static int tr_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
     return (-EINVAL);
   }
 
+  if (data->meta != NULL)
+  {
+    tr_meta_data_action_invoke (data->meta, &(vl->meta));
+  }
+
 #define HANDLE_FIELD(f,e) \
   if (data->f != NULL) \
     tr_action_invoke (data->f, vl->f, sizeof (vl->f), e)
   HANDLE_FIELD (host, 0);
   HANDLE_FIELD (plugin, 0);
   HANDLE_FIELD (plugin_instance, 1);
-  /* HANDLE_FIELD (type); */
+  /* HANDLE_FIELD (type, 0); */
   HANDLE_FIELD (type_instance, 1);
 
   return (FC_TARGET_CONTINUE);
index 4f00cbbdaf1aedbc2bf6eedbdf60a003e826e9b5..6b44bcc4c78f7bb7ef0997d2951d1004b2ec4b85 100644 (file)
 
 #include "common.h"
 #include "filter_chain.h"
+#include "meta_data.h"
+#include "utils_subst.h"
+
+struct ts_key_list_s
+{
+  char *key;
+  struct ts_key_list_s *next;
+};
+typedef struct ts_key_list_s ts_key_list_t;
+
+static void ts_key_list_free (ts_key_list_t *l) /* {{{ */
+{
+  if (l == NULL)
+    return;
+
+  sfree (l->key);
+
+  if (l->next != NULL)
+    ts_key_list_free (l->next);
+
+  sfree (l);
+} /* }}} void ts_name_list_free */
 
 struct ts_data_s
 {
@@ -37,6 +59,7 @@ struct ts_data_s
   /* char *type; */
   char *type_instance;
   meta_data_t *meta;
+  ts_key_list_t *meta_delete;
 };
 typedef struct ts_data_s ts_data_t;
 
@@ -47,7 +70,7 @@ static int ts_util_get_key_and_string_wo_strdup (const oconfig_item_t *ci, char
       || (ci->values[1].type != OCONFIG_TYPE_STRING))
   {
     ERROR ("ts_util_get_key_and_string_wo_strdup: The %s option requires "
-        "exactly two string argument.", ci->key);
+        "exactly two string arguments.", ci->key);
     return (-1);
   }
 
@@ -92,31 +115,105 @@ static int ts_config_add_meta (meta_data_t **dest, /* {{{ */
 
   if (strlen (key) == 0)
   {
-    ERROR ("Target `set': The `%s' option does not accept empty string as first argument.",
-        ci->key);
+    ERROR ("Target `set': The `%s' option does not accept empty string as "
+        "first argument.", ci->key);
     return (-1);
   }
 
   if (!may_be_empty && (strlen (string) == 0))
   {
-    ERROR ("Target `set': The `%s' option does not accept empty string as second argument.",
-        ci->key);
+    ERROR ("Target `set': The `%s' option does not accept empty string as "
+        "second argument.", ci->key);
     return (-1);
   }
 
   if ((*dest) == NULL)
   {
-    // Create a new meta_data_t
+    /* Create a new meta_data_t */
     if ((*dest = meta_data_create()) == NULL)
     {
       ERROR ("Target `set': failed to create a meta data for `%s'.", ci->key);
-      return (-1);
+      return (-ENOMEM);
     }
   }
 
   return (meta_data_add_string (*dest, key, string));
 } /* }}} int ts_config_add_meta */
 
+static int ts_config_add_meta_delete (ts_key_list_t **dest, /* {{{ */
+    const oconfig_item_t *ci)
+{
+  ts_key_list_t *entry = NULL;
+
+  entry = calloc (1, sizeof (*entry));
+  if (entry == NULL)
+  {
+    ERROR ("ts_config_add_meta_delete: calloc failed.");
+    return (-ENOMEM);
+  }
+
+  if (cf_util_get_string (ci, &entry->key) != 0)
+  {
+    ts_key_list_free (entry);
+    return (-1);  /* An error has already been reported. */
+  }
+
+  if (strlen (entry->key) == 0)
+  {
+    ERROR ("Target `set': The `%s' option does not accept empty string as "
+        "first argument.", ci->key);
+    ts_key_list_free (entry);
+    return (-1);
+  }
+
+  entry->next = *dest;
+  *dest = entry;
+
+  return (0);
+} /* }}} int ts_config_add_meta_delete */
+
+static void ts_subst (char *dest, size_t size, const char *string, /* {{{ */
+    const value_list_t *vl)
+{
+  char temp[DATA_MAX_NAME_LEN];
+
+  /* Initialize the field with the template. */
+  sstrncpy (dest, string, size);
+
+  if (strchr (dest, '%') == NULL)
+    return;
+
+#define REPLACE_FIELD(t, v) \
+  if (subst_string (temp, sizeof (temp), dest, t, v) != NULL) \
+    sstrncpy (dest, temp, size);
+  REPLACE_FIELD ("%{host}", vl->host);
+  REPLACE_FIELD ("%{plugin}", vl->plugin);
+  REPLACE_FIELD ("%{plugin_instance}", vl->plugin_instance);
+  REPLACE_FIELD ("%{type}", vl->type);
+  REPLACE_FIELD ("%{type_instance}", vl->type_instance);
+
+  if (vl->meta != NULL)
+  {
+    char **meta_toc;
+    int meta_entries = meta_data_toc (vl->meta, &meta_toc);
+    for (int i = 0; i < meta_entries; i++)
+    {
+      char meta_name[DATA_MAX_NAME_LEN];
+      char *value_str;
+      const char *key = meta_toc[i];
+
+      ssnprintf (meta_name, sizeof (meta_name), "%%{meta:%s}", key);
+      if (meta_data_as_string (vl->meta, key, &value_str) != 0)
+        continue;
+
+      REPLACE_FIELD (meta_name, value_str);
+      sfree (value_str);
+    }
+
+    strarray_free (meta_toc, (size_t) meta_entries);
+  }
+} /* }}} int ts_subst */
+
 static int ts_destroy (void **user_data) /* {{{ */
 {
   ts_data_t *data;
@@ -134,6 +231,7 @@ static int ts_destroy (void **user_data) /* {{{ */
   /* free (data->type); */
   free (data->type_instance);
   meta_data_destroy(data->meta);
+  ts_key_list_free (data->meta_delete);
   free (data);
 
   return (0);
@@ -157,6 +255,7 @@ static int ts_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
   /* data->type = NULL; */
   data->type_instance = NULL;
   data->meta = NULL;
+  data->meta_delete = NULL;
 
   status = 0;
   for (int i = 0; i < ci->children_num; i++)
@@ -184,6 +283,8 @@ static int ts_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
     else if (strcasecmp ("MetaData", child->key) == 0)
       status = ts_config_add_meta (&data->meta, child,
           /* may be empty = */ 1);
+    else if (strcasecmp ("DeleteMetaData", child->key) == 0)
+      status = ts_config_add_meta_delete (&data->meta_delete, child);
     else
     {
       ERROR ("Target `set': The `%s' configuration option is not understood "
@@ -203,13 +304,30 @@ static int ts_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
         && (data->plugin_instance == NULL)
         /* && (data->type == NULL) */
         && (data->type_instance == NULL)
-        && (data->meta == NULL))
+        && (data->meta == NULL)
+        && (data->meta_delete == NULL))
     {
       ERROR ("Target `set': You need to set at least one of `Host', "
-          "`Plugin', `PluginInstance', `TypeInstance', `MetaData'.");
+          "`Plugin', `PluginInstance', `TypeInstance', "
+          "`MetaData', or `DeleteMetaData'.");
       status = -1;
     }
 
+    if (data->meta != NULL)
+    {
+      /* If data->meta_delete is NULL, this loop is a no-op. */
+      for (ts_key_list_t *l=data->meta_delete; l != NULL; l = l->next)
+      {
+        if (meta_data_type (data->meta, l->key) != 0)
+        {
+          /* MetaData and DeleteMetaData for the same key. */
+          ERROR ("Target `set': Can only have one of `MetaData' or "
+              "`DeleteMetaData' for any given key.");
+          status = -1;
+        }
+      }
+    }
+
     break;
   }
 
@@ -227,6 +345,8 @@ static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
     notification_meta_t __attribute__((unused)) **meta, void **user_data)
 {
   ts_data_t *data;
+  value_list_t orig;
+  meta_data_t *new_meta = NULL;
 
   if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
     return (-EINVAL);
@@ -238,17 +358,80 @@ static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
     return (-EINVAL);
   }
 
+  orig = *vl;
+
   if (data->meta != NULL)
   {
-    meta_data_clone_merge(&(vl->meta), data->meta);
+    char temp[DATA_MAX_NAME_LEN*2];
+    int meta_entries;
+    char **meta_toc;
+
+    if ((new_meta = meta_data_create()) == NULL)
+    {
+      ERROR ("Target `set': failed to create replacement metadata.");
+      return (-ENOMEM);
+    }
+
+    meta_entries = meta_data_toc (data->meta, &meta_toc);
+    for (int i = 0; i < meta_entries; i++)
+    {
+      const char *key = meta_toc[i];
+      char *string;
+      int status;
+
+      status = meta_data_get_string (data->meta, key, &string);
+      if (status)
+      {
+        ERROR ("Target `set': Unable to get replacement metadata value `%s'.",
+            key);
+        strarray_free (meta_toc, (size_t) meta_entries);
+        return (status);
+      }
+
+      ts_subst (temp, sizeof (temp), string, &orig);
+
+      DEBUG ("target_set: ts_invoke: setting metadata value for key `%s': "
+          "`%s'.", key, temp);
+
+      sfree (string);
+
+      status = meta_data_add_string (new_meta, key, temp);
+      if (status)
+      {
+        ERROR ("Target `set': Unable to set metadata value `%s'.", key);
+        strarray_free (meta_toc, (size_t) meta_entries);
+        return (status);
+      }
+    }
+
+    strarray_free (meta_toc, (size_t) meta_entries);
+  }
+
+#define SUBST_FIELD(f) \
+  if (data->f != NULL) { \
+    ts_subst (vl->f, sizeof (vl->f), data->f, &orig); \
+    DEBUG ("target_set: ts_invoke: setting "#f": `%s'.", vl->f); \
+  }
+  SUBST_FIELD (host);
+  SUBST_FIELD (plugin);
+  SUBST_FIELD (plugin_instance);
+  /* SUBST_FIELD (type); */
+  SUBST_FIELD (type_instance);
+
+  /* Need to merge the metadata in now, because of the shallow copy. */
+  if (new_meta != NULL)
+  {
+    meta_data_clone_merge(&(vl->meta), new_meta);
+    meta_data_destroy(new_meta);
   }
 
-#define SET_FIELD(f) if (data->f != NULL) { sstrncpy (vl->f, data->f, sizeof (vl->f)); }
-  SET_FIELD (host);
-  SET_FIELD (plugin);
-  SET_FIELD (plugin_instance);
-  /* SET_FIELD (type); */
-  SET_FIELD (type_instance);
+  /* If data->meta_delete is NULL, this loop is a no-op. */
+  for (ts_key_list_t *l=data->meta_delete; l != NULL; l = l->next)
+  {
+    DEBUG ("target_set: ts_invoke: deleting metadata value for key `%s'.",
+        l->key);
+    meta_data_delete(vl->meta, l->key);
+  }
 
   return (FC_TARGET_CONTINUE);
 } /* }}} int ts_invoke */
index f7baa3aee468ce5e1a5cac6f29ea7f2a8ee8ecc9..3f2c9583f51a31c4196f922faab05daccfb1a9c0 100644 (file)
@@ -53,7 +53,6 @@ static void v5_swap_instances (value_list_t *vl) /* {{{ */
 static int v5_df (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_value;
 
   /* Can't upgrade if both instances have been set. */
   if ((vl->plugin_instance[0] != 0)
@@ -64,7 +63,7 @@ static int v5_df (const data_set_t *ds, value_list_t *vl) /* {{{ */
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = &new_value;
+  new_vl.values = &(value_t) { .gauge = NAN };
   new_vl.values_len = 1;
   new_vl.meta = NULL;
 
@@ -113,7 +112,6 @@ static int v5_interface (const data_set_t *ds, value_list_t *vl) /* {{{ */
 static int v5_mysql_qcache (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_value;
 
   if (vl->values_len != 5)
     return (FC_TARGET_STOP);
@@ -122,7 +120,7 @@ static int v5_mysql_qcache (const data_set_t *ds, value_list_t *vl) /* {{{ */
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = &new_value;
+  new_vl.values = &(value_t) { .gauge = NAN };
   new_vl.values_len = 1;
   new_vl.meta = NULL;
 
@@ -171,7 +169,6 @@ static int v5_mysql_qcache (const data_set_t *ds, value_list_t *vl) /* {{{ */
 static int v5_mysql_threads (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_value;
 
   if (vl->values_len != 4)
     return (FC_TARGET_STOP);
@@ -180,7 +177,7 @@ static int v5_mysql_threads (const data_set_t *ds, value_list_t *vl) /* {{{ */
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = &new_value;
+  new_vl.values = &(value_t) { .gauge = NAN };
   new_vl.values_len = 1;
   new_vl.meta = NULL;
 
@@ -224,7 +221,6 @@ static int v5_mysql_threads (const data_set_t *ds, value_list_t *vl) /* {{{ */
 static int v5_zfs_arc_counts (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_value;
   _Bool is_hits;
 
   if (vl->values_len != 4)
@@ -241,7 +237,7 @@ static int v5_zfs_arc_counts (const data_set_t *ds, value_list_t *vl) /* {{{ */
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = &new_value;
+  new_vl.values = &(value_t) { .gauge = NAN };
   new_vl.values_len = 1;
   new_vl.meta = NULL;
 
@@ -285,7 +281,6 @@ static int v5_zfs_arc_counts (const data_set_t *ds, value_list_t *vl) /* {{{ */
 static int v5_zfs_arc_l2_bytes (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_values[2];
 
   if (vl->values_len != 2)
     return (FC_TARGET_STOP);
@@ -294,8 +289,6 @@ static int v5_zfs_arc_l2_bytes (const data_set_t *ds, value_list_t *vl) /* {{{ *
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = new_values;
-  new_vl.values_len = 2;
   new_vl.meta = NULL;
 
   /* Change the type/-instance to "io_octets-L2" */
@@ -303,8 +296,12 @@ static int v5_zfs_arc_l2_bytes (const data_set_t *ds, value_list_t *vl) /* {{{ *
   sstrncpy (new_vl.type_instance, "L2", sizeof (new_vl.type_instance));
 
   /* Copy the actual values. */
-  new_vl.values[0].derive = (derive_t) vl->values[0].counter;
-  new_vl.values[1].derive = (derive_t) vl->values[1].counter;
+  value_t values[] = {
+    { .derive = (derive_t) vl->values[0].counter },
+    { .derive = (derive_t) vl->values[1].counter },
+  };
+  new_vl.values = values;
+  new_vl.values_len = STATIC_ARRAY_SIZE (values);
 
   /* Dispatch new value lists instead of this one */
   plugin_dispatch_values (&new_vl);
@@ -322,7 +319,6 @@ static int v5_zfs_arc_l2_bytes (const data_set_t *ds, value_list_t *vl) /* {{{ *
 static int v5_zfs_arc_l2_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_value;
 
   if (vl->values_len != 1)
     return (FC_TARGET_STOP);
@@ -331,7 +327,7 @@ static int v5_zfs_arc_l2_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = &new_value;
+  new_vl.values = &(value_t) { .gauge = NAN };
   new_vl.values_len = 1;
   new_vl.meta = NULL;
 
@@ -359,7 +355,6 @@ static int v5_zfs_arc_l2_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
 static int v5_zfs_arc_ratio (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_value;
 
   if (vl->values_len != 1)
     return (FC_TARGET_STOP);
@@ -368,7 +363,7 @@ static int v5_zfs_arc_ratio (const data_set_t *ds, value_list_t *vl) /* {{{ */
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = &new_value;
+  new_vl.values = &(value_t) { .gauge = NAN };
   new_vl.values_len = 1;
   new_vl.meta = NULL;
 
@@ -397,7 +392,6 @@ static int v5_zfs_arc_ratio (const data_set_t *ds, value_list_t *vl) /* {{{ */
 static int v5_zfs_arc_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
 {
   value_list_t new_vl;
-  value_t new_value;
 
   if (vl->values_len != 4)
     return (FC_TARGET_STOP);
@@ -406,7 +400,7 @@ static int v5_zfs_arc_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
   memcpy (&new_vl, vl, sizeof (new_vl));
 
   /* Reset data we can't simply copy */
-  new_vl.values = &new_value;
+  new_vl.values = &(value_t) { .gauge = NAN };
   new_vl.values_len = 1;
   new_vl.meta = NULL;
 
index e74e4bc8856d6360472a44d52a7dae93a3586ca2..8c93405eb57286fe3ce7a012809c57cd32f498a7 100644 (file)
@@ -296,7 +296,6 @@ static void conn_prepare_vl (value_list_t *vl, value_t *values)
 {
   vl->values = values;
   vl->values_len = 1;
-  sstrncpy (vl->host, hostname_g, sizeof (vl->host));
   sstrncpy (vl->plugin, "tcpconns", sizeof (vl->plugin));
   sstrncpy (vl->type, "tcp_connections", sizeof (vl->type));
 }
index a1cde320dd2cb3e9a83f9910da40beb31eefbb43..1bd969bd9e158dcbf6d7bb92c5fd9e68f70ce599 100644 (file)
@@ -121,14 +121,10 @@ static void tss2_submit_gauge (const char *plugin_instance,
        /*
         * Submits a gauge value to the collectd daemon
         */
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values     = values;
+       vl.values     = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "teamspeak2", sizeof (vl.plugin));
 
        if (plugin_instance != NULL)
@@ -150,15 +146,14 @@ static void tss2_submit_io (const char *plugin_instance, const char *type,
        /*
         * Submits the io rx/tx tuple to the collectd daemon
         */
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = rx;
-       values[1].derive = tx;
+       value_t values[] = {
+               { .derive = rx },
+               { .derive = tx },
+       };
 
        vl.values     = values;
-       vl.values_len = 2;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values_len = STATIC_ARRAY_SIZE (values);
        sstrncpy (vl.plugin, "teamspeak2", sizeof (vl.plugin));
 
        if (plugin_instance != NULL)
index 5ed6c278d0f985f52f1c8267027d501c370bf362..001eddf42aede512fd285b045145d52bd95a48d8 100644 (file)
--- a/src/ted.c
+++ b/src/ted.c
@@ -263,14 +263,10 @@ static int ted_open_device (void)
 
 static void ted_submit (const char *type, double value)
 {
-    value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
 
-    values[0].gauge = value;
-
-    vl.values = values;
+    vl.values = &(value_t) { .gauge = value };
     vl.values_len = 1;
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "ted", sizeof (vl.plugin));
     sstrncpy (vl.type, type, sizeof (vl.type));
 
index 1bcc276c1a8666be6b30113addc572af02689ef5..1bc966c82e8a47c46b680fb08b0cab578d8bb150 100644 (file)
@@ -48,9 +48,12 @@ static int check_count__ = 0;
 
 #define END_TEST exit ((fail_count__ == 0) ? 0 : 1);
 
+#define LOG(result, text) \
+  printf ("%s %i - %s\n", result ? "ok" : "not ok", ++check_count__, text)
+
 #define OK1(cond, text) do { \
   _Bool result = (cond); \
-  printf ("%s %i - %s\n", result ? "ok" : "not ok", ++check_count__, text); \
+  LOG (result, text); \
   if (!result) { return -1; } \
 } while (0)
 #define OK(cond) OK1(cond, #cond)
index e001a62ac7f85a69259e6e5e047414ad4e8e9587..09d9157efca218771b6c491eb1e4c9d90ebb4b6d 100644 (file)
@@ -47,17 +47,13 @@ enum dev_type {
 };
 
 static void thermal_submit (const char *plugin_instance, enum dev_type dt,
-               gauge_t value)
+               value_t value)
 {
        value_list_t vl = VALUE_LIST_INIT;
-       value_t v;
-
-       v.gauge = value;
-       vl.values = &v;
 
+       vl.values = &value;
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "thermal", sizeof(vl.plugin));
        if (plugin_instance != NULL)
                sstrncpy (vl.plugin_instance, plugin_instance,
@@ -72,52 +68,26 @@ static void thermal_submit (const char *plugin_instance, enum dev_type dt,
 static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
                const char *name, void __attribute__((unused)) *user_data)
 {
-       char filename[256];
-       char data[1024];
-       int len;
+       char filename[PATH_MAX];
        _Bool success = 0;
+       value_t value;
 
        if (device_list && ignorelist_match (device_list, name))
                return -1;
 
-       len = ssnprintf (filename, sizeof (filename),
-                       "%s/%s/temp", dirname_sysfs, name);
-       if ((len < 0) || ((size_t) len >= sizeof (filename)))
-               return -1;
-
-       len = (ssize_t) read_file_contents (filename, data, sizeof(data));
-       if (len > 1 && data[--len] == '\n') {
-               char *endptr = NULL;
-               double temp;
-
-               data[len] = 0;
-               errno = 0;
-               temp = strtod (data, &endptr) / 1000.0;
-
-               if (endptr == data + len && errno == 0) {
-                       thermal_submit(name, TEMP, temp);
-                       success = 1;
-               }
+       ssnprintf (filename, sizeof (filename), "%s/%s/temp", dirname_sysfs, name);
+       if (parse_value_file (filename, &value, DS_TYPE_GAUGE) == 0)
+       {
+               value.gauge /= 1000.0;
+               thermal_submit(name, TEMP, value);
+               success = 1;
        }
 
-       len = ssnprintf (filename, sizeof (filename),
-                       "%s/%s/cur_state", dirname_sysfs, name);
-       if ((len < 0) || ((size_t) len >= sizeof (filename)))
-               return -1;
-
-       len = (ssize_t) read_file_contents (filename, data, sizeof(data));
-       if (len > 1 && data[--len] == '\n') {
-               char *endptr = NULL;
-               double state;
-
-               data[len] = 0;
-               errno = 0;
-               state = strtod (data, &endptr);
-
-               if (endptr == data + len && errno == 0) {
-                       thermal_submit(name, COOLING_DEV, state);
-                       success = 1;
-               }
+       ssnprintf (filename, sizeof (filename), "%s/%s/cur_state", dirname_sysfs, name);
+       if (parse_value_file (filename, &value, DS_TYPE_GAUGE) == 0)
+       {
+               thermal_submit(name, COOLING_DEV, value);
+               success = 1;
        }
 
        return (success ? 0 : -1);
@@ -176,7 +146,7 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
                temp = (strtod (data + len, &endptr) + add) * factor;
 
                if (endptr != data + len && errno == 0) {
-                       thermal_submit(name, TEMP, temp);
+                       thermal_submit(name, TEMP, (value_t) { .gauge = temp });
                        return 0;
                }
        }
index 7c6d9129e709ee9b71a30a3a57848fc9fca56b06..154215f867bcc16ed0c6e4cec866883628c3af6c 100644 (file)
@@ -86,15 +86,12 @@ static void printerr (void)
                        ecode, tcrdberrmsg(ecode));
 }
 
-static void tt_submit (gauge_t val, const char* type)
+static void tt_submit (gauge_t value, const char* type)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = val;
-
-       vl.values = values;
-       vl.values_len = STATIC_ARRAY_SIZE (values);
+       vl.values = &(value_t) { .gauge = value };
+       vl.values_len = 1;
 
        sstrncpy (vl.host, config_host, sizeof (vl.host));
        sstrncpy (vl.plugin, "tokyotyrant", sizeof (vl.plugin));
index 2d8a08e646319b961f8ffb24f1a8654bb470c23f..31321490309d7a63c0fb449e0944e3b1b835042c 100644 (file)
@@ -524,12 +524,9 @@ turbostat_submit (const char *plugin_instance,
        gauge_t value)
 {
        value_list_t vl = VALUE_LIST_INIT;
-       value_t v;
 
-       v.gauge = value;
-       vl.values = &v;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, PLUGIN_NAME, sizeof (vl.plugin));
        if (plugin_instance != NULL)
                sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
@@ -1018,8 +1015,7 @@ parse_int_file(const char *fmt, ...)
 {
        va_list args;
        char path[PATH_MAX];
-       FILE *filep;
-       int len, value;
+       int len;
 
        va_start(args, fmt);
        len = vsnprintf(path, sizeof(path), fmt, args);
@@ -1029,18 +1025,13 @@ parse_int_file(const char *fmt, ...)
                return -1;
        }
 
-       filep = fopen(path, "r");
-       if (!filep) {
-               ERROR("turbostat plugin: Failed to open '%s'", path);
-               return -1;
-       }
-       if (fscanf(filep, "%d", &value) != 1) {
-               ERROR("turbostat plugin: Failed to parse number from '%s'", path);
-               fclose(filep);
+       value_t v;
+       if (parse_value_file (path, &v, DS_TYPE_DERIVE) != 0) {
+               ERROR ("turbostat plugin: Parsing \"%s\" failed.", path);
                return -1;
        }
-       fclose(filep);
-       return value;
+
+       return (int) v.derive;
 }
 
 static int
index 9ebc5fc6b0fc3922bf20f5364360f83764dac6a7..cb7501ec3cc444bc4f0e9bc1ed6ac38714048359 100644 (file)
@@ -74,13 +74,17 @@ duration                seconds:GAUGE:0:U
 email_check             value:GAUGE:0:U
 email_count             value:GAUGE:0:U
 email_size              value:GAUGE:0:U
+energy                  value:GAUGE:U:U
+energy_wh               value:GAUGE:U:U
 entropy                 value:GAUGE:0:4294967295
+errors                  value:DERIVE:0:U
 evicted_keys            value:DERIVE:0:U
 expired_keys            value:DERIVE:0:U
 fanspeed                value:GAUGE:0:U
 file_handles            value:GAUGE:0:U
 file_size               value:GAUGE:0:U
 files                   value:GAUGE:0:U
+filter_result           value:DERIVE:0:U
 flow                    value:GAUGE:0:U
 fork_rate               value:DERIVE:0:U
 frequency               value:GAUGE:0:U
@@ -99,19 +103,25 @@ if_errors               rx:DERIVE:0:U, tx:DERIVE:0:U
 if_multicast            value:DERIVE:0:U
 if_octets               rx:DERIVE:0:U, tx:DERIVE:0:U
 if_packets              rx:DERIVE:0:U, tx:DERIVE:0:U
+if_rx_dropped           value:DERIVE:0:U
 if_rx_errors            value:DERIVE:0:U
 if_rx_octets            value:DERIVE:0:U
+if_rx_packets           value:DERIVE:0:U
+if_tx_dropped           value:DERIVE:0:U
 if_tx_errors            value:DERIVE:0:U
 if_tx_octets            value:DERIVE:0:U
+if_tx_packets           value:DERIVE:0:U
 invocations             value:DERIVE:0:U
 io_octets               rx:DERIVE:0:U, tx:DERIVE:0:U
 io_packets              rx:DERIVE:0:U, tx:DERIVE:0:U
+ipc                     value:GAUGE:0:U
 ipt_bytes               value:DERIVE:0:U
 ipt_packets             value:DERIVE:0:U
 irq                     value:DERIVE:0:U
 latency                 value:GAUGE:0:U
 links                   value:GAUGE:0:U
 load                    shortterm:GAUGE:0:5000, midterm:GAUGE:0:5000, longterm:GAUGE:0:5000
+memory_bandwidth        value:DERIVE:0:U
 md_disks                value:GAUGE:0:U
 memcached_command       value:DERIVE:0:U
 memcached_connections   value:GAUGE:0:U
index 808ba98bae65c48f20ec970c1c930214bdb51410..73037e49b2e2b7a05739139c92911e1d3a33734d 100644 (file)
@@ -289,7 +289,7 @@ static void *us_handle_client (void *arg)
 
                if (strcasecmp (fields[0], "getval") == 0)
                {
-                       handle_getval (fhout, buffer);
+                       cmd_handle_getval (fhout, buffer);
                }
                else if (strcasecmp (fields[0], "getthreshold") == 0)
                {
@@ -297,11 +297,11 @@ static void *us_handle_client (void *arg)
                }
                else if (strcasecmp (fields[0], "putval") == 0)
                {
-                       handle_putval (fhout, buffer);
+                       cmd_handle_putval (fhout, buffer);
                }
                else if (strcasecmp (fields[0], "listval") == 0)
                {
-                       handle_listval (fhout, buffer);
+                       cmd_handle_listval (fhout, buffer);
                }
                else if (strcasecmp (fields[0], "putnotif") == 0)
                {
@@ -309,7 +309,7 @@ static void *us_handle_client (void *arg)
                }
                else if (strcasecmp (fields[0], "flush") == 0)
                {
-                       handle_flush (fhout, buffer);
+                       cmd_handle_flush (fhout, buffer);
                }
                else
                {
index cbe2f8c5dcaf2ebcaf4ff4fc059bbffa684d805e..f0e1a6f42df4c48106a128ab2227037aa56f7171 100644 (file)
@@ -58,17 +58,13 @@ static time_t boottime;
 extern kstat_ctl_t *kc;
 #endif /* #endif HAVE_LIBKSTAT */
 
-static void uptime_submit (gauge_t uptime)
+static void uptime_submit (gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = uptime;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "uptime", sizeof (vl.plugin));
        sstrncpy (vl.type, "uptime", sizeof (vl.type));
 
index 30e0dbe67020817ed0d4b2630eb0341f99cdd5be..e0c5116846cd5d5b3f2add69725118e21fd3f131 100644 (file)
 
 static void users_submit (gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "users", sizeof (vl.plugin));
        sstrncpy (vl.type, "users", sizeof (vl.plugin));
 
index 1876150f38a0f6155fca7de383b86a49247f3c1d..9ef50ffb3c216d819d2b256b26956912af67b8f8 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/utils_cmd_flush.c
- * Copyright (C) 2008       Sebastian Harl
+ * Copyright (C) 2008, 2016 Sebastian Harl
  * Copyright (C) 2008       Florian Forster
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
 #include "utils_parse_option.h"
 #include "utils_cmd_flush.h"
 
-int handle_flush (FILE *fh, char *buffer)
+cmd_status_t cmd_parse_flush (size_t argc, char **argv,
+               cmd_flush_t *ret_flush, const cmd_options_t *opts,
+               cmd_error_handler_t *err)
 {
-       int success = 0;
-       int error   = 0;
-
-       double timeout = 0.0;
-       char **plugins = NULL;
-       size_t plugins_num = 0;
-       char **identifiers = NULL;
-       size_t identifiers_num = 0;
-
-#define PRINT_TO_SOCK(fh, ...) \
-       do { \
-               if (fprintf (fh, __VA_ARGS__) < 0) { \
-                       char errbuf[1024]; \
-                       WARNING ("handle_flush: failed to write to socket #%i: %s", \
-                                       fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-                       strarray_free (plugins, plugins_num); \
-                       strarray_free (identifiers, identifiers_num); \
-                       return -1; \
-               } \
-               fflush(fh); \
-       } while (0)
-
-       if ((fh == NULL) || (buffer == NULL))
-               return (-1);
-
-       DEBUG ("utils_cmd_flush: handle_flush (fh = %p, buffer = %s);",
-                       (void *) fh, buffer);
 
-       if (strncasecmp ("FLUSH", buffer, strlen ("FLUSH")) != 0)
+       if ((ret_flush == NULL) || (opts == NULL))
        {
-               PRINT_TO_SOCK (fh, "-1 Cannot parse command.\n");
-               return (-1);
+               errno = EINVAL;
+               cmd_error (CMD_ERROR, err, "Invalid arguments to cmd_parse_flush.");
+               return (CMD_ERROR);
        }
-       buffer += strlen ("FLUSH");
 
-       while (*buffer != 0)
+       for (size_t i = 0; i < argc; i++)
        {
                char *opt_key;
                char *opt_value;
@@ -78,66 +53,133 @@ int handle_flush (FILE *fh, char *buffer)
 
                opt_key = NULL;
                opt_value = NULL;
-               status = parse_option (&buffer, &opt_key, &opt_value);
+               status = cmd_parse_option (argv[i], &opt_key, &opt_value, err);
                if (status != 0)
                {
-                       PRINT_TO_SOCK (fh, "-1 Parsing options failed.\n");
-                       strarray_free (plugins, plugins_num);
-                       strarray_free (identifiers, identifiers_num);
-                       return (-1);
+                       if (status == CMD_NO_OPTION)
+                               cmd_error (CMD_PARSE_ERROR, err,
+                                               "Invalid option string `%s'.", argv[i]);
+                       cmd_destroy_flush (ret_flush);
+                       return (CMD_PARSE_ERROR);
                }
 
                if (strcasecmp ("plugin", opt_key) == 0)
-                       strarray_add (&plugins, &plugins_num, opt_value);
+               {
+                       strarray_add (&ret_flush->plugins, &ret_flush->plugins_num,
+                                       opt_value);
+               }
                else if (strcasecmp ("identifier", opt_key) == 0)
-                       strarray_add (&identifiers, &identifiers_num, opt_value);
+               {
+                       identifier_t *id = realloc (ret_flush->identifiers,
+                                       (ret_flush->identifiers_num + 1) * sizeof (*id));
+                       if (id == NULL)
+                       {
+                               cmd_error (CMD_ERROR, err, "realloc failed.");
+                               cmd_destroy_flush (ret_flush);
+                               return (CMD_ERROR);
+                       }
+
+                       ret_flush->identifiers = id;
+                       id = ret_flush->identifiers + ret_flush->identifiers_num;
+                       ret_flush->identifiers_num++;
+                       if (parse_identifier (opt_value,
+                                               &id->host, &id->plugin, &id->plugin_instance,
+                                               &id->type, &id->type_instance,
+                                               opts->identifier_default_host) != 0)
+                       {
+                               cmd_error (CMD_PARSE_ERROR, err,
+                                               "Invalid identifier `%s'.", opt_value);
+                               cmd_destroy_flush (ret_flush);
+                               return (CMD_PARSE_ERROR);
+                       }
+               }
                else if (strcasecmp ("timeout", opt_key) == 0)
                {
                        char *endptr;
 
                        errno = 0;
                        endptr = NULL;
-                       timeout = strtod (opt_value, &endptr);
+                       ret_flush->timeout = strtod (opt_value, &endptr);
 
-                       if ((endptr == opt_value) || (errno != 0) || (!isfinite (timeout)))
+                       if ((endptr == opt_value) || (errno != 0)
+                                       || (!isfinite (ret_flush->timeout)))
                        {
-                               PRINT_TO_SOCK (fh, "-1 Invalid value for option `timeout': "
-                                               "%s\n", opt_value);
-                               strarray_free (plugins, plugins_num);
-                               strarray_free (identifiers, identifiers_num);
-                               return (-1);
+                               cmd_error (CMD_PARSE_ERROR, err,
+                                               "Invalid value for option `timeout': %s",
+                                               opt_value);
+                               cmd_destroy_flush (ret_flush);
+                               return (CMD_PARSE_ERROR);
                        }
-                       else if (timeout < 0.0)
+                       else if (ret_flush->timeout < 0.0)
                        {
-                               timeout = 0.0;
+                               ret_flush->timeout = 0.0;
                        }
                }
                else
                {
-                       PRINT_TO_SOCK (fh, "-1 Cannot parse option %s\n", opt_key);
-                       strarray_free (plugins, plugins_num);
-                       strarray_free (identifiers, identifiers_num);
-                       return (-1);
+                       cmd_error (CMD_PARSE_ERROR, err,
+                                       "Cannot parse option `%s'.", opt_key);
+                       cmd_destroy_flush (ret_flush);
+                       return (CMD_PARSE_ERROR);
                }
-       } /* while (*buffer != 0) */
+       }
+
+       return (CMD_OK);
+} /* cmd_status_t cmd_parse_flush */
 
-       for (size_t i = 0; (i == 0) || (i < plugins_num); i++)
+cmd_status_t cmd_handle_flush (FILE *fh, char *buffer)
+{
+       cmd_error_handler_t err = { cmd_error_fh, fh };
+       cmd_t cmd;
+
+       int success = 0;
+       int error   = 0;
+       int status;
+
+       if ((fh == NULL) || (buffer == NULL))
+               return (-1);
+
+       DEBUG ("utils_cmd_flush: cmd_handle_flush (fh = %p, buffer = %s);",
+                       (void *) fh, buffer);
+
+       if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
+               return (status);
+       if (cmd.type != CMD_FLUSH)
+       {
+               cmd_error (CMD_UNKNOWN_COMMAND, &err, "Unexpected command: `%s'.",
+                               CMD_TO_STRING (cmd.type));
+               cmd_destroy (&cmd);
+               return (CMD_UNKNOWN_COMMAND);
+       }
+
+       for (size_t i = 0; (i == 0) || (i < cmd.cmd.flush.plugins_num); i++)
        {
                char *plugin = NULL;
 
-               if (plugins_num != 0)
-                       plugin = plugins[i];
+               if (cmd.cmd.flush.plugins_num != 0)
+                       plugin = cmd.cmd.flush.plugins[i];
 
-               for (size_t j = 0; (j == 0) || (j < identifiers_num); j++)
+               for (size_t j = 0; (j == 0) || (j < cmd.cmd.flush.identifiers_num); j++)
                {
                        char *identifier = NULL;
+                       char buffer[1024];
                        int status;
 
-                       if (identifiers_num != 0)
-                               identifier = identifiers[j];
+                       if (cmd.cmd.flush.identifiers_num != 0)
+                       {
+                               identifier_t *id = cmd.cmd.flush.identifiers + j;
+                               if (format_name (buffer, sizeof (buffer),
+                                                       id->host, id->plugin, id->plugin_instance,
+                                                       id->type, id->type_instance) != 0)
+                               {
+                                       error++;
+                                       continue;
+                               }
+                               identifier = buffer;
+                       }
 
                        status = plugin_flush (plugin,
-                                       DOUBLE_TO_CDTIME_T (timeout),
+                                       DOUBLE_TO_CDTIME_T (cmd.cmd.flush.timeout),
                                        identifier);
                        if (status == 0)
                                success++;
@@ -146,14 +188,26 @@ int handle_flush (FILE *fh, char *buffer)
                }
        }
 
-       PRINT_TO_SOCK (fh, "0 Done: %i successful, %i errors\n",
+       cmd_error (CMD_OK, &err, "Done: %i successful, %i errors",
                        success, error);
 
-       strarray_free (plugins, plugins_num);
-       strarray_free (identifiers, identifiers_num);
+       cmd_destroy (&cmd);
        return (0);
 #undef PRINT_TO_SOCK
-} /* int handle_flush */
+} /* cmd_status_t cmd_handle_flush */
+
+void cmd_destroy_flush (cmd_flush_t *flush)
+{
+       if (flush == NULL)
+               return;
+
+       strarray_free (flush->plugins, flush->plugins_num);
+       flush->plugins = NULL;
+       flush->plugins_num = 0;
+
+       sfree (flush->identifiers);
+       flush->identifiers_num = 0;
+} /* void cmd_destroy_flush */
 
 /* vim: set sw=4 ts=4 tw=78 noexpandtab : */
 
index f43b25726749b20348f9c4ae641bb223dc603c5a..9dbff20c74cc611095db17c7fb8974d78f3b0b50 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * collectd - src/utils_cmd_flush.h
- * Copyright (C) 2008       Sebastian Harl
+ * Copyright (C) 2008, 2016 Sebastian Harl
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 
 #include <stdio.h>
 
-int handle_flush (FILE *fh, char *buffer);
+#include "utils_cmds.h"
+
+cmd_status_t cmd_parse_flush (size_t argc, char **argv,
+               cmd_flush_t *ret_flush, const cmd_options_t *opts,
+               cmd_error_handler_t *err);
+
+cmd_status_t cmd_handle_flush (FILE *fh, char *buffer);
+
+void cmd_destroy_flush (cmd_flush_t *flush);
 
 #endif /* UTILS_CMD_FLUSH_H */
 
index b2a0a23bfd892e7b77b6e24c4c1ad3934d69a6bc..e6086f27193226c631f9bb7e4a8358c0dde545e2 100644 (file)
@@ -101,7 +101,8 @@ int handle_getthreshold (FILE *fh, char *buffer)
 
   status = parse_identifier (identifier_copy, &host,
       &plugin, &plugin_instance,
-      &type, &type_instance);
+      &type, &type_instance,
+      /* default_host = */ NULL);
   if (status != 0)
   {
     DEBUG ("handle_getthreshold: Cannot parse identifier `%s'.", identifier);
index cd88760a3746f01e4dee0a25f121987553e48ae8..f29680a1393fba6f6b4e32061d39a693efa77a1e 100644 (file)
 #include "utils_parse_option.h"
 #include "utils_cmd_getval.h"
 
+cmd_status_t cmd_parse_getval (size_t argc, char **argv,
+    cmd_getval_t *ret_getval, const cmd_options_t *opts,
+    cmd_error_handler_t *err)
+{
+  char *identifier_copy;
+  int status;
+
+  if ((ret_getval == NULL) || (opts == NULL))
+  {
+    errno = EINVAL;
+    cmd_error (CMD_ERROR, err, "Invalid arguments to cmd_parse_getval.");
+    return (CMD_ERROR);
+  }
+
+  if (argc != 1)
+  {
+    if (argc == 0)
+      cmd_error (CMD_PARSE_ERROR, err, "Missing identifier.");
+    else
+      cmd_error (CMD_PARSE_ERROR, err,
+         "Garbage after identifier: `%s'.", argv[1]);
+    return (CMD_PARSE_ERROR);
+  }
+
+  /* parse_identifier() modifies its first argument,
+   * returning pointers into it */
+  identifier_copy = sstrdup (argv[0]);
+
+  status = parse_identifier (argv[0], &ret_getval->identifier.host,
+      &ret_getval->identifier.plugin, &ret_getval->identifier.plugin_instance,
+      &ret_getval->identifier.type, &ret_getval->identifier.type_instance,
+      opts->identifier_default_host);
+  if (status != 0)
+  {
+    DEBUG ("cmd_parse_getval: Cannot parse identifier `%s'.", identifier_copy);
+    cmd_error (CMD_PARSE_ERROR, err,
+       "Cannot parse identifier `%s'.", identifier_copy);
+    sfree (identifier_copy);
+    return (CMD_PARSE_ERROR);
+  }
+
+  ret_getval->raw_identifier = identifier_copy;
+  return (CMD_OK);
+} /* cmd_status_t cmd_parse_getval */
+
 #define print_to_socket(fh, ...) \
   do { \
     if (fprintf (fh, __VA_ARGS__) < 0) { \
       char errbuf[1024]; \
-      WARNING ("handle_getval: failed to write to socket #%i: %s", \
+      WARNING ("cmd_handle_getval: failed to write to socket #%i: %s", \
           fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
       return -1; \
     } \
     fflush(fh); \
   } while (0)
 
-int handle_getval (FILE *fh, char *buffer)
+cmd_status_t cmd_handle_getval (FILE *fh, char *buffer)
 {
-  char *command;
-  char *identifier;
-  char *identifier_copy;
+  cmd_error_handler_t err = { cmd_error_fh, fh };
+  cmd_status_t status;
+  cmd_t cmd;
 
-  char *hostname;
-  char *plugin;
-  char *plugin_instance;
-  char *type;
-  char *type_instance;
   gauge_t *values;
   size_t values_num;
 
   const data_set_t *ds;
 
-  int   status;
 
   if ((fh == NULL) || (buffer == NULL))
     return (-1);
 
-  DEBUG ("utils_cmd_getval: handle_getval (fh = %p, buffer = %s);",
+  DEBUG ("utils_cmd_getval: cmd_handle_getval (fh = %p, buffer = %s);",
       (void *) fh, buffer);
 
-  command = NULL;
-  status = parse_string (&buffer, &command);
-  if (status != 0)
-  {
-    print_to_socket (fh, "-1 Cannot parse command.\n");
-    return (-1);
-  }
-  assert (command != NULL);
-
-  if (strcasecmp ("GETVAL", command) != 0)
-  {
-    print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
-    return (-1);
-  }
-
-  identifier = NULL;
-  status = parse_string (&buffer, &identifier);
-  if (status != 0)
-  {
-    print_to_socket (fh, "-1 Cannot parse identifier.\n");
-    return (-1);
-  }
-  assert (identifier != NULL);
-
-  if (*buffer != 0)
-  {
-    print_to_socket (fh, "-1 Garbage after end of command: %s\n", buffer);
-    return (-1);
-  }
-
-  /* parse_identifier() modifies its first argument,
-   * returning pointers into it */
-  identifier_copy = sstrdup (identifier);
-
-  status = parse_identifier (identifier_copy, &hostname,
-      &plugin, &plugin_instance,
-      &type, &type_instance);
-  if (status != 0)
+  if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
+    return (status);
+  if (cmd.type != CMD_GETVAL)
   {
-    DEBUG ("handle_getval: Cannot parse identifier `%s'.", identifier);
-    print_to_socket (fh, "-1 Cannot parse identifier `%s'.\n", identifier);
-    sfree (identifier_copy);
-    return (-1);
+    cmd_error (CMD_UNKNOWN_COMMAND, &err,
+       "Unexpected command: `%s'.", CMD_TO_STRING (cmd.type));
+    cmd_destroy (&cmd);
+    return (CMD_UNKNOWN_COMMAND);
   }
 
-  ds = plugin_get_ds (type);
+  ds = plugin_get_ds (cmd.cmd.getval.identifier.type);
   if (ds == NULL)
   {
-    DEBUG ("handle_getval: plugin_get_ds (%s) == NULL;", type);
-    print_to_socket (fh, "-1 Type `%s' is unknown.\n", type);
-    sfree (identifier_copy);
+    DEBUG ("cmd_handle_getval: plugin_get_ds (%s) == NULL;",
+       cmd.cmd.getval.identifier.type);
+    cmd_error (CMD_ERROR, &err, "Type `%s' is unknown.\n",
+       cmd.cmd.getval.identifier.type);
+    cmd_destroy (&cmd);
     return (-1);
   }
 
   values = NULL;
   values_num = 0;
-  status = uc_get_rate_by_name (identifier, &values, &values_num);
+  status = uc_get_rate_by_name (cmd.cmd.getval.raw_identifier, &values, &values_num);
   if (status != 0)
   {
-    print_to_socket (fh, "-1 No such value\n");
-    sfree (identifier_copy);
-    return (-1);
+    cmd_error (CMD_ERROR, &err, "No such value.");
+    cmd_destroy (&cmd);
+    return (CMD_ERROR);
   }
 
   if (ds->ds_num != values_num)
@@ -137,10 +143,10 @@ int handle_getval (FILE *fh, char *buffer)
     ERROR ("ds[%s]->ds_num = %zu, "
        "but uc_get_rate_by_name returned %zu values.",
        ds->type, ds->ds_num, values_num);
-    print_to_socket (fh, "-1 Error reading value from cache.\n");
+    cmd_error (CMD_ERROR, &err, "Error reading value from cache.");
     sfree (values);
-    sfree (identifier_copy);
-    return (-1);
+    cmd_destroy (&cmd);
+    return (CMD_ERROR);
   }
 
   print_to_socket (fh, "%zu Value%s found\n", values_num,
@@ -159,9 +165,17 @@ int handle_getval (FILE *fh, char *buffer)
   }
 
   sfree (values);
-  sfree (identifier_copy);
+  cmd_destroy (&cmd);
+
+  return (CMD_OK);
+} /* cmd_status_t cmd_handle_getval */
+
+void cmd_destroy_getval (cmd_getval_t *getval)
+{
+  if (getval == NULL)
+    return;
 
-  return (0);
-} /* int handle_getval */
+  sfree (getval->raw_identifier);
+} /* void cmd_destroy_getval */
 
 /* vim: set sw=2 sts=2 ts=8 : */
index 5e12f692b2416d99c2ab6b30ed689dc41756c4a8..b0c64be1030fd0350d9512745fc6da493663b1a7 100644 (file)
 
 #include <stdio.h>
 
-int handle_getval (FILE *fh, char *buffer);
+#include "utils_cmds.h"
+
+cmd_status_t cmd_parse_getval (size_t argc, char **argv,
+    cmd_getval_t *ret_getval, const cmd_options_t *opts,
+    cmd_error_handler_t *err);
+
+cmd_status_t cmd_handle_getval (FILE *fh, char *buffer);
+
+void cmd_destroy_getval (cmd_getval_t *getval);
 
 #endif /* UTILS_CMD_GETVAL_H */
 
index afbd01d0ceed106dd2b4852d06ca5b7a76e3dcea..27b88cbfdc923ea02f4b3d603dac48454bc96a74 100644 (file)
 #include "utils_cache.h"
 #include "utils_parse_option.h"
 
+cmd_status_t cmd_parse_listval (size_t argc, char **argv,
+    cmd_listval_t *ret_listval __attribute__((unused)),
+    const cmd_options_t *opts __attribute__((unused)),
+    cmd_error_handler_t *err)
+{
+  if (argc != 0)
+  {
+    cmd_error (CMD_PARSE_ERROR, err,
+       "Garbage after end of command: `%s'.", argv[0]);
+    return (CMD_PARSE_ERROR);
+  }
+
+  return (CMD_OK);
+} /* cmd_status_t cmd_parse_listval */
+
 #define free_everything_and_return(status) do { \
     for (size_t j = 0; j < number; j++) { \
       sfree(names[j]); \
       char errbuf[1024]; \
       WARNING ("handle_listval: failed to write to socket #%i: %s", \
           fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-      free_everything_and_return (-1); \
+      free_everything_and_return (CMD_ERROR); \
     } \
     fflush(fh); \
   } while (0)
 
-int handle_listval (FILE *fh, char *buffer)
+cmd_status_t cmd_handle_listval (FILE *fh, char *buffer)
 {
-  char *command;
+  cmd_error_handler_t err = { cmd_error_fh, fh };
+  cmd_status_t status;
+  cmd_t cmd;
+
   char **names = NULL;
   cdtime_t *times = NULL;
   size_t number = 0;
-  int status;
 
   DEBUG ("utils_cmd_listval: handle_listval (fh = %p, buffer = %s);",
       (void *) fh, buffer);
 
-  command = NULL;
-  status = parse_string (&buffer, &command);
-  if (status != 0)
+  if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
+    return (status);
+  if (cmd.type != CMD_LISTVAL)
   {
-    print_to_socket (fh, "-1 Cannot parse command.\n");
-    free_everything_and_return (-1);
-  }
-  assert (command != NULL);
-
-  if (strcasecmp ("LISTVAL", command) != 0)
-  {
-    print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
-    free_everything_and_return (-1);
-  }
-
-  if (*buffer != 0)
-  {
-    print_to_socket (fh, "-1 Garbage after end of command: %s\n", buffer);
-    free_everything_and_return (-1);
+    cmd_error (CMD_UNKNOWN_COMMAND, &err,
+       "Unexpected command: `%s'.", CMD_TO_STRING (cmd.type));
+    free_everything_and_return (CMD_UNKNOWN_COMMAND);
   }
 
   status = uc_get_names (&names, &times, &number);
   if (status != 0)
   {
     DEBUG ("command listval: uc_get_names failed with status %i", status);
-    print_to_socket (fh, "-1 uc_get_names failed.\n");
-    free_everything_and_return (-1);
+    cmd_error (CMD_ERROR, &err, "uc_get_names failed.");
+    free_everything_and_return (CMD_ERROR);
   }
 
   print_to_socket (fh, "%i Value%s found\n",
@@ -100,7 +105,12 @@ int handle_listval (FILE *fh, char *buffer)
     print_to_socket (fh, "%.3f %s\n", CDTIME_T_TO_DOUBLE (times[i]),
                names[i]);
 
-  free_everything_and_return (0);
-} /* int handle_listval */
+  free_everything_and_return (CMD_OK);
+} /* cmd_status_t cmd_handle_listval */
+
+void cmd_destroy_listval (cmd_listval_t *listval __attribute__((unused)))
+{
+  /* nothing to do */
+} /* void cmd_destroy_listval */
 
 /* vim: set sw=2 sts=2 ts=8 : */
index fc125bc1ce0ec45f6eb0db694037bba25857bb6d..895878c02e25f05a7ce188489570e9499e53ae8c 100644 (file)
 
 #include <stdio.h>
 
-int handle_listval (FILE *fh, char *buffer);
+#include "utils_cmds.h"
+
+cmd_status_t cmd_parse_listval (size_t argc, char **argv,
+    cmd_listval_t *ret_listval, const cmd_options_t *opts,
+    cmd_error_handler_t *err);
+
+cmd_status_t cmd_handle_listval (FILE *fh, char *buffer);
+
+void cmd_destroy_listval (cmd_listval_t *listval);
 
 #endif /* UTILS_CMD_LISTVAL_H */
 
index bf3e2b6f2b9880cf50f6d602bf721ed42c51afb7..691f1f806b2bfc83b176b850159c8ef345173fab 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/utils_cmd_putval.c
  * Copyright (C) 2007-2009  Florian octo Forster
+ * Copyright (C) 2016       Sebastian tokkee Harl
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -22,6 +23,7 @@
  *
  * Authors:
  *   Florian octo Forster <octo at collectd.org>
+ *   Sebastian tokkee Harl <sh at tokkee.org>
  **/
 
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
 
+#include "utils_cmds.h"
+#include "utils_cmd_putval.h"
 #include "utils_parse_option.h"
 #include "utils_cmd_putval.h"
 
-#define print_to_socket(fh, ...) \
-    do { \
-        if (fprintf (fh, __VA_ARGS__) < 0) { \
-            char errbuf[1024]; \
-            WARNING ("handle_putval: failed to write to socket #%i: %s", \
-                    fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
-            sfree (vl.values); \
-            return -1; \
-        } \
-        fflush(fh); \
-    } while (0)
+/*
+ * private helper functions
+ */
 
 static int set_option (value_list_t *vl, const char *key, const char *value)
 {
@@ -66,11 +62,18 @@ static int set_option (value_list_t *vl, const char *key, const char *value)
                return (1);
 
        return (0);
-} /* int parse_option */
+} /* int set_option */
+
+/*
+ * public API
+ */
 
-int handle_putval (FILE *fh, char *buffer)
+cmd_status_t cmd_parse_putval (size_t argc, char **argv,
+               cmd_putval_t *ret_putval, const cmd_options_t *opts,
+               cmd_error_handler_t *err)
 {
-       char *command;
+       cmd_status_t result;
+
        char *identifier;
        char *hostname;
        char *plugin;
@@ -78,56 +81,44 @@ int handle_putval (FILE *fh, char *buffer)
        char *type;
        char *type_instance;
        int   status;
-       int   values_submitted;
 
        char *identifier_copy;
 
        const data_set_t *ds;
        value_list_t vl = VALUE_LIST_INIT;
-       vl.values = NULL;
-
-       DEBUG ("utils_cmd_putval: handle_putval (fh = %p, buffer = %s);",
-                       (void *) fh, buffer);
 
-       command = NULL;
-       status = parse_string (&buffer, &command);
-       if (status != 0)
+       if ((ret_putval == NULL) || (opts == NULL))
        {
-               print_to_socket (fh, "-1 Cannot parse command.\n");
-               return (-1);
+               errno = EINVAL;
+               cmd_error (CMD_ERROR, err, "Invalid arguments to cmd_parse_putval.");
+               return (CMD_ERROR);
        }
-       assert (command != NULL);
 
-       if (strcasecmp ("PUTVAL", command) != 0)
+       if (argc < 2)
        {
-               print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
-               return (-1);
+               cmd_error (CMD_PARSE_ERROR, err,
+                               "Missing identifier and/or value-list.");
+               return (CMD_PARSE_ERROR);
        }
 
-       identifier = NULL;
-       status = parse_string (&buffer, &identifier);
-       if (status != 0)
-       {
-               print_to_socket (fh, "-1 Cannot parse identifier.\n");
-               return (-1);
-       }
-       assert (identifier != NULL);
+       identifier = argv[0];
 
-       /* parse_identifier() modifies its first argument,
-        * returning pointers into it */
+       /* parse_identifier() modifies its first argument, returning pointers into
+        * it; retain the old value for later. */
        identifier_copy = sstrdup (identifier);
 
-       status = parse_identifier (identifier_copy, &hostname,
+       status = parse_identifier (identifier, &hostname,
                        &plugin, &plugin_instance,
-                       &type, &type_instance);
+                       &type, &type_instance,
+                       opts->identifier_default_host);
        if (status != 0)
        {
-               DEBUG ("handle_putval: Cannot parse identifier `%s'.",
-                               identifier);
-               print_to_socket (fh, "-1 Cannot parse identifier `%s'.\n",
-                               identifier);
+               DEBUG ("cmd_handle_putval: Cannot parse identifier `%s'.",
+                               identifier_copy);
+               cmd_error (CMD_PARSE_ERROR, err, "Cannot parse identifier `%s'.",
+                               identifier_copy);
                sfree (identifier_copy);
-               return (-1);
+               return (CMD_PARSE_ERROR);
        }
 
        if ((strlen (hostname) >= sizeof (vl.host))
@@ -137,9 +128,9 @@ int handle_putval (FILE *fh, char *buffer)
                        || ((type_instance != NULL)
                                && (strlen (type_instance) >= sizeof (vl.type_instance))))
        {
-               print_to_socket (fh, "-1 Identifier too long.\n");
+               cmd_error (CMD_PARSE_ERROR, err, "Identifier too long.");
                sfree (identifier_copy);
-               return (-1);
+               return (CMD_PARSE_ERROR);
        }
 
        sstrncpy (vl.host, hostname, sizeof (vl.host));
@@ -151,84 +142,148 @@ int handle_putval (FILE *fh, char *buffer)
                sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
        ds = plugin_get_ds (type);
-       if (ds == NULL) {
-               print_to_socket (fh, "-1 Type `%s' isn't defined.\n", type);
+       if (ds == NULL)
+       {
+               cmd_error (CMD_PARSE_ERROR, err, "1 Type `%s' isn't defined.", type);
                sfree (identifier_copy);
-               return (-1);
+               return (CMD_PARSE_ERROR);
        }
 
-       /* Free identifier_copy */
        hostname = NULL;
        plugin = NULL; plugin_instance = NULL;
        type = NULL;   type_instance = NULL;
-       sfree (identifier_copy);
 
        vl.values_len = ds->ds_num;
        vl.values = malloc (vl.values_len * sizeof (*vl.values));
        if (vl.values == NULL)
        {
-               print_to_socket (fh, "-1 malloc failed.\n");
-               return (-1);
+               cmd_error (CMD_ERROR, err, "malloc failed.");
+               sfree (identifier_copy);
+               return (CMD_ERROR);
        }
 
-       /* All the remaining fields are part of the optionlist. */
-       values_submitted = 0;
-       while (*buffer != 0)
+       ret_putval->raw_identifier = identifier_copy;
+       if (ret_putval->raw_identifier == NULL)
        {
-               char *string = NULL;
-               char *value  = NULL;
+               cmd_error (CMD_ERROR, err, "malloc failed.");
+               cmd_destroy_putval (ret_putval);
+               sfree (vl.values);
+               return (CMD_ERROR);
+       }
 
-               status = parse_option (&buffer, &string, &value);
-               if (status < 0)
-               {
-                       /* parse_option failed, buffer has been modified.
-                        * => we need to abort */
-                       print_to_socket (fh, "-1 Misformatted option.\n");
-                       sfree (vl.values);
-                       return (-1);
-               }
-               else if (status == 0)
+       /* All the remaining fields are part of the option list. */
+       result = CMD_OK;
+       for (size_t i = 1; i < argc; ++i)
+       {
+               value_list_t *tmp;
+
+               char *key   = NULL;
+               char *value = NULL;
+
+               status = cmd_parse_option (argv[i], &key, &value, err);
+               if (status == CMD_OK)
                {
-                       assert (string != NULL);
+                       assert (key != NULL);
                        assert (value != NULL);
-                       set_option (&vl, string, value);
+                       set_option (&vl, key, value);
                        continue;
                }
-               /* else: parse_option but buffer has not been modified. This is
-                * the default if no `=' is found.. */
+               else if (status != CMD_NO_OPTION)
+               {
+                       /* parse_option failed, buffer has been modified.
+                        * => we need to abort */
+                       result = status;
+                       break;
+               }
+               /* else: cmd_parse_option did not find an option; treat this as a
+                * value list. */
 
-               status = parse_string (&buffer, &string);
+               status = parse_values (argv[i], &vl, ds);
                if (status != 0)
                {
-                       print_to_socket (fh, "-1 Misformatted value.\n");
-                       sfree (vl.values);
-                       return (-1);
+                       cmd_error (CMD_PARSE_ERROR, err, "Parsing the values string failed.");
+                       result = CMD_PARSE_ERROR;
+                       break;
                }
-               assert (string != NULL);
 
-               status = parse_values (string, &vl, ds);
-               if (status != 0)
+               tmp = (value_list_t *) realloc (ret_putval->vl,
+                               (ret_putval->vl_num + 1) * sizeof(*ret_putval->vl));
+               if (tmp == NULL)
                {
-                       print_to_socket (fh, "-1 Parsing the values string failed.\n");
-                       sfree (vl.values);
-                       return (-1);
+                       cmd_error (CMD_ERROR, err, "realloc failed.");
+                       cmd_destroy_putval (ret_putval);
+                       result = CMD_ERROR;
+                       break;
                }
 
-               plugin_dispatch_values (&vl);
-               values_submitted++;
+               ret_putval->vl = tmp;
+               ret_putval->vl_num++;
+               memcpy (&ret_putval->vl[ret_putval->vl_num - 1], &vl, sizeof (vl));
        } /* while (*buffer != 0) */
        /* Done parsing the options. */
 
-       if (fh!=stdout)
-               print_to_socket (fh, "0 Success: %i %s been dispatched.\n",
-                       values_submitted,
-                       (values_submitted == 1) ? "value has" : "values have");
+       if (result != CMD_OK)
+       {
+               if (ret_putval->vl_num == 0)
+                       sfree (vl.values);
+               cmd_destroy_putval (ret_putval);
+       }
+
+       return (result);
+} /* cmd_status_t cmd_parse_putval */
 
-       sfree (vl.values);
-       return (0);
-} /* int handle_putval */
+void cmd_destroy_putval (cmd_putval_t *putval)
+{
+       if (putval == NULL)
+               return;
+
+       sfree (putval->raw_identifier);
+
+       for (size_t i = 0; i < putval->vl_num; ++i)
+       {
+               if (i == 0) /* values is shared between all entries */
+                       sfree (putval->vl[i].values);
+               meta_data_destroy (putval->vl[i].meta);
+               putval->vl[i].meta = NULL;
+       }
+       sfree (putval->vl);
+       putval->vl = NULL;
+       putval->vl_num = 0;
+} /* void cmd_destroy_putval */
+
+cmd_status_t cmd_handle_putval (FILE *fh, char *buffer)
+{
+       cmd_error_handler_t err = { cmd_error_fh, fh };
+       cmd_t cmd;
+
+       int status;
+
+       DEBUG ("utils_cmd_putval: cmd_handle_putval (fh = %p, buffer = %s);",
+                       (void *) fh, buffer);
+
+       if ((status = cmd_parse (buffer, &cmd, NULL, &err)) != CMD_OK)
+               return (status);
+       if (cmd.type != CMD_PUTVAL)
+       {
+               cmd_error (CMD_UNKNOWN_COMMAND, &err, "Unexpected command: `%s'.",
+                               CMD_TO_STRING (cmd.type));
+               cmd_destroy (&cmd);
+               return (CMD_UNKNOWN_COMMAND);
+       }
+
+       for (size_t i = 0; i < cmd.cmd.putval.vl_num; ++i)
+               plugin_dispatch_values (&cmd.cmd.putval.vl[i]);
+
+       if (fh != stdout)
+               cmd_error (CMD_OK, &err, "Success: %i %s been dispatched.",
+                               (int)cmd.cmd.putval.vl_num,
+                               (cmd.cmd.putval.vl_num == 1) ? "value has" : "values have");
+
+       cmd_destroy (&cmd);
+       return (CMD_OK);
+} /* int cmd_handle_putval */
 
-int create_putval (char *ret, size_t ret_len, /* {{{ */
+int cmd_create_putval (char *ret, size_t ret_len, /* {{{ */
        const data_set_t *ds, const value_list_t *vl)
 {
        char buffer_ident[6 * DATA_MAX_NAME_LEN];
@@ -255,4 +310,4 @@ int create_putval (char *ret, size_t ret_len, /* {{{ */
                        buffer_values);
 
        return (0);
-} /* }}} int create_putval */
+} /* }}} int cmd_create_putval */
index 795409eb92e3e5e277a7a2aa6e147918d41ba874..bb0b227fc3bd26ed6c9f8cae3c43262e684173c2 100644 (file)
 #include <stdio.h>
 
 #include "plugin.h"
+#include "utils_cmds.h"
 
-int handle_putval (FILE *fh, char *buffer);
+cmd_status_t cmd_parse_putval (size_t argc, char **argv,
+               cmd_putval_t *ret_putval, const cmd_options_t *opts,
+               cmd_error_handler_t *err);
 
-int create_putval (char *ret, size_t ret_len,
+cmd_status_t cmd_handle_putval (FILE *fh, char *buffer);
+
+void cmd_destroy_putval (cmd_putval_t *putval);
+
+int cmd_create_putval (char *ret, size_t ret_len,
                const data_set_t *ds, const value_list_t *vl);
 
 #endif /* UTILS_CMD_PUTVAL_H */
diff --git a/src/utils_cmds.c b/src/utils_cmds.c
new file mode 100644 (file)
index 0000000..1f53ad1
--- /dev/null
@@ -0,0 +1,352 @@
+/**
+ * collectd - src/utils_cmds.c
+ * Copyright (C) 2008       Florian Forster
+ * Copyright (C) 2016       Sebastian 'tokkee' Harl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ *   Sebastian 'tokkee' Harl <sh at tokkee.org>
+ **/
+
+#include "utils_cmds.h"
+#include "utils_cmd_flush.h"
+#include "utils_cmd_getval.h"
+#include "utils_cmd_listval.h"
+#include "utils_cmd_putval.h"
+#include "utils_parse_option.h"
+#include "daemon/common.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+static cmd_options_t default_options = {
+       /* identifier_default_host = */ NULL,
+};
+
+/*
+ * private helper functions
+ */
+
+static cmd_status_t cmd_split (char *buffer,
+               size_t *ret_len, char ***ret_fields,
+               cmd_error_handler_t *err)
+{
+       char *field;
+       bool in_field, in_quotes;
+
+       size_t estimate, len;
+       char **fields;
+
+       estimate = 0;
+       in_field = false;
+       for (char *string = buffer; *string != '\0'; ++string)
+       {
+               /* Make a quick worst-case estimate of the number of fields by
+                * counting spaces and ignoring quotation marks. */
+               if (!isspace ((int)*string))
+               {
+                       if (!in_field)
+                       {
+                               estimate++;
+                               in_field = true;
+                       }
+               }
+               else
+               {
+                       in_field = false;
+               }
+       }
+
+       /* fields will be NULL-terminated */
+       fields = malloc ((estimate + 1) * sizeof (*fields));
+       if (fields == NULL) {
+               cmd_error (CMD_ERROR, err, "malloc failed.");
+               return (CMD_ERROR);
+       }
+
+#define END_FIELD() \
+       do { \
+               *field = '\0'; \
+               field = NULL; \
+               in_field = false; \
+       } while (0)
+#define NEW_FIELD() \
+       do { \
+               field = string; \
+               in_field = true; \
+               assert (len < estimate); \
+               fields[len] = field; \
+               field++; \
+               len++; \
+       } while (0)
+
+       len = 0;
+       field = NULL;
+       in_field = false;
+       in_quotes = false;
+       for (char *string = buffer; *string != '\0'; string++)
+       {
+               if (isspace ((int)string[0]))
+               {
+                       if (! in_quotes)
+                       {
+                               if (in_field)
+                                       END_FIELD ();
+
+                               /* skip space */
+                               continue;
+                       }
+               }
+               else if (string[0] == '"')
+               {
+                       /* Note: Two consecutive quoted fields not separated by space are
+                        * treated as different fields. This is the collectd 5.x behavior
+                        * around splitting fields. */
+
+                       if (in_quotes)
+                       {
+                               /* end of quoted field */
+                               if (! in_field) /* empty quoted string */
+                                       NEW_FIELD ();
+                               END_FIELD ();
+                               in_quotes = false;
+                               continue;
+                       }
+
+                       in_quotes = true;
+                       /* if (! in_field): add new field on next iteration
+                        * else: quoted string following an unquoted string (one field)
+                        * in either case: skip quotation mark */
+                       continue;
+               }
+               else if ((string[0] == '\\') && in_quotes)
+               {
+                       /* Outside of quotes, a backslash is a regular character (mostly
+                        * for backward compatibility). */
+
+                       if (string[1] == '\0')
+                       {
+                               free (fields);
+                               cmd_error (CMD_PARSE_ERROR, err,
+                                               "Backslash at end of string.");
+                               return (CMD_PARSE_ERROR);
+                       }
+
+                       /* un-escape the next character; skip backslash */
+                       string++;
+               }
+
+               if (! in_field)
+                       NEW_FIELD ();
+               else {
+                       *field = string[0];
+                       field++;
+               }
+       }
+
+       if (in_quotes)
+       {
+               free (fields);
+               cmd_error (CMD_PARSE_ERROR, err, "Unterminated quoted string.");
+               return (CMD_PARSE_ERROR);
+       }
+
+#undef NEW_FIELD
+#undef END_FIELD
+
+       fields[len] = NULL;
+       if (ret_len != NULL)
+               *ret_len = len;
+       if (ret_fields != NULL)
+               *ret_fields = fields;
+       else
+               free (fields);
+       return (CMD_OK);
+} /* int cmd_split */
+
+/*
+ * public API
+ */
+
+void cmd_error (cmd_status_t status, cmd_error_handler_t *err,
+               const char *format, ...)
+{
+       va_list ap;
+
+       if ((err == NULL) || (err->cb == NULL))
+               return;
+
+       va_start (ap, format);
+       err->cb (err->ud, status, format, ap);
+       va_end (ap);
+} /* void cmd_error */
+
+cmd_status_t cmd_parsev (size_t argc, char **argv, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err)
+{
+       char *command = NULL;
+       cmd_status_t status;
+
+       if ((argc < 1) || (argv == NULL) || (ret_cmd == NULL))
+       {
+               errno = EINVAL;
+               cmd_error (CMD_ERROR, err, "Missing command.");
+               return CMD_ERROR;
+       }
+
+       if (opts == NULL)
+               opts = &default_options;
+
+       memset (ret_cmd, 0, sizeof (*ret_cmd));
+       command = argv[0];
+       if (strcasecmp ("FLUSH", command) == 0)
+       {
+               ret_cmd->type = CMD_FLUSH;
+               status = cmd_parse_flush (argc - 1, argv + 1,
+                               &ret_cmd->cmd.flush, opts, err);
+       }
+       else if (strcasecmp ("GETVAL", command) == 0)
+       {
+               ret_cmd->type = CMD_GETVAL;
+               status = cmd_parse_getval (argc - 1, argv + 1,
+                               &ret_cmd->cmd.getval, opts, err);
+       }
+       else if (strcasecmp ("LISTVAL", command) == 0)
+       {
+               ret_cmd->type = CMD_LISTVAL;
+               status = cmd_parse_listval (argc - 1, argv + 1,
+                               &ret_cmd->cmd.listval, opts, err);
+       }
+       else if (strcasecmp ("PUTVAL", command) == 0)
+       {
+               ret_cmd->type = CMD_PUTVAL;
+               status = cmd_parse_putval (argc - 1, argv + 1,
+                               &ret_cmd->cmd.putval, opts, err);
+       }
+       else
+       {
+               ret_cmd->type = CMD_UNKNOWN;
+               cmd_error (CMD_UNKNOWN_COMMAND, err,
+                               "Unknown command `%s'.", command);
+               return (CMD_UNKNOWN_COMMAND);
+       }
+
+       if (status != CMD_OK)
+               ret_cmd->type = CMD_UNKNOWN;
+       return (status);
+} /* cmd_status_t cmd_parsev */
+
+cmd_status_t cmd_parse (char *buffer, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err)
+{
+       char **fields = NULL;
+       size_t fields_num = 0;
+       cmd_status_t status;
+
+       if ((status = cmd_split (buffer, &fields_num, &fields, err)) != CMD_OK)
+               return status;
+
+       status = cmd_parsev (fields_num, fields, ret_cmd, opts, err);
+       free (fields);
+       return (status);
+} /* cmd_status_t cmd_parse */
+
+void cmd_destroy (cmd_t *cmd)
+{
+       if (cmd == NULL)
+               return;
+
+       switch (cmd->type)
+       {
+               case CMD_UNKNOWN:
+                       /* nothing to do */
+                       break;
+               case CMD_FLUSH:
+                       cmd_destroy_flush (&cmd->cmd.flush);
+                       break;
+               case CMD_GETVAL:
+                       cmd_destroy_getval (&cmd->cmd.getval);
+                       break;
+               case CMD_LISTVAL:
+                       cmd_destroy_listval (&cmd->cmd.listval);
+                       break;
+               case CMD_PUTVAL:
+                       cmd_destroy_putval (&cmd->cmd.putval);
+                       break;
+       }
+} /* void cmd_destroy */
+
+cmd_status_t cmd_parse_option (char *field,
+               char **ret_key, char **ret_value, cmd_error_handler_t *err)
+{
+       char *key, *value;
+
+       if (field == NULL)
+       {
+               errno = EINVAL;
+               cmd_error (CMD_ERROR, err, "Invalid argument to cmd_parse_option.");
+               return (CMD_ERROR);
+       }
+       key = value = field;
+
+       /* Look for the equal sign. */
+       while (isalnum ((int)value[0]) || (value[0] == '_') || (value[0] == ':'))
+               value++;
+       if ((value[0] != '=') || (value == key))
+       {
+               /* Whether this is a fatal error is up to the caller. */
+               return (CMD_NO_OPTION);
+       }
+       *value = '\0';
+       value++;
+
+       if (ret_key != NULL)
+               *ret_key = key;
+       if (ret_value != NULL)
+               *ret_value = value;
+
+       return (CMD_OK);
+} /* cmd_status_t cmd_parse_option */
+
+void cmd_error_fh (void *ud, cmd_status_t status,
+               const char *format, va_list ap)
+{
+       FILE *fh = ud;
+       int code = -1;
+       char buf[1024];
+
+       if (status == CMD_OK)
+               code = 0;
+
+       vsnprintf (buf, sizeof(buf), format, ap);
+       buf[sizeof (buf) - 1] = '\0';
+       if (fprintf (fh, "%i %s\n", code, buf) < 0)
+       {
+               char errbuf[1024];
+               WARNING ("utils_cmds: failed to write to file-handle #%i: %s",
+                               fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf)));
+               return;
+       }
+
+       fflush (fh);
+} /* void cmd_error_fh */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
diff --git a/src/utils_cmds.h b/src/utils_cmds.h
new file mode 100644 (file)
index 0000000..205e89a
--- /dev/null
@@ -0,0 +1,211 @@
+/**
+ * collectd - src/utils_cmds.h
+ * Copyright (C) 2016 Sebastian 'tokkee' Harl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Sebastian 'tokkee' Harl <sh at tokkee.org>
+ **/
+
+#ifndef UTILS_CMDS_H
+#define UTILS_CMDS_H 1
+
+#include "plugin.h"
+
+#include <stdarg.h>
+
+typedef enum {
+       CMD_UNKNOWN = 0,
+       CMD_FLUSH   = 1,
+       CMD_GETVAL  = 2,
+       CMD_LISTVAL = 3,
+       CMD_PUTVAL  = 4,
+} cmd_type_t;
+#define CMD_TO_STRING(type) \
+       ((type) == CMD_FLUSH) ? "FLUSH" \
+               : ((type) == CMD_GETVAL) ? "GETVAL" \
+               : ((type) == CMD_LISTVAL) ? "LISTVAL" \
+               : ((type) == CMD_PUTVAL) ? "PUTVAL" \
+               : "UNKNOWN"
+
+typedef struct {
+       double timeout;
+
+       char **plugins;
+       size_t plugins_num;
+       identifier_t *identifiers;
+       size_t identifiers_num;
+} cmd_flush_t;
+
+typedef struct {
+       char *raw_identifier;
+       identifier_t identifier;
+} cmd_getval_t;
+
+typedef struct {
+} cmd_listval_t;
+
+typedef struct {
+       /* The raw identifier as provided by the user. */
+       char *raw_identifier;
+
+       /* An array of the fully parsed identifier and all value lists, and their
+        * options as provided by the user. */
+       value_list_t *vl;
+       size_t vl_num;
+} cmd_putval_t;
+
+/*
+ * NAME
+ *   cmd_t
+ *
+ * DESCRIPTION
+ *   The representation of a fully parsed command.
+ */
+typedef struct {
+       cmd_type_t type;
+       union {
+               cmd_flush_t flush;
+               cmd_getval_t getval;
+               cmd_listval_t listval;
+               cmd_putval_t putval;
+       } cmd;
+} cmd_t;
+
+/*
+ * NAME
+ *   cmd_options_t
+ *
+ * DESCRIPTIONS
+ *   Optional settings for tuning the parser behavior.
+ */
+typedef struct {
+       /* identifier_default_host: If non-NULL, the hostname is optional and will
+        * default to the specified value. */
+       char *identifier_default_host;
+} cmd_options_t;
+
+/*
+ * NAME
+ *   cmd_status_t
+ *
+ * DESCRIPTION
+ *   Status codes describing the parse result.
+ */
+typedef enum {
+       CMD_OK              =  0,
+       CMD_ERROR           = -1,
+       CMD_PARSE_ERROR     = -2,
+       CMD_UNKNOWN_COMMAND = -3,
+
+       /* Not necessarily fatal errors. */
+       CMD_NO_OPTION       =  1,
+} cmd_status_t;
+
+/*
+ * NAME
+ *   cmd_error_handler_t
+ *
+ * DESCRIPTION
+ *   An error handler describes a callback to be invoked when the parser
+ *   encounters an error. The user data pointer will be passed to the callback
+ *   as the first argument.
+ */
+typedef struct {
+       void (*cb) (void *, cmd_status_t, const char *, va_list);
+       void *ud;
+} cmd_error_handler_t;
+
+/*
+ * NAME:
+ *   cmd_error
+ *
+ * DESCRIPTION
+ *   Reports an error via the specified error handler (if set).
+ */
+void cmd_error (cmd_status_t status, cmd_error_handler_t *err,
+               const char *format, ...);
+
+/*
+ * NAME
+ *   cmd_parse
+ *
+ * DESCRIPTION
+ *   Parse a command string and populate a command object.
+ *
+ * PARAMETERS
+ *   `buffer'  The command string to be parsed.
+ *   `ret_cmd' The parse result will be stored at this location.
+ *   `opts'    Parser options. If NULL, defaults will be used.
+ *   `err'     An optional error handler to invoke on error.
+ *
+ * RETURN VALUE
+ *   CMD_OK on success or the respective error code otherwise.
+ */
+cmd_status_t cmd_parse (char *buffer, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err);
+
+cmd_status_t cmd_parsev (size_t argc, char **argv, cmd_t *ret_cmd,
+               const cmd_options_t *opts, cmd_error_handler_t *err);
+
+void cmd_destroy (cmd_t *cmd);
+
+/*
+ * NAME
+ *   cmd_parse_option
+ *
+ * DESCRIPTION
+ *   Parses a command option which must be of the form:
+ *     name=value with \ and spaces
+ *
+ * PARAMETERS
+ *   `field'     The parsed input field with any quotes removed and special
+ *               characters unescaped.
+ *   `ret_key'   The parsed key will be stored at this location.
+ *   `ret_value' The parsed value will be stored at this location.
+ *
+ * RETURN VALUE
+ *   CMD_OK on success or an error code otherwise.
+ *   CMD_NO_OPTION if `field' does not represent an option at all (missing
+ *   equal sign).
+ */
+cmd_status_t cmd_parse_option (char *field,
+               char **ret_key, char **ret_value, cmd_error_handler_t *err);
+
+/*
+ * NAME
+ *   cmd_error_fh
+ *
+ * DESCRIPTION
+ *   An error callback writing the message to an open file handle using the
+ *   format expected by the unixsock or exec plugins.
+ *
+ * PARAMETERS
+ *   `ud'     Error handler user-data pointer. This must be an open
+ *            file-handle (FILE *).
+ *   `status' The error status code.
+ *   `format' Printf-style format string.
+ *   `ap'     Variable argument list providing the arguments for the format
+ *            string.
+ */
+void cmd_error_fh (void *ud, cmd_status_t status,
+               const char *format, va_list ap);
+
+#endif /* UTILS_CMDS_H */
diff --git a/src/utils_cmds_test.c b/src/utils_cmds_test.c
new file mode 100644 (file)
index 0000000..9e9eae3
--- /dev/null
@@ -0,0 +1,320 @@
+/**
+ * collectd - src/tests/utils_cmds_test.c
+ * Copyright (C) 2016       Sebastian 'tokkee' Harl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *   Sebastian 'tokkee' Harl <sh at tokkee.org>
+ **/
+
+#include "common.h"
+#include "testing.h"
+#include "utils_cmds.h"
+
+static void error_cb (void *ud, cmd_status_t status,
+               const char *format, va_list ap)
+{
+       if (status == CMD_OK)
+               return;
+
+       printf ("ERROR[%d]: ", status);
+       vprintf (format, ap);
+       printf ("\n");
+       fflush (stdout);
+} /* void error_cb */
+
+static cmd_options_t default_host_opts = {
+       /* identifier_default_host = */ "dummy-host",
+};
+
+static struct {
+       char *input;
+       cmd_options_t *opts;
+       cmd_status_t expected_status;
+       cmd_type_t expected_type;
+} parse_data[] = {
+       /* Valid FLUSH commands. */
+       {
+               "FLUSH",
+               NULL,
+               CMD_OK,
+               CMD_FLUSH,
+       },
+       {
+               "FLUSH identifier=myhost/magic/MAGIC",
+               NULL,
+               CMD_OK,
+               CMD_FLUSH,
+       },
+       {
+               "FLUSH identifier=magic/MAGIC",
+               &default_host_opts,
+               CMD_OK,
+               CMD_FLUSH,
+       },
+       {
+               "FLUSH timeout=123 plugin=\"A\"",
+               NULL,
+               CMD_OK,
+               CMD_FLUSH,
+       },
+       /* Invalid FLUSH commands. */
+       {
+               /* Missing hostname; no default. */
+               "FLUSH identifier=magic/MAGIC",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               /* Missing 'identifier' key. */
+               "FLUSH myhost/magic/MAGIC",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               /* Invalid timeout. */
+               "FLUSH timeout=A",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               /* Invalid identifier. */
+               "FLUSH identifier=invalid",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               /* Invalid option. */
+               "FLUSH invalid=option",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+
+       /* Valid GETVAL commands. */
+       {
+               "GETVAL myhost/magic/MAGIC",
+               NULL,
+               CMD_OK,
+               CMD_GETVAL,
+       },
+       {
+               "GETVAL magic/MAGIC",
+               &default_host_opts,
+               CMD_OK,
+               CMD_GETVAL,
+       },
+
+       /* Invalid GETVAL commands. */
+       {
+               "GETVAL magic/MAGIC",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "GETVAL",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "GETVAL invalid",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+
+       /* Valid LISTVAL commands. */
+       {
+               "LISTVAL",
+               NULL,
+               CMD_OK,
+               CMD_LISTVAL,
+       },
+
+       /* Invalid LISTVAL commands. */
+       {
+               "LISTVAL invalid",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+
+       /* Valid PUTVAL commands. */
+       {
+               "PUTVAL magic/MAGIC N:42",
+               &default_host_opts,
+               CMD_OK,
+               CMD_PUTVAL,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC N:42",
+               NULL,
+               CMD_OK,
+               CMD_PUTVAL,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC 1234:42",
+               NULL,
+               CMD_OK,
+               CMD_PUTVAL,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC 1234:42 2345:23",
+               NULL,
+               CMD_OK,
+               CMD_PUTVAL,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC interval=2 1234:42",
+               NULL,
+               CMD_OK,
+               CMD_PUTVAL,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC interval=2 1234:42 interval=5 2345:23",
+               NULL,
+               CMD_OK,
+               CMD_PUTVAL,
+       },
+
+       /* Invalid PUTVAL commands. */
+       {
+               "PUTVAL magic/MAGIC N:42",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "PUTVAL",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "PUTVAL invalid N:42",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC A:42",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC 1234:A",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "PUTVAL myhost/magic/MAGIC",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "PUTVAL 1234:A",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       {
+               "PUTVAL myhost/magic/UNKNOWN 1234:42",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       /*
+        * As of collectd 5.x, PUTVAL accepts invalid options.
+       {
+               "PUTVAL myhost/magic/MAGIC invalid=2 1234:42",
+               NULL,
+               CMD_PARSE_ERROR,
+               CMD_UNKNOWN,
+       },
+       */
+
+       /* Invalid commands. */
+       {
+               "INVALID",
+               NULL,
+               CMD_UNKNOWN_COMMAND,
+               CMD_UNKNOWN,
+       },
+       {
+               "INVALID interval=2",
+               NULL,
+               CMD_UNKNOWN_COMMAND,
+               CMD_UNKNOWN,
+       },
+};
+
+DEF_TEST(parse)
+{
+       cmd_error_handler_t err = { error_cb, NULL };
+       int test_result = 0;
+
+       for (size_t i = 0; i < STATIC_ARRAY_SIZE (parse_data); i++) {
+               char *input = strdup (parse_data[i].input);
+
+               char description[1024];
+               cmd_status_t status;
+               cmd_t cmd;
+
+               _Bool result;
+
+               memset (&cmd, 0, sizeof (cmd));
+
+               status = cmd_parse (input, &cmd, parse_data[i].opts, &err);
+               snprintf (description, sizeof (description),
+                               "cmd_parse (\"%s\", opts=%p) = %d (type=%d [%s]); want %d (type=%d [%s])",
+                               parse_data[i].input, parse_data[i].opts, status,
+                               cmd.type, CMD_TO_STRING (cmd.type),
+                               parse_data[i].expected_status,
+                               parse_data[i].expected_type,
+                               CMD_TO_STRING (parse_data[i].expected_type));
+               result = (status == parse_data[i].expected_status)
+                               && (cmd.type == parse_data[i].expected_type);
+               LOG (result, description);
+
+               /* Run all tests before failing. */
+               if (! result)
+                       test_result = -1;
+
+               cmd_destroy (&cmd);
+               free (input);
+       }
+
+       return (test_result);
+}
+
+int main (int argc, char **argv)
+{
+       RUN_TEST(parse);
+       END_TEST;
+}
index e523420415a78521210f3fc3f932aa6e76cfaaf4..0af586ffa2a29816d75829364e695bb6d61e6408 100644 (file)
@@ -150,18 +150,29 @@ static int gr_format_name (char *ret, int ret_len,
         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,
-            (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-',
-            n_type_instance);
+    {
+        if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(n_plugin, n_type) == 0)
+            sstrncpy (tmp_type, n_type_instance, sizeof (tmp_type));
+        else
+            ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
+                n_type,
+                (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-',
+                n_type_instance);
+    }
     else
         sstrncpy (tmp_type, n_type, sizeof (tmp_type));
 
     /* Assert always_append_ds -> ds_name */
     assert (!(flags & GRAPHITE_ALWAYS_APPEND_DS) || (ds_name != NULL));
     if (ds_name != NULL)
-        ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
-            prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
+    {
+        if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(tmp_plugin, tmp_type) == 0)
+            ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
+                prefix, n_host, postfix, tmp_plugin, ds_name);
+        else
+            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);
index 60576dacb913d363947e40f1111d7cd701c33e13..5165f9e65f113fb5c8c64703afffcd6f8940eec5 100644 (file)
@@ -29,6 +29,7 @@
 #define GRAPHITE_STORE_RATES        0x01
 #define GRAPHITE_SEPARATE_INSTANCES 0x02
 #define GRAPHITE_ALWAYS_APPEND_DS   0x04
+#define GRAPHITE_DROP_DUPE_FIELDS   0x08
 
 int format_graphite (char *buffer,
     size_t buffer_size, const data_set_t *ds,
index 2ca9ddf8e551bd43691dd9b3f4b5d0f3c54188b9..226ba0ba39f44d79af6bd279fef778fddb8c41ab 100644 (file)
@@ -85,7 +85,7 @@ typedef struct user_obj_s user_obj_t;
 struct user_obj_s
 {
   void *user_obj;
-  identifier_t ident;
+  lookup_identifier_t ident;
 
   user_obj_t *next;
 };
@@ -175,7 +175,7 @@ static int lu_copy_ident_to_match_part (part_match_t *match_part, /* {{{ */
 } /* }}} int lu_copy_ident_to_match_part */
 
 static int lu_copy_ident_to_match (identifier_match_t *match, /* {{{ */
-    identifier_t const *ident, unsigned int group_by)
+    lookup_identifier_t const *ident, unsigned int group_by)
 {
   memset (match, 0, sizeof (*match));
 
@@ -609,7 +609,7 @@ void lookup_destroy (lookup_t *obj) /* {{{ */
 } /* }}} void lookup_destroy */
 
 int lookup_add (lookup_t *obj, /* {{{ */
-    identifier_t const *ident, unsigned int group_by, void *user_class)
+    lookup_identifier_t const *ident, unsigned int group_by, void *user_class)
 {
   by_type_entry_t *by_type = NULL;
   user_class_list_t *user_class_obj;
index 1d01ebdf2978a32b924e21fe844c6cc87793c37e..e46e7637780ad72f75c59bb8b82bc9c045517066 100644 (file)
@@ -53,7 +53,7 @@ typedef void (*lookup_free_class_callback_t) (void *user_class);
  * freed. */
 typedef void (*lookup_free_obj_callback_t) (void *user_obj);
 
-struct identifier_s
+struct lookup_identifier_s
 {
   char host[DATA_MAX_NAME_LEN];
   char plugin[DATA_MAX_NAME_LEN];
@@ -61,7 +61,7 @@ struct identifier_s
   char type[DATA_MAX_NAME_LEN];
   char type_instance[DATA_MAX_NAME_LEN];
 };
-typedef struct identifier_s identifier_t;
+typedef struct lookup_identifier_s lookup_identifier_t;
 
 #define LU_GROUP_BY_HOST            0x01
 #define LU_GROUP_BY_PLUGIN          0x02
@@ -80,7 +80,7 @@ lookup_t *lookup_create (lookup_class_callback_t,
 void lookup_destroy (lookup_t *obj);
 
 int lookup_add (lookup_t *obj,
-    identifier_t const *ident, unsigned int group_by, void *user_class);
+    lookup_identifier_t const *ident, unsigned int group_by, void *user_class);
 
 /* TODO(octo): Pass lookup_obj_callback_t to lookup_search()? */
 int lookup_search (lookup_t *obj,
index 44660638c4234b79a85e77566f338b7383f33bcd..b5a8e61a6f14514da2191a8382409c47d0907004 100644 (file)
@@ -32,8 +32,8 @@
 static _Bool expect_new_obj = 0;
 static _Bool have_new_obj = 0;
 
-static identifier_t last_class_ident;
-static identifier_t last_obj_ident;
+static lookup_identifier_t last_class_ident;
+static lookup_identifier_t last_obj_ident;
 
 static data_source_t dsrc_test = { "value", DS_TYPE_DERIVE, 0.0, NAN };
 static data_set_t const ds_test = { "test", 1, &dsrc_test };
@@ -45,8 +45,8 @@ static int lookup_obj_callback (data_set_t const *ds,
     value_list_t const *vl,
     void *user_class, void *user_obj)
 {
-  identifier_t *class = user_class;
-  identifier_t *obj = user_obj;
+  lookup_identifier_t *class = user_class;
+  lookup_identifier_t *obj = user_obj;
 
   OK1(expect_new_obj == have_new_obj,
       (expect_new_obj ? "New obj is created." : "Updating existing obj."));
@@ -63,8 +63,8 @@ static int lookup_obj_callback (data_set_t const *ds,
 static void *lookup_class_callback (data_set_t const *ds,
     value_list_t const *vl, void *user_class)
 {
-  identifier_t *class = user_class;
-  identifier_t *obj;
+  lookup_identifier_t *class = user_class;
+  lookup_identifier_t *obj;
 
   assert (expect_new_obj);
 
@@ -88,7 +88,7 @@ static int checked_lookup_add (lookup_t *obj, /* {{{ */
     char const *type, char const *type_instance,
     unsigned int group_by)
 {
-  identifier_t ident;
+  lookup_identifier_t ident;
   void *user_class;
 
   strncpy (ident.host, host, sizeof (ident.host));
@@ -111,7 +111,7 @@ static int checked_lookup_search (lookup_t *obj,
     _Bool expect_new)
 {
   int status;
-  value_list_t vl = VALUE_LIST_STATIC;
+  value_list_t vl = VALUE_LIST_INIT;
   data_set_t const *ds = &ds_unknown;
 
   strncpy (vl.host, host, sizeof (vl.host));
index 28ea6772b7bb71a2549143f81fa886f8fe9f6b83..7a238173b99626f076db9f92b7626daec5958d4f 100644 (file)
@@ -3,6 +3,6 @@
    Memcheck:Addr4
    fun:parse_value
    fun:parse_values
-   fun:test_parse_values
+   ...
    fun:main
 }
index 6cc092c0041eac9fcb028e179610f1c4cf40606e..e1464dc40cccf155bb2e38514d779feed7dc522e 100644 (file)
@@ -94,13 +94,10 @@ static int varnish_submit (const char *plugin_instance, /* {{{ */
        vl.values = &value;
        vl.values_len = 1;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-
        sstrncpy (vl.plugin, "varnish", sizeof (vl.plugin));
 
        if (plugin_instance == NULL)
                plugin_instance = "default";
-
        ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
                "%s-%s", plugin_instance, category);
 
@@ -117,22 +114,16 @@ static int varnish_submit_gauge (const char *plugin_instance, /* {{{ */
                const char *category, const char *type, const char *type_instance,
                uint64_t gauge_value)
 {
-       value_t value;
-
-       value.gauge = (gauge_t) gauge_value;
-
-       return (varnish_submit (plugin_instance, category, type, type_instance, value));
+       return (varnish_submit (plugin_instance, category, type, type_instance,
+                               (value_t) { .gauge = (gauge_t) gauge_value }));
 } /* }}} int varnish_submit_gauge */
 
 static int varnish_submit_derive (const char *plugin_instance, /* {{{ */
                const char *category, const char *type, const char *type_instance,
                uint64_t derive_value)
 {
-       value_t value;
-
-       value.derive = (derive_t) derive_value;
-
-       return (varnish_submit (plugin_instance, category, type, type_instance, value));
+       return (varnish_submit (plugin_instance, category, type, type_instance,
+                               (value_t) { .derive = (derive_t) derive_value }));
 } /* }}} int varnish_submit_derive */
 
 #if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
@@ -951,16 +942,14 @@ static int varnish_init (void) /* {{{ */
 
        varnish_config_apply_default (conf);
 
-       user_data_t ud = {
-               .data = conf,
-               .free_func = varnish_config_free
-       };
-
        plugin_register_complex_read (/* group = */ "varnish",
                        /* name      = */ "varnish/localhost",
                        /* callback  = */ varnish_read,
                        /* interval  = */ 0,
-                       /* user data = */ &ud);
+                       &(user_data_t) {
+                               .data = conf,
+                               .free_func = varnish_config_free,
+                       });
 
        return (0);
 } /* }}} int varnish_init */
@@ -968,7 +957,6 @@ static int varnish_init (void) /* {{{ */
 static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */
 {
        user_config_t *conf;
-       user_data_t ud;
        char callback_name[DATA_MAX_NAME_LEN];
 
        conf = calloc (1, sizeof (*conf));
@@ -1132,14 +1120,14 @@ static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */
        ssnprintf (callback_name, sizeof (callback_name), "varnish/%s",
                        (conf->instance == NULL) ? "localhost" : conf->instance);
 
-       ud.data = conf;
-       ud.free_func = varnish_config_free;
-
        plugin_register_complex_read (/* group = */ "varnish",
                        /* name      = */ callback_name,
                        /* callback  = */ varnish_read,
                        /* interval  = */ 0,
-                       /* user data = */ &ud);
+                       &(user_data_t) {
+                               .data = conf,
+                               .free_func = varnish_config_free,
+                       });
 
        have_instance = 1;
 
index c1c77bcf135e18ed7e0feff620868915b2a89614..99fe42db3918301e5cfce4de5a1117a76cfe26e1 100644 (file)
@@ -223,103 +223,71 @@ init_value_list (value_list_t *vl, virDomainPtr dom)
 
 } /* void init_value_list */
 
-static void
-memory_submit (gauge_t memory, virDomainPtr dom)
+static void submit (virDomainPtr dom,
+                    char const *type, char const *type_instance,
+                    value_t *values, size_t values_len)
 {
-    value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
-
     init_value_list (&vl, dom);
 
-    values[0].gauge = memory;
-
     vl.values = values;
-    vl.values_len = 1;
+    vl.values_len = values_len;
 
-    sstrncpy (vl.type, "memory", sizeof (vl.type));
-    sstrncpy (vl.type_instance, "total", sizeof (vl.type_instance));
+    sstrncpy (vl.type, type, sizeof (vl.type));
+    if (type_instance != NULL)
+        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
 
     plugin_dispatch_values (&vl);
 }
 
 static void
-memory_stats_submit (gauge_t memory, virDomainPtr dom, int tag_index)
+memory_submit (gauge_t value, virDomainPtr dom)
+{
+    submit (dom, "memory", "total", &(value_t) { .gauge = value }, 1);
+}
+
+static void
+memory_stats_submit (gauge_t value, virDomainPtr dom, int tag_index)
 {
     static const char *tags[] = { "swap_in", "swap_out", "major_fault", "minor_fault",
                                     "unused", "available", "actual_balloon", "rss"};
 
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, dom);
-
-    values[0].gauge = memory;
-
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, "memory", sizeof (vl.type));
-    sstrncpy (vl.type_instance, tags[tag_index], sizeof (vl.type_instance));
+    if ((tag_index < 0) || (tag_index >= STATIC_ARRAY_SIZE (tags))) {
+        ERROR ("virt plugin: Array index out of bounds: tag_index = %d", tag_index);
+        return;
+    }
 
-    plugin_dispatch_values (&vl);
+    submit (dom, "memory", tags[tag_index], &(value_t) { .gauge = value }, 1);
 }
 
 static void
-cpu_submit (unsigned long long cpu_time,
+cpu_submit (unsigned long long value,
             virDomainPtr dom, const char *type)
 {
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, dom);
-
-    values[0].derive = cpu_time;
-
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-
-    plugin_dispatch_values (&vl);
+    submit (dom, type, NULL, &(value_t) { .derive = (derive_t) value }, 1);
 }
 
 static void
-vcpu_submit (derive_t cpu_time,
+vcpu_submit (derive_t value,
              virDomainPtr dom, int vcpu_nr, const char *type)
 {
-    value_t values[1];
-    value_list_t vl = VALUE_LIST_INIT;
+    char type_instance[DATA_MAX_NAME_LEN];
 
-    init_value_list (&vl, dom);
+    ssnprintf (type_instance, sizeof (type_instance), "%d", vcpu_nr);
 
-    values[0].derive = cpu_time;
-    vl.values = values;
-    vl.values_len = 1;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-    ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
-
-    plugin_dispatch_values (&vl);
+    submit (dom, type, type_instance, &(value_t) { .derive = value }, 1);
 }
 
 static void
 submit_derive2 (const char *type, derive_t v0, derive_t v1,
              virDomainPtr dom, const char *devname)
 {
-    value_t values[2];
-    value_list_t vl = VALUE_LIST_INIT;
-
-    init_value_list (&vl, dom);
+    value_t values[] = {
+        { .derive = v0 },
+        { .derive = v1 },
+    };
 
-    values[0].derive = v0;
-    values[1].derive = v1;
-    vl.values = values;
-    vl.values_len = 2;
-
-    sstrncpy (vl.type, type, sizeof (vl.type));
-    sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
-
-    plugin_dispatch_values (&vl);
+    submit (dom, type, devname, values, STATIC_ARRAY_SIZE (values));
 } /* void submit_derive2 */
 
 static int
index 46ffa13b1108582b3de120decc22180cf569c2d3..98c4c2a0592f7c75bcfaf61330ee6f24e95f0ea7 100644 (file)
@@ -51,7 +51,6 @@ static void submit (const char *plugin_instance, const char *type,
   vl.values = values;
   vl.values_len = values_len;
 
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
   sstrncpy (vl.plugin, "vmem", sizeof (vl.plugin));
   if (plugin_instance != NULL)
     sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
@@ -65,12 +64,13 @@ static void submit (const char *plugin_instance, const char *type,
 static void submit_two (const char *plugin_instance, const char *type,
     const char *type_instance, derive_t c0, derive_t c1)
 {
-  value_t values[2];
+  value_t values[] = {
+    { .derive = c0 },
+    { .derive = c1 },
+  };
 
-  values[0].derive = c0;
-  values[1].derive = c1;
-
-  submit (plugin_instance, type, type_instance, values, 2);
+  submit (plugin_instance, type, type_instance,
+      values, STATIC_ARRAY_SIZE (values));
 } /* void submit_one */
 
 static void submit_one (const char *plugin_instance, const char *type,
index 806fd921a7fca07dd531a91d0819c3c9d2126505..0e58a9710c7800e974b2c415ec886c216f232235 100644 (file)
@@ -56,15 +56,14 @@ static int vserver_init (void)
 static void traffic_submit (const char *plugin_instance,
                const char *type_instance, derive_t rx, derive_t tx)
 {
-       value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].derive = rx;
-       values[1].derive = tx;
+       value_t values[] = {
+               { .derive = rx },
+               { .derive = tx },
+       };
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, "if_octets", sizeof (vl.type));
@@ -76,16 +75,15 @@ static void traffic_submit (const char *plugin_instance,
 static void load_submit (const char *plugin_instance,
                gauge_t snum, gauge_t mnum, gauge_t lnum)
 {
-       value_t values[3];
        value_list_t vl = VALUE_LIST_INIT;
-
-       values[0].gauge = snum;
-       values[1].gauge = mnum;
-       values[2].gauge = lnum;
+       value_t values[] = {
+               { .gauge = snum },
+               { .gauge = mnum },
+               { .gauge = lnum },
+       };
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, "load", sizeof (vl.type));
@@ -97,14 +95,10 @@ static void submit_gauge (const char *plugin_instance, const char *type,
                const char *type_instance, gauge_t value)
 
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
-       vl.values_len = STATIC_ARRAY_SIZE (values);
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       vl.values = &(value_t) { .gauge = value };
+       vl.values_len = 1;
        sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
index b998462598fd764c1214ebf5c7d07a7fae81a44d..16aad50f48db267d5aa33adc6b664686efc8c0c1 100644 (file)
@@ -54,14 +54,10 @@ static double wireless_dbm_to_watt (double dbm)
 static void wireless_submit (const char *plugin_instance, const char *type,
                double value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "wireless", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance,
                        sizeof (vl.plugin_instance));
index 787445d50678227c96e39013e03a47269a94ecb3..ad8dfcef487a2e512e4c2e539c8698625c17a105 100644 (file)
@@ -566,6 +566,9 @@ static int wg_config_node (oconfig_item_t *ci)
         else if (strcasecmp ("AlwaysAppendDS", child->key) == 0)
             cf_util_get_flag (child, &cb->format_flags,
                     GRAPHITE_ALWAYS_APPEND_DS);
+        else if (strcasecmp ("DropDuplicateFields", child->key) == 0)
+            cf_util_get_flag (child, &cb->format_flags,
+                    GRAPHITE_DROP_DUPE_FIELDS);
         else if (strcasecmp ("EscapeCharacter", child->key) == 0)
             config_set_char (&cb->escape_char, child);
         else
@@ -593,15 +596,13 @@ static int wg_config_node (oconfig_item_t *ci)
         ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
                 cb->name);
 
-    user_data_t ud = {
-        .data = cb,
-        .free_func = wg_callback_free
-    };
-
-    plugin_register_write (callback_name, wg_write, &ud);
+    plugin_register_write (callback_name, wg_write,
+            &(user_data_t) {
+                .data = cb,
+                .free_func = wg_callback_free,
+            });
 
-    ud.free_func = NULL;
-    plugin_register_flush (callback_name, wg_flush, &ud);
+    plugin_register_flush (callback_name, wg_flush, &(user_data_t) { .data = cb });
 
     return (0);
 }
index f8cc4e8df5627a946e0e431087a55b6f7dae5495..b3baa555d2393fb7f3d48903afb5cdd4528a7c5b 100644 (file)
@@ -419,6 +419,9 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
         }
         assert (command_len < cb->send_buffer_free);
 
+        /* Make scan-build happy. */
+        assert (cb->send_buffer != NULL);
+
         /* `command_len + 1' because `command_len' does not include the
          * trailing null byte. Neither does `send_buffer_fill'. */
         memcpy (cb->send_buffer + cb->send_buffer_fill,
index 9fda2dfc13a416989afeb1de71b2ad6dcb84a99d..4b42231064f0beb254b598f2d797db94e0d5370c 100644 (file)
@@ -172,9 +172,9 @@ static int kafka_write(const data_set_t *ds, /* {{{ */
 
     switch (ctx->format) {
     case KAFKA_FORMAT_COMMAND:
-        status = create_putval(buffer, sizeof(buffer), ds, vl);
+        status = cmd_create_putval(buffer, sizeof(buffer), ds, vl);
         if (status != 0) {
-            ERROR("write_kafka plugin: create_putval failed with status %i.",
+            ERROR("write_kafka plugin: cmd_create_putval failed with status %i.",
                   status);
             return status;
         }
@@ -383,12 +383,11 @@ static void kafka_config_topic(rd_kafka_conf_t *conf, oconfig_item_t *ci) /* {{{
     ssnprintf(callback_name, sizeof(callback_name),
               "write_kafka/%s", tctx->topic_name);
 
-    user_data_t ud = {
-        .data = tctx,
-        .free_func = kafka_topic_context_free
-    };
-
-    status = plugin_register_write (callback_name, kafka_write, &ud);
+    status = plugin_register_write (callback_name, kafka_write,
+            &(user_data_t) {
+                .data = tctx,
+                .free_func = kafka_topic_context_free,
+            });
     if (status != 0) {
         WARNING ("write_kafka plugin: plugin_register_write (\"%s\") "
                 "failed with status %i.",
index b0dc6f11cca43072ed7a094ba6ef3c2f2e6ac794..e10a912e5bc09b612e5adbb8d0f7ba331afacbac 100644 (file)
 #include "plugin.h"
 
 #include "utils_format_graphite.h"
+#include "utils_format_json.h"
 
 #include <netdb.h>
 
-#define WL_BUF_SIZE 8192
+#define WL_BUF_SIZE 16384
 
-static int wl_write_messages (const data_set_t *ds, const value_list_t *vl)
+#define WL_FORMAT_GRAPHITE 1
+#define WL_FORMAT_JSON 2
+
+/* Plugin:WriteLog has to also operate without a config, so use a global. */
+int wl_format = WL_FORMAT_GRAPHITE;
+
+static int wl_write_graphite (const data_set_t *ds, const value_list_t *vl)
 {
     char buffer[WL_BUF_SIZE] = { 0 };
     int status;
 
     if (0 != strcmp (ds->type, vl->type))
     {
-        ERROR ("write_log plugin: DS type does not match "
-                "value list type");
+        ERROR ("write_log plugin: DS type does not match value list type");
         return -1;
     }
 
@@ -56,20 +62,95 @@ static int wl_write_messages (const data_set_t *ds, const value_list_t *vl)
     INFO ("write_log values:\n%s", buffer);
 
     return (0);
-} /* int wl_write_messages */
+} /* int wl_write_graphite */
+
+static int wl_write_json (const data_set_t *ds, const value_list_t *vl)
+{
+    char buffer[WL_BUF_SIZE] = { 0 };
+    size_t bfree = sizeof(buffer);
+    size_t bfill = 0;
+
+    if (0 != strcmp (ds->type, vl->type))
+    {
+        ERROR ("write_log plugin: DS type does not match value list type");
+        return -1;
+    }
+
+    format_json_initialize(buffer, &bfill, &bfree);
+    format_json_value_list(buffer, &bfill, &bfree, ds, vl,
+                           /* store rates = */ 0);
+    format_json_finalize(buffer, &bfill, &bfree);
+
+    INFO ("write_log values:\n%s", buffer);
+
+    return (0);
+} /* int wl_write_json */
 
 static int wl_write (const data_set_t *ds, const value_list_t *vl,
         __attribute__ ((unused)) user_data_t *user_data)
 {
-    int status;
+    int status = 0;
 
-    status = wl_write_messages (ds, vl);
+    if (wl_format == WL_FORMAT_GRAPHITE)
+    {
+        status = wl_write_graphite (ds, vl);
+    }
+    else if (wl_format == WL_FORMAT_JSON)
+    {
+        status = wl_write_json (ds, vl);
+    }
 
     return (status);
 }
 
+static int wl_config (oconfig_item_t *ci) /* {{{ */
+{
+    _Bool format_seen = 0;
+
+    for (int i = 0; i < ci->children_num; i++)
+    {
+        oconfig_item_t *child = ci->children + i;
+
+        if (strcasecmp ("Format", child->key) == 0)
+        {
+            char str[16];
+
+            if (cf_util_get_string_buffer (child, str, sizeof (str)) != 0)
+                continue;
+
+            if (format_seen)
+            {
+                WARNING ("write_log plugin: Redefining option `%s'.",
+                    child->key);
+            }
+            format_seen = 1;
+
+            if (strcasecmp ("Graphite", str) == 0)
+                wl_format = WL_FORMAT_GRAPHITE;
+            else if (strcasecmp ("JSON", str) == 0)
+                wl_format = WL_FORMAT_JSON;
+            else
+            {
+                ERROR ("write_log plugin: Unknown format `%s' for option `%s'.",
+                    str, child->key);
+                return (-EINVAL);
+            }
+        }
+        else
+        {
+            ERROR ("write_log plugin: Invalid configuration option: `%s'.",
+                child->key);
+            return (-EINVAL);
+        }
+    }
+
+    return (0);
+} /* }}} int wl_config */
+
 void module_register (void)
 {
+    plugin_register_complex_config ("write_log", wl_config);
+    /* If config is supplied, the global wl_format will be set. */
     plugin_register_write ("write_log", wl_write, NULL);
 }
 
index 6d5f37943ea330c369fc6f871777aa8f7887e6e3..796574e749538701364d6e3e2b55420f578c91f6 100644 (file)
@@ -339,12 +339,11 @@ static int wm_config_node (oconfig_item_t *ci) /* {{{ */
 
     ssnprintf (cb_name, sizeof (cb_name), "write_mongodb/%s", node->name);
 
-    user_data_t ud = {
-      .data = node,
-      .free_func = wm_config_free
-    };
-
-    status = plugin_register_write (cb_name, wm_write, &ud);
+    status = plugin_register_write (cb_name, wm_write,
+                   &(user_data_t) {
+                           .data = node,
+                           .free_func = wm_config_free,
+                   });
     INFO ("write_mongodb plugin: registered write plugin %s %d",cb_name,status);
   }
 
index c16537c25f91d96763a757535cb1279bc5f7cade..bafbfe511930fc30e70ff513019e9cb0c4dc8f95 100644 (file)
@@ -234,12 +234,11 @@ static int wr_config_node (oconfig_item_t *ci) /* {{{ */
 
     ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name);
 
-    user_data_t ud = {
-      .data = node,
-      .free_func = wr_config_free
-    };
-
-    status = plugin_register_write (cb_name, wr_write, &ud);
+    status = plugin_register_write (cb_name, wr_write,
+        &(user_data_t) {
+          .data = node,
+          .free_func = wr_config_free,
+        });
   }
 
   if (status != 0)
index f1cd938810ac80b1640004ff98916e349a4b8229..de375d2682a1eb0e281b4d5a711a0f6073139d0b 100644 (file)
@@ -108,17 +108,13 @@ static int xencpu_shutdown (void)
     return 0;
 } /* static int xencpu_shutdown */
 
-static void submit_value (int cpu_num, gauge_t percent)
+static void submit_value (int cpu_num, gauge_t value)
 {
-    value_t values[1];
     value_list_t vl = VALUE_LIST_INIT;
 
-    values[0].gauge = percent;
-
-    vl.values = values;
+    vl.values = &(value_t) { .gauge = value };
     vl.values_len = 1;
 
-    sstrncpy (vl.host, hostname_g, sizeof (vl.host));
     sstrncpy (vl.plugin, "xencpu", sizeof (vl.plugin));
     sstrncpy (vl.type, "percent", sizeof (vl.type));
     sstrncpy (vl.type_instance, "load", sizeof (vl.type_instance));
@@ -145,9 +141,10 @@ static int xencpu_read (void)
     int status;
     for (int cpu = 0; cpu < nr_cpus; cpu++) {
         gauge_t rate = NAN;
-        value_t value = {.derive = cpu_info[cpu].idletime};
 
-        status = value_to_rate (&rate, value, DS_TYPE_DERIVE, now, &cpu_states[cpu]);
+        status = value_to_rate (&rate,
+                                (value_t) { .derive = cpu_info[cpu].idletime }, DS_TYPE_DERIVE,
+                                now, &cpu_states[cpu]);
         if (status == 0) {
             submit_value(cpu, 100 - rate/10000000);
         }
index 353599502fe5f53f3193fbc59ccac2a38ef8f24a..5a2774bb033470b79c775266ba4c46114ae7c0dd 100644 (file)
@@ -35,14 +35,10 @@ static gint xmms_session;
 
 static void cxmms_submit (const char *type, gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = value;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "xmms", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
 
index 8261282a825e1fc5ea13dea2bfacf222a35b4037..ad287bb107eed0e9e50b2974e95349a779f9d9b2 100644 (file)
@@ -138,14 +138,13 @@ static long long get_zfs_value(kstat_t *dummy __attribute__((unused)),
 }
 #endif
 
-static void za_submit (const char* type, const char* type_instance, value_t* values, int values_len)
+static void za_submit (const char* type, const char* type_instance, value_t* values, size_t values_len)
 {
        value_list_t vl = VALUE_LIST_INIT;
 
        vl.values = values;
        vl.values_len = values_len;
 
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "zfs_arc", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
@@ -155,45 +154,34 @@ static void za_submit (const char* type, const char* type_instance, value_t* val
 
 static void za_submit_gauge (const char* type, const char* type_instance, gauge_t value)
 {
-       value_t vv;
-
-       vv.gauge = value;
-       za_submit (type, type_instance, &vv, 1);
+       za_submit (type, type_instance, &(value_t) { .gauge = value }, 1);
 }
 
 static int za_read_derive (kstat_t *ksp, const char *kstat_value,
     const char *type, const char *type_instance)
 {
-  long long tmp;
-  value_t v;
-
-  tmp = get_zfs_value (ksp, (char *)kstat_value);
+  long long tmp = get_zfs_value (ksp, (char *)kstat_value);
   if (tmp == -1LL)
   {
     WARNING ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
     return (-1);
   }
 
-  v.derive = (derive_t) tmp;
-  za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
+  za_submit (type, type_instance, &(value_t) { .derive = (derive_t) tmp }, /* values_num = */ 1);
   return (0);
 }
 
 static int za_read_gauge (kstat_t *ksp, const char *kstat_value,
     const char *type, const char *type_instance)
 {
-  long long tmp;
-  value_t v;
-
-  tmp = get_zfs_value (ksp, (char *)kstat_value);
+  long long tmp = get_zfs_value (ksp, (char *)kstat_value);
   if (tmp == -1LL)
   {
     WARNING ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
     return (-1);
   }
 
-  v.gauge = (gauge_t) tmp;
-  za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
+  za_submit (type, type_instance, &(value_t) { .gauge = (gauge_t) tmp }, /* values_num = */ 1);
   return (0);
 }
 
@@ -215,7 +203,6 @@ static void za_submit_ratio (const char* type_instance, gauge_t hits, gauge_t mi
 static int za_read (void)
 {
        gauge_t  arc_hits, arc_misses, l2_hits, l2_misses;
-       value_t  l2_io[2];
        kstat_t  *ksp   = NULL;
 
 #if defined(KERNEL_LINUX)
@@ -331,10 +318,11 @@ static int za_read (void)
        za_submit_ratio ("L2", l2_hits, l2_misses);
 
        /* I/O */
-       l2_io[0].derive = get_zfs_value(ksp, "l2_read_bytes");
-       l2_io[1].derive = get_zfs_value(ksp, "l2_write_bytes");
-
-       za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
+       value_t  l2_io[] = {
+               { .derive = (derive_t) get_zfs_value(ksp, "l2_read_bytes") },
+               { .derive = (derive_t) get_zfs_value(ksp, "l2_write_bytes") },
+       };
+       za_submit ("io_octets", "L2", l2_io, STATIC_ARRAY_SIZE (l2_io));
 
 #if defined(KERNEL_LINUX)
        free_zfs_values (ksp);
index d9e46f5ad1ea690ca022b2732c09a3918046f558..bd51c55ec8b53374f2454e2031e4c2e02dd4b4e1 100644 (file)
@@ -91,7 +91,6 @@ zone_submit_value(char *zone, gauge_t value)
 
        vl.values = values;
        vl.values_len = 1; /*STATIC_ARRAY_SIZE (values);*/
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "zone", sizeof (vl.plugin));
        sstrncpy (vl.type, "percent", sizeof (vl.type));
        sstrncpy (vl.type_instance, zone, sizeof (vl.type_instance));
index 84174853d24c62bd8ba22aaa17bc28e5f68aaa3d..539112e85d1e7120f7aa8be7585f53f9887100f3 100644 (file)
@@ -66,16 +66,12 @@ static int zookeeper_config(const char *key, const char *value)
        return 0;
 }
 
-static void zookeeper_submit_gauge (const char * type, const char * type_inst, gauge_t val)
+static void zookeeper_submit_gauge (const char * type, const char * type_inst, gauge_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].gauge = val;
-
-       vl.values = values;
+       vl.values = &(value_t) { .gauge = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "zookeeper", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_inst != NULL)
@@ -84,16 +80,12 @@ static void zookeeper_submit_gauge (const char * type, const char * type_inst, g
        plugin_dispatch_values (&vl);
 } /* zookeeper_submit_gauge */
 
-static void zookeeper_submit_derive (const char * type, const char * type_inst, derive_t val)
+static void zookeeper_submit_derive (const char * type, const char * type_inst, derive_t value)
 {
-       value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-       values[0].derive = val;
-
-       vl.values = values;
+       vl.values = &(value_t) { .derive = value };
        vl.values_len = 1;
-       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "zookeeper", sizeof (vl.plugin));
        sstrncpy (vl.type, type, sizeof (vl.type));
        if (type_inst != NULL)