Merge branch 'collectd-5.6'
authorMarc Fournier <marc.fournier@camptocamp.com>
Mon, 10 Oct 2016 19:04:03 +0000 (21:04 +0200)
committerMarc Fournier <marc.fournier@camptocamp.com>
Mon, 10 Oct 2016 19:04:03 +0000 (21:04 +0200)
1  2 
contrib/redhat/collectd.spec
src/Makefile.am
src/collectd.conf.pod
src/daemon/common.c
src/lua.c
src/rrdcached.c
src/tail_csv.c
src/vserver.c
src/write_redis.c

@@@ -73,7 -73,6 +73,7 @@@
  %define with_gmond 0%{!?_without_gmond:1}
  %define with_gps 0%{!?_without_gps:1}
  %define with_hddtemp 0%{!?_without_hddtemp:1}
 +%define with_hugepages 0%{!?_without_hugepages:1}
  %define with_interface 0%{!?_without_interface:1}
  %define with_ipc 0%{!?_without_ipc:1}
  %define with_ipmi 0%{!?_without_ipmi:1}
  %define with_barometer 0%{!?_without_barometer:0}
  # plugin grpc disabled, requires protobuf-compiler >= 3.0
  %define with_grpc 0%{!?_without_grpc:0}
 +# plugin dpdkstat disabled, requires libdpdk
 +%define with_dpdkstat 0%{!?_without_dpdkstat:0}
  # plugin lpar disabled, requires AIX
  %define with_lpar 0%{!?_without_lpar:0}
 +# plugin intel_rdt disabled, requires intel-cmt-cat
 +%define with_intel_rdt 0%{!?_without_intel_rdt:0}
  # plugin mic disabled, requires Mic
  %define with_mic 0%{!?_without_mic:0}
  # plugin netapp disabled, requires libnetapp
  
  Summary:      Statistics collection and monitoring daemon
  Name:         collectd
 -Version:      5.6.1
 +Version:      5.7.0
- Release:      2%{?dist}
+ Release:      1%{?dist}
  URL:          https://collectd.org
  Source:               https://collectd.org/files/%{name}-%{version}.tar.bz2
  License:      GPLv2
@@@ -456,17 -451,6 +456,17 @@@ The HDDTemp plugin collects the tempera
  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
@@@ -1084,12 -1068,6 +1084,12 @@@ Collectd utilitie
  %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
- * Tue Aug 23 2016 Marc Fournier <marc.fournier@camptocamp.com> - 5.7.0-1
++* 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
  * Sun Aug 14 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.6.0-1
- - New PRE-RELEASE version
+ - New upstream version
  - New plugins enabled by default: chrony, cpusleep, gps, lua, mqtt, notify_nagios
  - New plugins disabled by default: grpc, xencpu, zone
  
diff --combined src/Makefile.am
@@@ -213,7 -213,7 +213,7 @@@ endi
  
  if BUILD_PLUGIN_BATTERY
  pkglib_LTLIBRARIES += battery.la
 -battery_la_SOURCES = battery.c
 +battery_la_SOURCES = battery.c battery_statefs.c
  battery_la_LDFLAGS = $(PLUGIN_LDFLAGS)
  if BUILD_WITH_LIBIOKIT
  battery_la_LDFLAGS += -framework IOKit
@@@ -390,14 -390,6 +390,14 @@@ dns_la_LDFLAGS = $(PLUGIN_LDFLAGS
  dns_la_LIBADD = -lpcap
  endif
  
 +if BUILD_PLUGIN_DPDKSTAT
 +pkglib_LTLIBRARIES += dpdkstat.la
 +dpdkstat_la_SOURCES = dpdkstat.c
 +dpdkstat_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_DPDK_CFLAGS)
 +dpdkstat_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_DPDK_LDFLAGS)
 +dpdkstat_la_LIBADD = $(BUILD_WITH_DPDK_LIBS) 
 +endif
 +
  if BUILD_PLUGIN_DRBD
  pkglib_LTLIBRARIES += drbd.la
  drbd_la_SOURCES = drbd.c
