- 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>
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
[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
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
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.
- 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.
- 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.
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).
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'.
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
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.
* 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
* 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)
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.
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
-------------------------------
The `build.sh' script takes no arguments.
+
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
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.
+++ /dev/null
-* 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/
my $type = shift;
my %plugins;
- my $interval;
our $cb_name = undef;
}
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;
}
%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;
}
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. "
}
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.");
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};
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"
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=""
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"
plugin_entropy="yes"
plugin_fhcount="yes"
plugin_fscache="yes"
+ plugin_hugepages="yes"
plugin_interface="yes"
plugin_ipc="yes"
plugin_irq="yes"
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])
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])
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])
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])
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])
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])
#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)));
} /* 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
/* 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. */
%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
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
%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
%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
%{?_with_disk} \
%{?_with_dns} \
%{?_with_drbd} \
+ %{?_with_dpdkstat} \
%{?_with_email} \
%{?_with_entropy} \
%{?_with_ethstat} \
%{?_with_gps} \
%{?_with_grpc} \
%{?_with_hddtemp} \
+ %{?_with_hugepages} \
+ %{?_with_intel_rdt} \
%{?_with_interface} \
%{?_with_ipc} \
%{?_with_ipmi} \
%if %{with_drbd}
%{_libdir}/%{name}/drbd.so
%endif
+%if %{with_dpdkstat}
+%{_libdir}/%{name}/dpdkstat.so
+%endif
%if %{with_ethstat}
%{_libdir}/%{name}/ethstat.so
%endif
%if %{with_fscache}
%{_libdir}/%{name}/fscache.so
%endif
+%if %{with_hugepages}
+%{_libdir}/%{name}/hugepages.so
+%endif
%if %{with_interface}
%{_libdir}/%{name}/interface.so
%endif
%{_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
%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
--- /dev/null
+# 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`.
--- /dev/null
+# 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`.
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 {
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
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
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
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
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
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);
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),
/* name = */ callback_name,
/* callback = */ apache_read_host,
/* interval = */ 0,
- /* user_data = */ &ud);
+ &(user_data_t) {
+ .data = st,
+ .free_func = apache_free,
+ });
+
}
if (status != 0)
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)
} /* 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)
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));
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));
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));
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)
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));
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));
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));
# 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));
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, ¤t, &voltage);
#endif
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 */
{
int status;
+ if (query_statefs)
+ return battery_read_statefs ();
+
DEBUG ("battery plugin: Trying sysfs ...");
status = read_sysfs ();
if (status == 0)
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\".",
--- /dev/null
+/**
+ * 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);
+}
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,
}
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));
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 */
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));
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)
{
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
=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)>,
#@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>
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>
=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
=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
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>
=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
=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>
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>
=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.
=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
=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
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)
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 */
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));
/* #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;
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],
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
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) /* {{{ */
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.
} /* }}} 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));
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);
#include "common.h"
#include "plugin.h"
-#define MODULE_NAME "cpufreq"
-
static int num_cpu = 0;
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);
#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));
} /* }}} 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));
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));
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));
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) */
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
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
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);
* something wrong.
*/
if (init_global_variables () != 0)
- return (1);
+ exit (EXIT_FAILURE);
if (test_config)
return (0);
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;
+ }
+
+ memcpy(ptr, sep, sep_len);
+
+ ptr += sep_len;
+ avail -= sep_len;
+ }
- assert (buffer[buffer_size - 1] == 0);
- return ((int) strlen (buffer));
+ 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)
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)
* 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'.
* 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);
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);
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);
}
#include "collectd.h"
+#include "common.h"
#include "plugin.h"
#include "meta_data.h"
+#define MD_MAX_NONSTRING_CHARS 128
+
/*
* Data types
*/
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 : */
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 : */
}
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);
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);
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)
{
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)
{
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; "
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);
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 */
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);
};
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
{
*
* 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
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));
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* */
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. */
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 : */
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 : */
}
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);
}
}
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);
}
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,
}
/* 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;
/* #endif HAVE_LIBKSTAT */
#elif defined(HAVE_LIBSTATGRAB)
-/* #endif HAVE_LIBKSTATGRAB */
+/* #endif HAVE_LIBSTATGRAB */
#elif HAVE_PERFSTAT
static perfstat_disk_t * stat_disk;
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));
#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));
#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));
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 ());
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));
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));
--- /dev/null
+/*-
+ * 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);
+}
}
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));
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));
#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));
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);
}
{
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;
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)
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",
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));
plugin_dispatch_values(&vl);
}
-
static int fhcount_read(void) {
int numfields = 0;
int buffer_len = 60;
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);
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));
*/
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));
/**
* 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"),
*
* Authors:
* Sebastian Harl <sh at tokkee.org>
+ * Florian octo Forster <octo at collectd.org>
**/
#include <grpc++/grpc++.h>
using collectd::Collectd;
-using collectd::DispatchValuesRequest;
-using collectd::DispatchValuesResponse;
+using collectd::PutValuesRequest;
+using collectd::PutValuesResponse;
using collectd::QueryValuesRequest;
using collectd::QueryValuesResponse;
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;
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. */
}
return 0;
- } /* int DispatchValues */
+ } /* int PutValues */
private:
std::unique_ptr<Collectd::Stub> stub_;
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)
* 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
* 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
# 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>
#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[] =
{
* 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;
(ai_return == EAI_SYSTEM)
? sstrerror (errno, errbuf, sizeof (errbuf))
: gai_strerror (ai_return));
- return (-1);
+ return (NULL);
}
fd = -1;
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];
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)
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));
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 */
--- /dev/null
+/*-
+ * 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);
+}
--- /dev/null
+/**
+ * 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);
+}
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));
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));
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;
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));
int rule_num)
{
int status;
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
/* Select the rules to collect */
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),
}
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,
int rule_num)
{
int status;
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
/* Select the rules to collect */
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),
}
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);
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));
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));
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));
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);
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);
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);
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);
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);
}
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];
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));
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));
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");
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");
*
* Authors:
* Chad Malfait <malfaitc at yahoo.com>
- * Benjamin Gilbert <bgilbert at cs.cmu.edu>
+ * Benjamin Gilbert <bgilbert at backtick.net>
**/
#include <lvm2app.h>
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));
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));
}
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,
#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>
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;
};
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);
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, /* {{{ */
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);
}
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);
}
}
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;
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
&& (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.");
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 */
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));
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);
} /* }}} 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));
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) */
struct memcached_s
{
char *name;
- char *socket;
char *host;
- char *port;
+ char *socket;
+ char *connhost;
+ char *connport;
};
typedef struct memcached_s memcached_t;
return;
sfree (st->name);
- sfree (st->socket);
sfree (st->host);
- sfree (st->port);
+ sfree (st->socket);
+ sfree (st->connhost);
+ sfree (st->connport);
sfree (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));
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)
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));
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)
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));
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 */
* <Plugin memcached>
* <Instance "instance_name">
* Host foo.zomg.com
+ * Address 1.2.3.4
* Port "1234"
* </Instance>
* </Plugin>
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++)
{
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.",
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)
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 ();
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));
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));
}
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));
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));
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)
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;
}
}
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;
}
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
{
}
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 */
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));
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
{
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 */
}
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)
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)
{
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);
/* 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);
}
if (val == 0ULL)
continue;
- counter_submit ("mysql_handler",
+ derive_submit ("mysql_handler",
key + strlen ("Handler_"),
val, db);
}
else if (strncmp (key, "Table_locks_",
strlen ("Table_locks_")) == 0)
{
- counter_submit ("mysql_locks",
+ derive_submit ("mysql_locks",
key + strlen ("Table_locks_"),
val, db);
}
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)
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)
/* 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;
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;
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));
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
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;
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,
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 */
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));
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));
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
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 */
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));
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)
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));
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));
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
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,
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;
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));
char *buffer;
size_t buffer_size;
int status;
+ char errbuf[1024];
char file[4096];
char *endptr;
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);
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++;
char *buffer;
size_t buffer_size;
int status;
+ char errbuf[1024];
char *buffer_ptr;
char *dummy;
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",
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);
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) */
static int cow_init (void)
{
int status;
+ char errbuf[1024];
if (device_g == NULL)
{
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);
}
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));
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) /* {{{ */
(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,
+ });
}
}
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)
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
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,
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,
*
* Authors:
* Sebastian Harl <sh at tokkee.org>
+ * Pavel Rochnyak <pavel2000 ngs.ru>
**/
/*
#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);
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
*/
* 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;
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 },
return 0;
}
- ret = call_pv (sub_name, G_SCALAR);
+ ret = call_pv (sub_name, G_SCALAR|G_EVAL);
t->running = old_running;
return ret;
/*
* 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;
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;
*
* 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 *);
XPUSHs (sv_2mortal (newRV_noinc ((SV *)pvl)));
}
else if (PLUGIN_LOG == type) {
+ subname = va_arg(ap, char *);
/*
* $_[0] = $level;
*
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] =
* {
* type_instance => $type_instance
* };
*/
- notification_t *n;
- HV *notif = newHV ();
-
n = va_arg (ap, notification_t *);
if (-1 == notification2hv (aTHX_ n, notif)) {
}
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;
va_end (ap);
return ret;
-} /* static int pplugin_call_all (int, ...) */
+} /* static int pplugin_call (int, ...) */
/*
* collectd's Perl interpreter based thread implementation.
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
}
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
* 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).
*
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;
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;
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);
} /* 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;
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);
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;
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;
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)
dTHX;
plugin_unregister_complex_config ("perl");
+ plugin_unregister_read_group ("perl");
if (NULL == perl_threads)
return 0;
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;
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) */
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, ®ister_legacy_flush);
else
{
log_warn ("Ignoring unknown config key \"%s\".", c->key);
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));
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);
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));
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;
}
/* <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;
if (i >= lookup_table_length)
{
INFO ("powerdns plugin: submit: Not found in lookup table: %s = %s;",
- pdns_type, value);
+ pdns_type, value_str);
return;
}
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)
/* 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));
/* 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));
#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));
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",
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));
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);
}
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);
}
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,
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);
{
cr_data_t *router_data;
char read_name[128];
- user_data_t user_data;
int status;
router_data = calloc (1, sizeof (*router_data));
}
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);
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);
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));
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;
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",
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));
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,
{
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. */
/* 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);
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));
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));
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.");
/* 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)
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);
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);
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);
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);
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);
{
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);
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);
}
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);
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 */
metric->value -= delta;
metric->counter += (derive_t) delta;
- values[0].derive = metric->counter;
+ vl.values[0].derive = metric->counter;
}
return (plugin_dispatch_values (&vl));
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,
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));
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));
{
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);
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));
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);
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));
{
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;
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;
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;
if (act->replacement == NULL)
{
ERROR ("tr_config_add_action: tr_strdup failed.");
- regfree (&act->re);
- sfree (act);
+ tr_action_destroy (act);
return (-ENOMEM);
}
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];
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;
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);
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++)
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 "
&& (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'.");
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);
#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
{
/* char *type; */
char *type_instance;
meta_data_t *meta;
+ ts_key_list_t *meta_delete;
};
typedef struct ts_data_s ts_data_t;
|| (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);
}
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;
/* free (data->type); */
free (data->type_instance);
meta_data_destroy(data->meta);
+ ts_key_list_free (data->meta_delete);
free (data);
return (0);
/* 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++)
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 "
&& (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;
}
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);
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 */
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)
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;
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);
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;
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);
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;
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)
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;
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);
memcpy (&new_vl, vl, sizeof (new_vl));
/* Reset data we can't simply copy */
- new_vl.values = new_values;
- new_vl.values_len = 2;
new_vl.meta = NULL;
/* Change the type/-instance to "io_octets-L2" */
sstrncpy (new_vl.type_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);
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);
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;
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);
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;
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);
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;
{
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));
}
/*
* 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)
/*
* 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)
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));
};
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,
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);
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;
}
}
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));
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));
{
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);
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
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
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
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));
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));
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);
#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,
_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));
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);
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
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 */
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));
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;
} /* 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
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));
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,
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));
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));
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));
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));
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
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);
}
}
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,
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.",
#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;
}
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);
}
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);
}
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)
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));
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);
}
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));
}
#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));
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);
}
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)
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);
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));
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)
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)