@@@ -478,12 -470,6 +478,12 @@@ hddtemp_la_LIBADD += -lsocke
  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
@@@ -962,14 -948,6 +962,14 @@@ protocols_la_SOURCES = protocols.
  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
@@@ -1273,7 -1251,6 +1273,6 @@@ pkglib_LTLIBRARIES += write_graphite.l
  write_graphite_la_SOURCES = write_graphite.c \
                          utils_format_graphite.c utils_format_graphite.h
  write_graphite_la_LDFLAGS = $(PLUGIN_LDFLAGS)
- write_graphite_la_LIBADD = libformat_json.la
  endif
  
  if BUILD_PLUGIN_WRITE_HTTP
@@@ -1301,7 -1278,6 +1300,7 @@@ pkglib_LTLIBRARIES += write_log.l
  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
diff --combined src/collectd.conf.pod
@@@ -960,7 -960,7 +960,7 @@@ support the SM Bus command subset)
  
  The reduction or normalization to mean sea level pressure requires (depending
  on selected method/approximation) also altitude and reference to temperature
- sensor(s).  When multiple temperature sensors are configured the minumum of
+ sensor(s).  When multiple temperature sensors are configured the minimum of
  their values is always used (expecting that the warmer ones are affected by
  e.g. direct sun light at that moment).
  
@@@ -1072,7 -1072,7 +1072,7 @@@ The altitude (in meters) of the locatio
  
  Temperature sensor(s) which should be used as a reference when normalizing the
  pressure using C<Normalization> method 2.
- When specified more sensors a minumum is found and used each time.  The
+ When specified more sensors a minimum is found and used each time.  The
  temperature reading directly from this pressure sensor/plugin is typically not
  suitable as the pressure sensor will be probably inside while we want outside
  temperature.  The collectd reference name is something like
@@@ -1114,13 -1114,6 +1114,13 @@@ When set to B<true>, the battery plugi
  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>
@@@ -2229,7 -2222,7 +2229,7 @@@ is passed to them, so invalid settings 
  plugin's fault, it will report errors if it gets them from the libraryE<nbsp>/
  the driver. If a driver complains about an option, the plugin will dump a
  complete list of all options understood by that driver to the log. There is no
- way to programatically find out if an option expects a string or a numeric
+ way to programmatically find out if an option expects a string or a numeric
  argument, so you will have to refer to the appropriate DBD's documentation to
  find this out. Sorry.
  
@@@ -2376,67 -2369,6 +2376,67 @@@ Enabled by default, collects unknown (a
  
  =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
@@@ -2887,101 -2819,6 +2887,101 @@@ TCP-Port to connect to. Defaults to B<7
  
  =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
@@@ -3395,12 -3232,11 +3395,12 @@@ interpreted. For a description of matc
  
  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>
@@@ -3413,25 -3249,16 +3413,25 @@@ following options are allowed
  
  =item B<Host> I<Hostname>
  
 -Hostname to connect to. Defaults to B<127.0.0.1>.
 +Sets the B<host> field of dispatched values. Defaults to the global hostname
 +setting.
 +For backwards compatibility, values are also dispatched with the global
 +hostname when B<Host> is set to B<127.0.0.1> or B<localhost> and B<Address> is
 +not set.
 +
 +=item B<Address> I<Address>
 +
 +Hostname or IP to connect to. For backwards compatibility, defaults to the
 +value of B<Host> or B<127.0.0.1> if B<Host> is unset.
  
  =item B<Port> I<Port>
  
 -TCP-Port to connect to. Defaults to B<11211>.
 +TCP port to connect to. Defaults to B<11211>.
  
  =item B<Socket> I<Path>
  
  Connect to I<memcached> using the UNIX domain socket at I<Path>. If this
 -setting is given, the B<Host> and B<Port> settings are ignored.
 +setting is given, the B<Address> and B<Port> settings are ignored.
  
  =back
  
@@@ -5872,7 -5699,7 +5872,7 @@@ values are made available through thos
  
  =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>
  
@@@ -5958,7 -5785,7 +5958,7 @@@ transaction fails or if the database se
  
  Specify the plugin instance name that should be used instead of the database
  name (which is the default, if this option has not been specified). This
- allows to query multiple databases of the same name on the same host (e.g.
+ allows one to query multiple databases of the same name on the same host (e.g.
  when running multiple database server versions in parallel).
  The plugin instance name can also be set from the query result using
  the B<PluginInstanceFrom> option in B<Query> block.
@@@ -6021,7 -5848,7 +6021,7 @@@ Use SSL only
  
  Specify the plugin instance name that should be used instead of the database
  name (which is the default, if this option has not been specified). This
- allows to query multiple databases of the same name on the same host (e.g.
+ allows one to query multiple databases of the same name on the same host (e.g.
  when running multiple database server versions in parallel).
  
  =item B<KRBSrvName> I<kerberos_service_name>
@@@ -6221,11 -6048,11 +6221,11 @@@ below this limit
  
  =item B<ProcessMatch> I<name> I<regex>
  
- Similar to the B<Process> option this allows to select more detailed
+ Similar to the B<Process> option this allows one to select more detailed
  statistics of processes matching the specified I<regex> (see L<regex(7)> for
  details). The statistics of all matching processes are summed up and
  dispatched to the daemon using the specified I<name> as an identifier. This
- allows to "group" several processes together. I<name> must not contain
+ allows one to "group" several processes together. I<name> must not contain
  slashes.
  
  =item B<CollectContextSwitch> I<Boolean>
@@@ -6440,8 -6267,8 +6440,8 @@@ C<collectd> anymore, it does not need t
  restarted. This results in much shorter (if any) gaps in graphs, especially
  under heavy load. Also, the C<rrdtool> command line utility is aware of the
  daemon so that it can flush values to disk automatically when needed. This
- allows to integrate automated flushing of values into graphing solutions much
- more easily.
+ allows one to integrate automated flushing of values into graphing solutions
+ much more easily.
  
  There are disadvantages, though: The daemon may reside on a different host, so
  it may not be possible for C<collectd> to create the appropriate RRD files
@@@ -7964,32 -7791,6 +7964,32 @@@ If set to B<true>, append the name of t
  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>
@@@ -8275,7 -8076,7 +8275,7 @@@ forwarded to the kafka producer librar
  
  =item B<Key> I<String>
  
- Use the specified string as a partioning key for the topic. Kafka breaks
+ Use the specified string as a partitioning key for the topic. Kafka breaks
  topic into partitions and guarantees that for a given topology, the same
  consumer will be used for a specific key. The special (case insensitive)
  string B<Random> can be used to specify that an arbitrary partition should
@@@ -9265,8 -9066,6 +9265,8 @@@ Available options
  
  =item B<TypeInstance> I<Regex>
  
 +=item B<MetaData> I<String> I<Regex>
 +
  Match values where the given regular expressions match the various fields of
  the identifier of a value. If multiple regular expressions are given, B<all>
  regexen must match for a value to match.
@@@ -9555,10 -9354,6 +9555,10 @@@ Available options
  
  =item B<TypeInstance> I<Regex> I<Replacement>
  
 +=item B<MetaData> I<String> I<Regex> I<Replacement>
 +
 +=item B<DeleteMetaData> I<String> I<Regex>
 +
  Match the appropriate field with the given regular expression I<Regex>. If the
  regular expression matches, that part that matches is replaced with
  I<Replacement>. If multiple places of the input buffer match a given regular
@@@ -9597,37 -9392,9 +9597,37 @@@ Available options
  
  =item B<MetaData> I<String> I<String>
  
 -Set the appropriate field to the given string. The strings for plugin instance
 -and type instance may be empty, the strings for host and plugin may not be
 -empty. It's currently not possible to set the type of a value this way.
 +Set the appropriate field to the given string. The strings for plugin instance,
 +type instance, and meta data may be empty, the strings for host and plugin may
 +not be empty. It's currently not possible to set the type of a value this way.
 +
 +The following placeholders will be replaced by an appropriate value:
 +
 +=over 4
 +
 +=item B<%{host}>
 +
 +=item B<%{plugin}>
 +
 +=item B<%{plugin_instance}>
 +
 +=item B<%{type}>
 +
 +=item B<%{type_instance}>
 +
 +These placeholders are replaced by the identifier field of the same name.
 +
 +=item B<%{meta:>I<name>B<}>
 +
 +These placeholders are replaced by the meta data value with the given name.
 +
 +=back
 +
 +Please note that these placeholders are B<case sensitive>!
 +
 +=item B<DeleteMetaData> I<String>
 +
 +Delete the named meta data field.
  
  =back
  
diff --combined src/daemon/common.c
  extern kstat_ctl_t *kc;
  #endif
  
+ /* AIX doesn't have MSG_DONTWAIT */
+ #ifndef MSG_DONTWAIT
+ #  define MSG_DONTWAIT MSG_NONBLOCK
+ #endif
  #if !HAVE_GETPWNAM_R
  static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER;
  #endif
@@@ -334,60 -339,50 +339,60 @@@ int strsplit (char *string, char **fiel
        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;
 +    }
 +
 +    if (field_len > avail)
 +      field_len = avail;
 +
 +    memcpy(ptr, fields[i], field_len);
 +    ptr += field_len;
  
 -      assert (buffer[buffer_size - 1] == 0);
 -      return ((int) strlen (buffer));
 +    avail -= field_len;
 +    if (ptr != NULL)
 +      *ptr = 0;
 +  }
 +
 +  return (int)buffer_req;
  }
  
  int escape_string (char *buffer, size_t buffer_size)
@@@ -1134,7 -1129,7 +1139,7 @@@ int parse_value (const char *value_orig
    }
  
    if (value == endptr) {
-     ERROR ("parse_value: Failed to parse string as %s: %s.",
+     ERROR ("parse_value: Failed to parse string as %s: \"%s\".",
          DS_TYPE_TO_STRING (ds_type), value);
      sfree (value);
      return -1;
@@@ -1209,28 -1204,6 +1214,28 @@@ int parse_values (char *buffer, value_l
        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)
diff --combined src/lua.c
+++ b/src/lua.c
@@@ -303,13 -303,15 +303,13 @@@ static int lua_cb_register_read(lua_Sta
    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");
@@@ -347,11 -349,13 +347,11 @@@ static int lua_cb_register_write(lua_St
    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");
@@@ -543,7 -547,7 +543,7 @@@ static int lua_config_script(const ocon
    if (status != 0)
      return (status);
  
-   INFO("Lua plugin: File \"%s\" loaded succesfully", abs_path);
+   INFO("Lua plugin: File \"%s\" loaded successfully", abs_path);
  
    return 0;
  } /* }}} int lua_config_script */
diff --combined src/rrdcached.c
@@@ -287,14 -287,34 +287,35 @@@ static int rc_config (oconfig_item_t *c
    return (0);
  } /* int rc_config */
  
+ static int try_reconnect (void)
+ {
+   int status;
+   rrdc_disconnect ();
+   rrd_clear_error ();
+   status = rrdc_connect (daemon_address);
+   if (status != 0)
+   {
+     ERROR ("rrdcached plugin: Failed to reconnect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
+     return (-1);
+   }
+   INFO ("rrdcached plugin: Successfully reconnected to RRDCacheD "
+       "at %s", daemon_address);
+   return (0);
+ } /* int try_reconnect */
  static int rc_read (void)
  {
    int status;
    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));
  
+   rrd_clear_error ();
    status = rrdc_connect (daemon_address);
    if (status != 0)
    {
-     ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
-         daemon_address, status);
+     ERROR ("rrdcached plugin: Failed to connect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
      return (-1);
    }
  
-   head = NULL;
-   status = rrdc_stats_get (&head);
-   if (status != 0)
+   while (42)
    {
-     ERROR ("rrdcached plugin: rrdc_stats_get failed with status %i.", status);
+     /* The RRD client lib does not provide any means for checking a
+      * connection, hence we'll have to retry upon failed operations. */
+     head = NULL;
+     rrd_clear_error ();
+     status = rrdc_stats_get (&head);
+     if (status == 0)
+       break;
+     if (!retried)
+     {
+       retried = 1;
+       if (try_reconnect () == 0)
+         continue;
+       /* else: report the error and fail */
+     }
+     ERROR ("rrdcached plugin: rrdc_stats_get failed: %s (status=%i).",
+         rrd_get_error (), status);
      return (-1);
    }
  
    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;
  
@@@ -407,6 -448,7 +444,7 @@@ static int rc_write (const data_set_t *
    char values[512];
    char *values_array[2];
    int status;
+   _Bool retried = 0;
  
    if (daemon_address == NULL)
    {
      }
    }
  
+   rrd_clear_error ();
    status = rrdc_connect (daemon_address);
    if (status != 0)
    {
-     ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
-         daemon_address, status);
+     ERROR ("rrdcached plugin: Failed to connect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
      return (-1);
    }
  
-   status = rrdc_update (filename, /* values_num = */ 1, (void *) values_array);
-   if (status != 0)
+   while (42)
    {
-     ERROR ("rrdcached plugin: rrdc_update (%s, [%s], 1) failed with "
-         "status %i.",
-         filename, values_array[0], status);
+     /* The RRD client lib does not provide any means for checking a
+      * connection, hence we'll have to retry upon failed operations. */
+     rrd_clear_error ();
+     status = rrdc_update (filename, /* values_num = */ 1, (void *) values_array);
+     if (status == 0)
+       break;
+     if (!retried)
+     {
+       retried = 1;
+       if (try_reconnect () == 0)
+         continue;
+       /* else: report the error and fail */
+     }
+     ERROR ("rrdcached plugin: rrdc_update (%s, [%s], 1) failed: %s (status=%i)",
+         filename, values_array[0], rrd_get_error (), status);
      return (-1);
    }
  
@@@ -489,6 -545,7 +541,7 @@@ static int rc_flush (__attribute__((unu
  {
    char filename[PATH_MAX + 1];
    int status;
+   _Bool retried = 0;
  
    if (identifier == NULL)
      return (EINVAL);
    else
      ssnprintf (filename, sizeof (filename), "%s.rrd", identifier);
  
+   rrd_clear_error ();
    status = rrdc_connect (daemon_address);
    if (status != 0)
    {
-     ERROR ("rrdcached plugin: rrdc_connect (%s) failed with status %i.",
-         daemon_address, status);
+     ERROR ("rrdcached plugin: Failed to connect to RRDCacheD "
+         "at %s: %s (status=%d)", daemon_address, rrd_get_error (), status);
      return (-1);
    }
  
-   status = rrdc_flush (filename);
-   if (status != 0)
+   while (42)
    {
-     ERROR ("rrdcached plugin: rrdc_flush (%s) failed with status %i.",
-         filename, status);
+     /* The RRD client lib does not provide any means for checking a
+      * connection, hence we'll have to retry upon failed operations. */
+     rrd_clear_error ();
+     status = rrdc_flush (filename);
+     if (status == 0)
+       break;
+     if (!retried)
+     {
+       retried = 1;
+       if (try_reconnect () == 0)
+         continue;
+       /* else: report the error and fail */
+     }
+     ERROR ("rrdcached plugin: rrdc_flush (%s) failed: %s (status=%i).",
+         filename, rrd_get_error (), status);
      return (-1);
    }
    DEBUG ("rrdcached plugin: rrdc_flush (%s): Success.", filename);
diff --combined src/tail_csv.c
@@@ -69,6 -69,7 +69,6 @@@ static int tcsv_submit (instance_defini
      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));
@@@ -481,11 -482,13 +481,11 @@@ static int tcsv_config_add_file(oconfig
  
      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);
@@@ -534,7 -537,7 +534,7 @@@ static int tcsv_init(void) { /* {{{ *
          else if (ds->ds_num != 1)
          {
              ERROR ("tail_csv plugin: The type \"%s\" has %zu data sources. "
-                     "Only types with a single data soure are supported.",
+                     "Only types with a single data source are supported.",
                      ds->type, ds->ds_num);
              continue;
          }
diff --combined src/vserver.c
@@@ -56,14 -56,15 +56,14 @@@ static int vserver_init (void
  static void traffic_submit (const char *plugin_instance,
                const char *type_instance, derive_t rx, derive_t tx)
  {
 -      value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 -
 -      values[0].derive = rx;
 -      values[1].derive = tx;
 +      value_t values[] = {
 +              { .derive = rx },
 +              { .derive = tx },
 +      };
  
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
 -      sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
        sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, "if_octets", sizeof (vl.type));
  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));
@@@ -95,10 -97,14 +95,10 @@@ static void submit_gauge (const char *p
                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));
@@@ -126,15 -132,7 +126,7 @@@ static derive_t vserver_get_sock_bytes(
  
  static int vserver_read (void)
  {
- #if NAME_MAX < 1024
- # define DIRENT_BUFFER_SIZE (sizeof (struct dirent) + 1024 + 1)
- #else
- # define DIRENT_BUFFER_SIZE (sizeof (struct dirent) + NAME_MAX + 1)
- #endif
-       DIR                     *proc;
-       struct dirent   *dent; /* 42 */
-       char dirent_buffer[DIRENT_BUFFER_SIZE];
+       DIR *proc;
  
        errno = 0;
        proc = opendir (PROCDIR);
  
        while (42)
        {
+               struct dirent *dent;
                int len;
                char file[BUFSIZE];
  
  
                int status;
  
-               status = readdir_r (proc, (struct dirent *) dirent_buffer, &dent);
-               if (status != 0)
+               errno = 0;
+               dent = readdir (proc);
+               if (dent == NULL)
                {
                        char errbuf[4096];
-                       ERROR ("vserver plugin: readdir_r failed: %s",
-                                       sstrerror (errno, errbuf, sizeof (errbuf)));
+                       if (errno == 0) /* end of directory */
+                               break;
+                       ERROR ("vserver plugin: failed to read directory %s: %s",
+                                       PROCDIR, sstrerror (errno, errbuf, sizeof (errbuf)));
                        closedir (proc);
                        return (-1);
                }
-               else if (dent == NULL)
-               {
-                       /* end of directory */
-                       break;
-               }
  
                if (dent->d_name[0] == '.')
                        continue;
diff --combined src/write_redis.c
@@@ -91,7 -91,7 +91,7 @@@ static int wr_write (const data_set_t *
      node->conn = redisConnectWithTimeout ((char *)node->host, node->port, node->timeout);
      if (node->conn == NULL)
      {
-       ERROR ("write_redis plugin: Connecting to host \"%s\" (port %i) failed: Unkown reason",
+       ERROR ("write_redis plugin: Connecting to host \"%s\" (port %i) failed: Unknown reason",
            (node->host != NULL) ? node->host : "localhost",
            (node->port != 0) ? node->port : 6379);
        pthread_mutex_unlock (&node->lock);
@@@ -234,11 -234,12 +234,11 @@@ static int wr_config_node (oconfig_item
  
      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)