Merge branch 'collectd-5.7'
authorFlorian Forster <octo@collectd.org>
Thu, 20 Jul 2017 07:12:14 +0000 (09:12 +0200)
committerFlorian Forster <octo@collectd.org>
Thu, 20 Jul 2017 07:12:14 +0000 (09:12 +0200)
Conflicts:
src/rrdtool.c

1  2 
src/collectd.conf.pod
src/rrdtool.c

diff --combined src/collectd.conf.pod
@@@ -2393,123 -2393,6 +2393,123 @@@ Enabled by default, collects unknown (a
  
  =back
  
 +=head2 Plugin C<dpdkevents>
 +
 +The I<dpdkevents plugin> collects events from DPDK such as link status of
 +network ports and Keep Alive status of DPDK logical cores.
 +In order to get Keep Alive events following requirements must be met:
 +- DPDK >= 16.07
 +- support for Keep Alive implemented in DPDK application. More details can
 +be found here: http://dpdk.org/doc/guides/sample_app_ug/keep_alive.html
 +
 +B<Synopsis:>
 +
 + <Plugin "dpdkevents">
 +   <EAL>
 +     Coremask "0x1"
 +     MemoryChannels "4"
 +     FilePrefix "rte"
 +   </EAL>
 +   <Event "link_status">
 +     SendEventsOnUpdate true
 +     EnabledPortMask 0xffff
 +     PortName "interface1"
 +     PortName "interface2"
 +     SendNotification false
 +   </Event>
 +   <Event "keep_alive">
 +     SendEventsOnUpdate true
 +     LCoreMask "0xf"
 +     KeepAliveShmName "/dpdk_keepalive_shm_name"
 +     SendNotification false
 +   </Event>
 + </Plugin>
 +
 +B<Options:>
 +
 +
 +=head3 The EAL block
 +
 +=over 4
 +
 +=item B<Coremask> I<Mask>
 +
 +=item B<Memorychannels> I<Channels>
 +
 +Number of memory channels per processor socket.
 +
 +=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.
 +
 +=back
 +
 +=head3 The Event block
 +
 +The B<Event> block defines configuration for specific event. It accepts a
 +single argument which specifies the name of the event.
 +
 +=head4 Link Status event
 +
 +=over 4
 +
 +=item B<SendEventOnUpdate> I<true|false>
 +
 +If set to true link status value will be dispatched only when it is
 +different from previously read value. This is an optional argument - default
 +value is true.
 +
 +=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 F's means
 +that all ports will be enabled. This is an optional argument - by default
 +all ports are 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.
 +
 +=item B<SendNotification> I<true|false>
 +
 +If set to true, link status notifications are sent, instead of link status
 +being collected as a statistic. This is an optional argument - default
 +value is false.
 +
 +=back
 +
 +=head4 Keep Alive event
 +
 +=over 4
 +
 +=item B<SendEventOnUpdate> I<true|false>
 +
 +If set to true keep alive value will be dispatched only when it is
 +different from previously read value. This is an optional argument - default
 +value is true.
 +
 +=item B<LCoreMask> I<Mask>
 +
 +An hexadecimal bit mask of the logical cores to monitor keep alive state.
 +
 +=item B<KeepAliveShmName> I<Name>
 +
 +Shared memory name identifier that is used by secondary process to monitor
 +the keep alive cores state.
 +
 +=item B<SendNotification> I<true|false>
 +
 +If set to true, keep alive notifications are sent, instead of keep alive
 +information being collected as a statistic. This is an optional
 +argument - default value is false.
 +
 +=back
 +
  =head2 Plugin C<dpdkstat>
  
  The I<dpdkstat plugin> collects information about DPDK interfaces using the
@@@ -2518,22 -2401,17 +2518,22 @@@ extended NIC stats API in DPDK
  B<Synopsis:>
  
   <Plugin "dpdkstat">
 -    Coremask "0x4"
 -    MemoryChannels "4"
 -    ProcessType "secondary"
 -    FilePrefix "rte"
 -    EnabledPortMask 0xffff
 -    PortName "interface1"
 -    PortName "interface2"
 +   <EAL>
 +     Coremask "0x4"
 +     MemoryChannels "4"
 +     FilePrefix "rte"
 +     SocketMemory "1024"
 +   </EAL>
 +   SharedMemObj "dpdk_collectd_stats_0"
 +   EnabledPortMask 0xffff
 +   PortName "interface1"
 +   PortName "interface2"
   </Plugin>
  
  B<Options:>
  
 +=head3 The EAL block
 +
  =over 4
  
  =item B<Coremask> I<Mask>
@@@ -2545,6 -2423,10 +2545,6 @@@ core numbering can change between platf
  
  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
  =item B<SocketMemory> I<MB>
  
  A string containing amount of Memory to allocate from hugepages on specific
 -sockets in MB
 +sockets in MB. This is an optional value.
 +
 +=back
 +
 +=over 3
 +
 +=item B<SharedMemObj> I<Mask>
 +
 +A string containing the name of the shared memory object that should be used to
 +share stats from the DPDK secondary process to the collectd dpdkstat plugin.
 +Defaults to dpdk_collectd_stats if no other value is configured.
  
  =item B<EnabledPortMask> I<Mask>
  
@@@ -3073,92 -2945,6 +3073,92 @@@ Defaults to B<false>
  
  =back
  
 +=head2 Plugin C<intel_pmu>
 +
 +The I<intel_pmu> plugin collects performance counters data on Intel CPUs using
 +Linux perf interface. All events are reported on a per core basis.
 +
 +B<Synopsis:>
 +
 +  <Plugin intel_pmu>
 +    ReportHardwareCacheEvents true
 +    ReportKernelPMUEvents true
 +    ReportSoftwareEvents true
 +    EventList "/var/cache/pmu/GenuineIntel-6-2D-core.json"
 +    HardwareEvents "L2_RQSTS.CODE_RD_HIT,L2_RQSTS.CODE_RD_MISS" "L2_RQSTS.ALL_CODE_RD"
 +  </Plugin>
 +
 +B<Options:>
 +
 +=over 4
 +
 +=item B<ReportHardwareCacheEvents> B<false>|B<true>
 +
 +Enable or disable measuring of hardware CPU cache events:
 +  - L1-dcache-loads
 +  - L1-dcache-load-misses
 +  - L1-dcache-stores
 +  - L1-dcache-store-misses
 +  - L1-dcache-prefetches
 +  - L1-dcache-prefetch-misses
 +  - L1-icache-loads
 +  - L1-icache-load-misses
 +  - L1-icache-prefetches
 +  - L1-icache-prefetch-misses
 +  - LLC-loads
 +  - LLC-load-misses
 +  - LLC-stores
 +  - LLC-store-misses
 +  - LLC-prefetches
 +  - LLC-prefetch-misses
 +  - dTLB-loads
 +  - dTLB-load-misses
 +  - dTLB-stores
 +  - dTLB-store-misses
 +  - dTLB-prefetches
 +  - dTLB-prefetch-misses
 +  - iTLB-loads
 +  - iTLB-load-misses
 +  - branch-loads
 +  - branch-load-misses
 +
 +=item B<ReportKernelPMUEvents> B<false>|B<true>
 +
 +Enable or disable measuring of the following events:
 +  - cpu-cycles
 +  - instructions
 +  - cache-references
 +  - cache-misses
 +  - branches
 +  - branch-misses
 +  - bus-cycles
 +
 +=item B<ReportSoftwareEvents> B<false>|B<true>
 +
 +Enable or disable measuring of software events provided by kernel:
 +  - cpu-clock
 +  - task-clock
 +  - context-switches
 +  - cpu-migrations
 +  - page-faults
 +  - minor-faults
 +  - major-faults
 +  - alignment-faults
 +  - emulation-faults
 +
 +=item B<EventList> I<filename>
 +
 +JSON performance counter event list file name. To be able to monitor all Intel
 +CPU specific events JSON event list file should be downloaded. Use the pmu-tools
 +event_download.py script to download event list for current CPU.
 +
 +=item B<HardwareEvents> I<events>
 +
 +This field is a list of event names or groups of comma separated event names.
 +This option requires B<EventList> option to be configured.
 +
 +=back
 +
  =head2 Plugin C<intel_rdt>
  
  The I<intel_rdt> plugin collects information provided by monitoring features of
@@@ -3173,10 -2959,6 +3173,10 @@@ allows to monitor instructions per cloc
  Monitor events are hardware dependant. Monitoring capabilities are detected on
  plugin initialization and only supported events are monitored.
  
 +B<Note:> I<intel_rdt> plugin is using model-specific registers (MSRs), which
 +require an additional capability to be enabled if collectd is run as a service.
 +Please refer to I<contrib/systemd.collectd.service> file for more details.
 +
  B<Synopsis:>
  
    <Plugin "intel_rdt">
@@@ -3230,7 -3012,7 +3230,7 @@@ See F</"IGNORELISTS"> for details
  
  =item B<IgnoreSelected> I<true>|I<false>
  
 -If no configuration if given, the B<interface>-plugin will collect data from
 +If no configuration is given, the B<interface>-plugin will collect data from
  all interfaces. This may not be practical, especially for loopback- and
  similar interfaces. Thus, you can use the B<Interface>-option to pick the
  interfaces you're interested in. Sometimes, however, it's easier/preferred
@@@ -3556,28 -3338,6 +3556,28 @@@ TCP-Port to connect to. Defaults to B<4
  
  =back
  
 +=head2 Plugin C<mcelog>
 +
 +The C<mcelog plugin> uses mcelog to retrieve machine check exceptions.
 +
 +By default the plugin connects to B<"/var/run/mcelog-client"> to check if the
 +mcelog server is running. When the server is running, the plugin will tail the
 +specified logfile to retrieve machine check exception information and send a
 +notification with the details from the logfile. The plugin will use the mcelog
 +client protocol to retrieve memory related machine check exceptions.
 +
 +=over 4
 +
 +=item B<McelogClientSocket> I<Path>
 +Connect to the mcelog client socket using the UNIX domain socket at I<Path>.
 +Defaults to B<"/var/run/mcelog-client">.
 +
 +=item B<McelogLogfile> I<Path>
 +
 +The mcelog file to parse. Defaults to B<"/var/log/mcelog">.
 +
 +=back
 +
  =head2 Plugin C<md>
  
  The C<md plugin> collects information from Linux Software-RAID devices (md).
@@@ -5348,40 -5108,6 +5348,40 @@@ making it through
  Add a UPS to collect data from. The format is identical to the one accepted by
  L<upsc(8)>.
  
 +=item B<ForceSSL> B<true>|B<false>
 +
 +Stops connections from falling back to unsecured if an SSL connection
 +cannot be established. Defaults to false if undeclared.
 +
 +=item B<VerifyPeer> I<true>|I<false>
 +
 +If set to true, requires a CAPath be provided. Will use the CAPath to find
 +certificates to use as Trusted Certificates to validate a upsd server certificate.
 +If validation of the upsd server certificate fails, the connection will not be
 +established. If ForceSSL is undeclared or set to false, setting VerifyPeer to true
 +will override and set ForceSSL to true.
 +
 +=item B<CAPath> I/path/to/certs/folder
 +
 +If VerifyPeer is set to true, this is required. Otherwise this is ignored.
 +The folder pointed at must contain certificate(s) named according to their hash.
 +Ex: XXXXXXXX.Y where X is the hash value of a cert and Y is 0. If name collisions
 +occur because two different certs have the same hash value, Y can be  incremented
 +in order to avoid conflict. To create a symbolic link to a certificate the following
 +command can be used from within the directory where the cert resides:
 +
 +C<ln -s some.crt ./$(openssl x509 -hash -noout -in some.crt).0>
 +
 +Alternatively, the package openssl-perl provides a command C<c_rehash> that will
 +generate links like the one described above for ALL certs in a given folder.
 +Example usage:
 +C<c_rehash /path/to/certs/folder>
 +
 +=item B<ConnectTimeout> I<Milliseconds>
 +
 +The B<ConnectTimeout> option sets the connect timeout, in milliseconds.
 +By default, the configured B<Interval> is used to set the timeout.
 +
  =back
  
  =head2 Plugin C<olsrd>
@@@ -5729,123 -5455,6 +5729,123 @@@ refer to them from
  
  =back
  
 +=head2 Plugin C<ovs_events>
 +
 +The I<ovs_events> plugin monitors the link status of I<Open vSwitch> (OVS)
 +connected interfaces, dispatches the values to collectd and sends the
 +notification whenever the link state change occurs. This plugin uses OVS
 +database to get a link state change notification.
 +
 +B<Synopsis:>
 +
 + <Plugin "ovs_events">
 +   Port 6640
 +   Address "127.0.0.1"
 +   Socket "/var/run/openvswitch/db.sock"
 +   Interfaces "br0" "veth0"
 +   SendNotification true
 +   DispatchValues false
 + </Plugin>
 +
 +The plugin provides the following configuration options:
 +
 +=over 4
 +
 +=item B<Address> I<node>
 +
 +The address of the OVS DB server JSON-RPC interface used by the plugin. To
 +enable the interface, OVS DB daemon should be running with C<--remote=ptcp:>
 +option. See L<ovsdb-server(1)> for more details. The option may be either
 +network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string
 +format. Defaults to B<'localhost'>.
 +
 +=item B<Port> I<service>
 +
 +TCP-port to connect to. Either a service name or a port number may be given.
 +Defaults to B<6640>.
 +
 +=item B<Socket> I<path>
 +
 +The UNIX domain socket path of OVS DB server JSON-RPC interface used by the
 +plugin. To enable the interface, the OVS DB daemon should be running with
 +C<--remote=punix:> option. See L<ovsdb-server(1)> for more details. If this
 +option is set, B<Address> and B<Port> options are ignored.
 +
 +=item B<Interfaces> [I<ifname> ...]
 +
 +List of interface names to be monitored by this plugin. If this option is not
 +specified or is empty then all OVS connected interfaces on all bridges are
 +monitored.
 +
 +Default: empty (all interfaces on all bridges are monitored)
 +
 +=item B<SendNotification> I<true|false>
 +
 +If set to true, OVS link notifications (interface status and OVS DB connection
 +terminate) are sent to collectd. Default value is true.
 +
 +=item B<DispatchValues> I<true|false>
 +
 +Dispatch the OVS DB interface link status value with configured plugin interval.
 +Defaults to false. Please note, if B<SendNotification> and B<DispatchValues>
 +options are false, no OVS information will be provided by the plugin.
 +
 +=back
 +
 +B<Note:> By default, the global interval setting is used within which to
 +retrieve the OVS link status. To configure a plugin-specific interval, please
 +use B<Interval> option of the OVS B<LoadPlugin> block settings. For milliseconds
 +simple divide the time by 1000 for example if the desired interval is 50ms, set
 +interval to 0.05.
 +
 +=head2 Plugin C<ovs_stats>
 +
 +The I<ovs_stats> plugin collects statistics of OVS connected interfaces.
 +This plugin uses OVSDB management protocol (RFC7047) monitor mechanism to get
 +statistics from OVSDB
 +
 +B<Synopsis:>
 +
 + <Plugin "ovs_stats">
 +   Port 6640
 +   Address "127.0.0.1"
 +   Socket "/var/run/openvswitch/db.sock"
 +   Bridges "br0" "br_ext"
 + </Plugin>
 +
 +The plugin provides the following configuration options:
 +
 +=over 4
 +
 +=item B<Address> I<node>
 +
 +The address of the OVS DB server JSON-RPC interface used by the plugin. To
 +enable the interface, OVS DB daemon should be running with C<--remote=ptcp:>
 +option. See L<ovsdb-server(1)> for more details. The option may be either
 +network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string
 +format. Defaults to B<'localhost'>.
 +
 +=item B<Port> I<service>
 +
 +TCP-port to connect to. Either a service name or a port number may be given.
 +Defaults to B<6640>.
 +
 +=item B<Socket> I<path>
 +
 +The UNIX domain socket path of OVS DB server JSON-RPC interface used by the
 +plugin. To enable the interface, the OVS DB daemon should be running with
 +C<--remote=punix:> option. See L<ovsdb-server(1)> for more details. If this
 +option is set, B<Address> and B<Port> options are ignored.
 +
 +=item B<Bridges> [I<brname> ...]
 +
 +List of OVS bridge names to be monitored by this plugin. If this option is
 +omitted or is empty then all OVS bridges will be monitored.
 +
 +Default: empty (monitor all bridges)
 +
 +=back
 +
  =head2 Plugin C<perl>
  
  This plugin embeds a Perl-interpreter into collectd and provides an interface
@@@ -6634,15 -6243,9 +6634,15 @@@ C<I<prefix>/var/run/collectd-powerdns>
  =item B<Process> I<Name>
  
  Select more detailed statistics of processes matching this name. The statistics
 -collected for these selected processes are size of the resident segment size
 -(RSS), user- and system-time used, number of processes and number of threads,
 -io data (where available) and minor and major pagefaults.
 +collected for these selected processes are:
 + - size of the resident segment size (RSS)
 + - user- and system-time used
 + - number of processes
 + - number of threads
 + - number of open files (under Linux)
 + - io data (where available)
 + - context switches (under Linux)
 + - minor and major pagefaults.
  
  Some platforms have a limit on the length of process names. I<Name> must stay
  below this limit.
@@@ -7043,14 -6646,20 +7043,20 @@@ one (exclusive)
  
  When the C<rrdtool> plugin uses a cache (by setting B<CacheTimeout>, see below)
  it writes all values for a certain RRD-file if the oldest value is older than
- (or equal to) the number of seconds specified. If some RRD-file is not updated
+ (or equal to) the number of seconds specified by B<CacheTimeout>.
+ That check happens on new values arriwal. If some RRD-file is not updated
  anymore for some reason (the computer was shut down, the network is broken,
- etc.) some values may still be in the cache. If B<CacheFlush> is set, then the
- entire cache is searched for entries older than B<CacheTimeout> seconds and
- written to disk every I<Seconds> seconds. Since this is kind of expensive and
- does nothing under normal circumstances, this value should not be too small.
- 900 seconds might be a good value, though setting this to 7200 seconds doesn't
- normally do much harm either.
+ etc.) some values may still be in the cache. If B<CacheFlush> is set, then
+ every I<Seconds> seconds the entire cache is searched for entries older than
+ B<CacheTimeout> + B<RandomTimeout> seconds. The entries found are written to
+ disk. Since scanning the entire cache is kind of expensive and does nothing
+ under normal circumstances, this value should not be too small. 900 seconds
+ might be a good value, though setting this to 7200 seconds doesn't normally
+ do much harm either.
+ Defaults to 10x B<CacheTimeout>.
+ B<CacheFlush> must be larger than or equal to B<CacheTimeout>, otherwise the
+ above default is used.
  
  =item B<CacheTimeout> I<Seconds>
  
@@@ -7264,122 -6873,6 +7270,122 @@@ Since the configuration of the C<snmp p
  other plugins, its documentation has been moved to an own manpage,
  L<collectd-snmp(5)>. Please see there for details.
  
 +=head2 Plugin C<snmp_agent>
 +
 +The I<snmp_agent> plugin is an AgentX subagent that receives and handles queries
 +from SNMP master agent and returns the data collected by read plugins.
 +The I<snmp_agent> plugin handles requests only for OIDs specified in
 +configuration file. To handle SNMP queries the plugin gets data from collectd
 +and translates requested values from collectd's internal format to SNMP format.
 +This plugin is a generic plugin and cannot work without configuration.
 +For more details on AgentX subagent see
 +<http://www.net-snmp.org/tutorial/tutorial-5/toolkit/demon/>
 +
 +B<Synopsis:>
 +
 +  <Plugin snmp_agent>
 +    <Data "memAvailReal">
 +      Plugin "memory"
 +      #PluginInstance "some"
 +      Type "memory"
 +      TypeInstance "free"
 +      OIDs "1.3.6.1.4.1.2021.4.6.0"
 +    </Data>
 +    <Table "ifTable">
 +      IndexOID "IF-MIB::ifIndex"
 +      SizeOID "IF-MIB::ifNumber"
 +      <Data "ifDescr">
 +        Instance true
 +        Plugin "interface"
 +        OIDs "IF-MIB::ifDescr"
 +      </Data>
 +      <Data "ifOctets">
 +        Plugin "interface"
 +        Type "if_octets"
 +        TypeInstance ""
 +        OIDs "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
 +      </Data>
 +    </Table>
 +  </Plugin>
 +
 +There are two types of blocks that can be contained in the
 +C<E<lt>PluginE<nbsp> snmp_agentE<gt>> block: B<Data> and B<Table>:
 +
 +=head3 The B<Data> block
 +
 +The B<Data> block defines a list OIDs that are to be handled. This block can
 +define scalar or table OIDs. If B<Data> block is defined inside of B<Table>
 +block it reperesents table OIDs.
 +The following options can be set:
 +
 +=over 4
 +
 +=item B<Instance> I<true|false>
 +
 +When B<Instance> is set to B<true>, the value for requested OID is copied from
 +plugin instance field of corresponding collectd value. If B<Data> block defines
 +scalar data type B<Instance> has no effect and can be omitted.
 +
 +=item B<Plugin> I<String>
 +
 +Read plugin name whose collected data will be mapped to specified OIDs.
 +
 +=item B<PluginInstance> I<String>
 +
 +Read plugin instance whose collected data will be mapped to specified OIDs.
 +The field is optional and by default there is no plugin instance check.
 +Allowed only if B<Data> block defines scalar data type.
 +
 +=item B<Type> I<String>
 +
 +Collectd's type that is to be used for specified OID, e.E<nbsp>g. "if_octets"
 +for example. The types are read from the B<TypesDB> (see L<collectd.conf(5)>).
 +
 +=item B<TypeInstance> I<String>
 +
 +Collectd's type-instance that is to be used for specified OID.
 +
 +=item B<OIDs> I<OID> [I<OID> ...]
 +
 +Configures the OIDs to be handled by I<snmp_agent> plugin. Values for these OIDs
 +are taken from collectd data type specified by B<Plugin>, B<PluginInstance>,
 +B<Type>, B<TypeInstance> fields of this B<Data> block. Number of the OIDs
 +configured should correspond to number of values in specified B<Type>.
 +For example two OIDs "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets" can be mapped to
 +"rx" and "tx" values of "if_octets" type.
 +
 +=item B<Scale> I<Value>
 +
 +The values taken from collectd are multiplied by I<Value>. The field is optional
 +and the default is B<1.0>.
 +
 +=item B<Shift> I<Value>
 +
 +I<Value> is added to values from collectd after they have been multiplied by
 +B<Scale> value. The field is optional and the default value is B<0.0>.
 +
 +=back
 +
 +=head3 The B<Table> block
 +
 +The B<Table> block defines a collection of B<Data> blocks that belong to one
 +snmp table. In addition to multiple B<Data> blocks the following options can be
 +set:
 +
 +=over 4
 +
 +=item B<IndexOID> I<OID>
 +
 +OID that is handled by the plugin and is mapped to numerical index value that is
 +generated by the plugin for each table record.
 +
 +=item B<SizeOID> I<OID>
 +
 +OID that is handled by the plugin. Returned value is the number of records in
 +the table. The field is optional.
 +
 +=back
 +
  =head2 Plugin C<statsd>
  
  The I<statsd plugin> listens to a UDP socket, reads "events" in the statsd
@@@ -8376,11 -7869,11 +8382,11 @@@ Collect statistics about worker threads
  
  =head2 Plugin C<virt>
  
 -This plugin allows CPU, disk and network load to be collected for virtualized
 -guests on the machine. This means that these metrics can be collected for guest
 -systems without installing any software on them - I<collectd> only runs on the
 -host system. The statistics are collected through libvirt
 -(L<http://libvirt.org/>).
 +This plugin allows CPU, disk, network load and other metrics to be collected for
 +virtualized guests on the machine. The statistics are collected through libvirt
 +API (L<http://libvirt.org/>). Majority of metrics can be gathered without
 +installing any additional software on guests, especially I<collectd>, which runs
 +only on the host system.
  
  Only I<Connection> is required.
  
@@@ -8518,61 -8011,6 +8524,61 @@@ You can also specify combinations of th
  For example B<name uuid> means to concatenate the guest name and UUID
  (with a literal colon character between, thus I<"foo:1234-1234-1234-1234">).
  
 +=item B<Instances> B<integer>
 +
 +How many read instances you want to use for this plugin. The default is one,
 +and the sensible setting is a multiple of the B<ReadThreads> value.
 +If you are not sure, just use the default setting.
 +
 +=item B<ExtraStats> B<string>
 +
 +Report additional extra statistics. The default is no extra statistics, preserving
 +the previous behaviour of the plugin. If unsure, leave the default. If enabled,
 +allows the plugin to reported more detailed statistics about the behaviour of
 +Virtual Machines. The argument is a space-separated list of selectors.
 +
 +Currently supported selectors are:
 +
 +=over 4
 +
 +=item B<cpu_util>: report CPU utilization per domain in percentage.
 +
 +=item B<disk>: report extra statistics like number of flush operations and total
 +service time for read, write and flush operations. Requires libvirt API version
 +I<0.9.5> or later.
 +
 +=item B<disk_err>: report disk errors if any occured. Requires libvirt API version
 +I<0.9.10> or later.
 +
 +=item B<domain_state>: report domain state and reason in human-readable format as
 +a notification. If libvirt API version I<0.9.2> or later is available, domain
 +reason will be included in notification.
 +
 +=item B<fs_info>: report file system information as a notification. Requires
 +libvirt API version I<1.2.11> or later. Can be collected only if I<Guest Agent>
 +is installed and configured inside VM. Make sure that installed I<Guest Agent>
 +version supports retrieving  file system information.
 +
 +=item B<job_stats_background>: report statistics about progress of a background
 +job on a domain. Only one type of job statistics can be collected at the same time.
 +Requires libvirt API version I<1.2.9> or later.
 +
 +=item B<job_stats_completed>: report statistics about a recently completed job on
 +a domain. Only one type of job statistics can be collected at the same time.
 +Requires libvirt API version I<1.2.9> or later.
 +
 +=item B<pcpu>: report the physical user/system cpu time consumed by the hypervisor, per-vm.
 +Requires libvirt API version I<0.9.11> or later.
 +
 +=item B<perf>: report performance monitoring events. To collect performance
 +metrics they must be enabled for domain and supported by the platform. Requires
 +libvirt API version I<1.3.3> or later.
 +B<Note>: I<perf> metrics can't be collected if I<intel_rdt> plugin is enabled.
 +
 +=item B<vcpupin>: report pinning of domain VCPUs to host physical CPUs.
 +
 +=back
 +
  =back
  
  =head2 Plugin C<vmem>
@@@ -8743,8 -8181,6 +8749,8 @@@ packets
  Synopsis:
  
   <Plugin write_tsdb>
 +   ResolveInterval 60
 +   ResolveJitter 60
     <Node "example">
       Host "tsd-1.my.domain"
       Port "4242"
   </Plugin>
  
  The configuration consists of one or more E<lt>B<Node>E<nbsp>I<Name>E<gt>
 -blocks. Inside the B<Node> blocks, the following options are recognized:
 +blocks and global directives.
 +
 +Global directives are:
 +
 +=over 4
 +
 +=item B<ResolveInterval> I<seconds>
 +
 +=item B<ResolveJitter> I<seconds>
 +
 +When I<collectd> connects to a TSDB node, it will request the hostname from
 +DNS. This can become a problem if the TSDB node is unavailable or badly
 +configured because collectd will request DNS in order to reconnect for every
 +metric, which can flood your DNS. So you can cache the last value for
 +I<ResolveInterval> seconds.
 +Defaults to the I<Interval> of the I<write_tsdb plugin>, e.g. 10E<nbsp>seconds.
 +
 +You can also define a jitter, a random interval to wait in addition to
 +I<ResolveInterval>. This prevents all your collectd servers to resolve the
 +hostname at the same time when the connection fails.
 +Defaults to the I<Interval> of the I<write_tsdb plugin>, e.g. 10E<nbsp>seconds.
 +
 +B<Note:> If the DNS resolution has already been successful when the socket
 +closes, the plugin will try to reconnect immediately with the cached
 +information. DNS is queried only when the socket is closed for a longer than
 +I<ResolveInterval> + I<ResolveJitter> seconds.
 +
 +=back
 +
 +Inside the B<Node> blocks, the following options are recognized:
  
  =over 4
  
@@@ -8999,23 -8406,6 +9005,23 @@@ create output in the I<JavaScript Objec
  
  Defaults to B<Command>.
  
 +=item B<Attribute> I<String> I<String>
 +
 +Only available for the KAIROSDB output format.
 +
 +Consider the two given strings to be the key and value of an additional tag for
 +each metric being sent out.
 +
 +You can add multiple B<Attribute>.
 +
 +=item B<TTL> I<Int>
 +
 +Only available for the KAIROSDB output format.
 +
 +Sets the Cassandra ttl for the data points.
 +
 +Please refer to L<http://kairosdb.github.io/docs/build/html/restapi/AddDataPoints.html?highlight=ttl>
 +
  =item B<Metrics> B<true>|B<false>
  
  Controls whether I<metrics> are POSTed to this location. Defaults to B<true>.
diff --combined src/rrdtool.c
@@@ -87,7 -87,7 +87,7 @@@ static rrdcreate_config_t rrdcreate_con
   * ALWAYS lock `cache_lock' first! */
  static cdtime_t cache_timeout = 0;
  static cdtime_t cache_flush_timeout = 0;
- static cdtime_t random_timeout = TIME_T_TO_CDTIME_T_STATIC(1);
+ static cdtime_t random_timeout = 0;
  static cdtime_t cache_flush_last;
  static c_avl_tree_t *cache = NULL;
  static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
@@@ -122,7 -122,7 +122,7 @@@ static int srrd_update(char *filename, 
              rrd_get_error());
    }
  
 -  return (status);
 +  return status;
  } /* int srrd_update */
  /* #endif HAVE_THREADSAFE_LIBRRD */
  
@@@ -140,7 -140,7 +140,7 @@@ static int srrd_update(char *filename, 
    new_argv = malloc((new_argc + 1) * sizeof(*new_argv));
    if (new_argv == NULL) {
      ERROR("rrdtool plugin: malloc failed.");
 -    return (-1);
 +    return -1;
    }
  
    new_argv[0] = "update";
  
    sfree(new_argv);
  
 -  return (status);
 +  return status;
  } /* int srrd_update */
  #endif /* !HAVE_THREADSAFE_LIBRRD */
  
@@@ -177,9 -177,9 +177,9 @@@ static int value_list_to_string_multipl
    memset(buffer, '\0', buffer_len);
  
    tt = CDTIME_T_TO_TIME_T(vl->time);
 -  status = ssnprintf(buffer, buffer_len, "%u", (unsigned int)tt);
 +  status = snprintf(buffer, buffer_len, "%u", (unsigned int)tt);
    if ((status < 1) || (status >= buffer_len))
 -    return (-1);
 +    return -1;
    offset = status;
  
    for (size_t i = 0; i < ds->ds_num; i++) {
          (ds->ds[i].type != DS_TYPE_GAUGE) &&
          (ds->ds[i].type != DS_TYPE_DERIVE) &&
          (ds->ds[i].type != DS_TYPE_ABSOLUTE))
 -      return (-1);
 +      return -1;
  
      if (ds->ds[i].type == DS_TYPE_COUNTER)
 -      status = ssnprintf(buffer + offset, buffer_len - offset, ":%llu",
 -                         vl->values[i].counter);
 +      status = snprintf(buffer + offset, buffer_len - offset, ":%llu",
 +                        vl->values[i].counter);
      else if (ds->ds[i].type == DS_TYPE_GAUGE)
 -      status = ssnprintf(buffer + offset, buffer_len - offset, ":" GAUGE_FORMAT,
 -                         vl->values[i].gauge);
 +      status = snprintf(buffer + offset, buffer_len - offset, ":" GAUGE_FORMAT,
 +                        vl->values[i].gauge);
      else if (ds->ds[i].type == DS_TYPE_DERIVE)
 -      status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIi64,
 -                         vl->values[i].derive);
 +      status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIi64,
 +                        vl->values[i].derive);
      else /*if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */
 -      status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
 -                         vl->values[i].absolute);
 +      status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
 +                        vl->values[i].absolute);
  
      if ((status < 1) || (status >= (buffer_len - offset)))
 -      return (-1);
 +      return -1;
  
      offset += status;
    } /* for ds->ds_num */
  
 -  return (0);
 +  return 0;
  } /* int value_list_to_string_multiple */
  
  static int value_list_to_string(char *buffer, int buffer_len,
    time_t tt;
  
    if (ds->ds_num != 1)
 -    return (value_list_to_string_multiple(buffer, buffer_len, ds, vl));
 +    return value_list_to_string_multiple(buffer, buffer_len, ds, vl);
  
    tt = CDTIME_T_TO_TIME_T(vl->time);
    switch (ds->ds[0].type) {
    case DS_TYPE_DERIVE:
 -    status = ssnprintf(buffer, buffer_len, "%u:%" PRIi64, (unsigned)tt,
 -                       vl->values[0].derive);
 +    status = snprintf(buffer, buffer_len, "%u:%" PRIi64, (unsigned)tt,
 +                      vl->values[0].derive);
      break;
    case DS_TYPE_GAUGE:
 -    status = ssnprintf(buffer, buffer_len, "%u:" GAUGE_FORMAT, (unsigned)tt,
 -                       vl->values[0].gauge);
 +    status = snprintf(buffer, buffer_len, "%u:" GAUGE_FORMAT, (unsigned)tt,
 +                      vl->values[0].gauge);
      break;
    case DS_TYPE_COUNTER:
 -    status = ssnprintf(buffer, buffer_len, "%u:%llu", (unsigned)tt,
 -                       vl->values[0].counter);
 +    status = snprintf(buffer, buffer_len, "%u:%llu", (unsigned)tt,
 +                      vl->values[0].counter);
      break;
    case DS_TYPE_ABSOLUTE:
 -    status = ssnprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt,
 -                       vl->values[0].absolute);
 +    status = snprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt,
 +                      vl->values[0].absolute);
      break;
    default:
 -    return (EINVAL);
 +    return EINVAL;
    }
  
    if ((status < 1) || (status >= buffer_len))
 -    return (ENOMEM);
 +    return ENOMEM;
  
 -  return (0);
 +  return 0;
  } /* int value_list_to_string */
  
  static int value_list_to_filename(char *buffer, size_t buffer_size,
      size_t datadir_len = strlen(datadir) + 1;
  
      if (datadir_len >= buffer_size)
 -      return (ENOMEM);
 +      return ENOMEM;
  
      sstrncpy(buffer, datadir, buffer_size);
      buffer[datadir_len - 1] = '/';
  
    status = FORMAT_VL(buffer, buffer_size, vl);
    if (status != 0)
 -    return (status);
 +    return status;
  
    len = strlen(buffer);
    assert(len < buffer_size);
    buffer_size -= len;
  
    if (buffer_size <= sizeof(suffix))
 -    return (ENOMEM);
 +    return ENOMEM;
  
    memcpy(buffer, suffix, sizeof(suffix));
 -  return (0);
 +  return 0;
  } /* int value_list_to_filename */
  
  static void *rrd_queue_thread(void __attribute__((unused)) * data) {
    } /* while (42) */
  
    pthread_exit((void *)0);
 -  return ((void *)0);
 +  return (void *)0;
  } /* void *rrd_queue_thread */
  
  static int rrd_queue_enqueue(const char *filename, rrd_queue_t **head,
  
    queue_entry = malloc(sizeof(*queue_entry));
    if (queue_entry == NULL)
 -    return (-1);
 +    return -1;
  
    queue_entry->filename = strdup(filename);
    if (queue_entry->filename == NULL) {
      free(queue_entry);
 -    return (-1);
 +    return -1;
    }
  
    queue_entry->next = NULL;
    pthread_cond_signal(&queue_cond);
    pthread_mutex_unlock(&queue_lock);
  
 -  return (0);
 +  return 0;
  } /* int rrd_queue_enqueue */
  
  static int rrd_queue_dequeue(const char *filename, rrd_queue_t **head,
  
    if (this == NULL) {
      pthread_mutex_unlock(&queue_lock);
 -    return (-1);
 +    return -1;
    }
  
    if (prev == NULL)
    sfree(this->filename);
    sfree(this);
  
 -  return (0);
 +  return 0;
  } /* int rrd_queue_dequeue */
  
  /* XXX: You must hold "cache_lock" when calling this function! */
@@@ -505,7 -505,6 +505,6 @@@ static void rrd_cache_flush(cdtime_t ti
          CDTIME_T_TO_DOUBLE(timeout));
  
    now = cdtime();
-   timeout = TIME_T_TO_CDTIME_T(timeout);
  
    /* Build a list of entries to be flushed */
    iter = c_avl_get_iterator(cache);
@@@ -568,7 -567,7 +567,7 @@@ static int rrd_cache_flush_identifier(c
  
    if (identifier == NULL) {
      rrd_cache_flush(timeout);
 -    return (0);
 +    return 0;
    }
  
    now = cdtime();
      INFO("rrdtool plugin: rrd_cache_flush_identifier: "
           "c_avl_get (%s) failed. Does that file really exist?",
           key);
 -    return (status);
 +    return status;
    }
  
    if (rc->flags == FLAG_FLUSHQ) {
        rc->flags = FLAG_FLUSHQ;
    }
  
 -  return (status);
 +  return status;
  } /* int rrd_cache_flush_identifier */
  
  static int64_t rrd_get_random_variation(void) {
-   long min;
-   long max;
    if (random_timeout == 0)
 -    return (0);
 +    return 0;
  
-   /* Assure that "cache_timeout + random_variation" is never negative. */
-   if (random_timeout > cache_timeout) {
-     INFO("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.",
-          CDTIME_T_TO_DOUBLE(cache_timeout));
-     random_timeout = cache_timeout;
-   }
-   max = (long)(random_timeout / 2);
-   min = max - ((long)random_timeout);
-   return (int64_t)cdrand_range(min, max);
+   return (int64_t)cdrand_range(-random_timeout, random_timeout);
  } /* int64_t rrd_get_random_variation */
  
  static int rrd_cache_insert(const char *filename, const char *value,
    if (cache == NULL) {
      pthread_mutex_unlock(&cache_lock);
      WARNING("rrdtool plugin: cache == NULL.");
 -    return (-1);
 +    return -1;
    }
  
    c_avl_get(cache, filename, (void *)&rc);
      rc = malloc(sizeof(*rc));
      if (rc == NULL) {
        pthread_mutex_unlock(&cache_lock);
 -      return (-1);
 +      return -1;
      }
      rc->values_num = 0;
      rc->values = NULL;
      DEBUG("rrdtool plugin: (rc->last_value = %" PRIu64 ") "
            ">= (value_time = %" PRIu64 ")",
            rc->last_value, value_time);
 -    return (-1);
 +    return -1;
    }
  
    values_new =
      sfree(cache_key);
      sfree(rc->values);
      sfree(rc);
 -    return (-1);
 +    return -1;
    }
    rc->values = values_new;
  
        sfree(rc->values[0]);
        sfree(rc->values);
        sfree(rc);
 -      return (-1);
 +      return -1;
      }
  
      c_avl_insert(cache, cache_key, rc);
  
    if ((cache_timeout > 0) &&
        ((cdtime() - cache_flush_last) > cache_flush_timeout))
-     rrd_cache_flush(cache_flush_timeout);
+     rrd_cache_flush(cache_timeout + random_timeout);
  
    pthread_mutex_unlock(&cache_lock);
  
 -  return (0);
 +  return 0;
  } /* int rrd_cache_insert */
  
  static int rrd_cache_destroy(void) /* {{{ */
  
    if (cache == NULL) {
      pthread_mutex_unlock(&cache_lock);
 -    return (0);
 +    return 0;
    }
  
    while (c_avl_pick(cache, &key, &value) == 0) {
    }
  
    pthread_mutex_unlock(&cache_lock);
 -  return (0);
 +  return 0;
  } /* }}} int rrd_cache_destroy */
  
  static int rrd_compare_numeric(const void *a_ptr, const void *b_ptr) {
    int b = *((int *)b_ptr);
  
    if (a < b)
 -    return (-1);
 +    return -1;
    else if (a > b)
 -    return (1);
 +    return 1;
    else
 -    return (0);
 +    return 0;
  } /* int rrd_compare_numeric */
  
  static int rrd_write(const data_set_t *ds, const value_list_t *vl,
    int status;
  
    if (do_shutdown)
 -    return (0);
 +    return 0;
  
    if (0 != strcmp(ds->type, vl->type)) {
      ERROR("rrdtool plugin: DS type does not match value list type");
    }
  
    if (value_list_to_filename(filename, sizeof(filename), vl) != 0)
 -    return (-1);
 +    return -1;
  
    if (value_list_to_string(values, sizeof(values), ds, vl) != 0)
 -    return (-1);
 +    return -1;
  
    if (stat(filename, &statbuf) == -1) {
      if (errno == ENOENT) {
        status = cu_rrd_create_file(filename, ds, vl, &rrdcreate_config);
        if (status != 0)
 -        return (-1);
 +        return -1;
        else if (rrdcreate_config.async)
 -        return (0);
 +        return 0;
      } else {
        char errbuf[1024];
        ERROR("stat(%s) failed: %s", filename,
              sstrerror(errno, errbuf, sizeof(errbuf)));
 -      return (-1);
 +      return -1;
      }
    } else if (!S_ISREG(statbuf.st_mode)) {
      ERROR("stat(%s): Not a regular file!", filename);
 -    return (-1);
 +    return -1;
    }
  
    status = rrd_cache_insert(filename, values, vl->time);
  
 -  return (status);
 +  return status;
  } /* int rrd_write */
  
  static int rrd_flush(cdtime_t timeout, const char *identifier,
  
    if (cache == NULL) {
      pthread_mutex_unlock(&cache_lock);
 -    return (0);
 +    return 0;
    }
  
    rrd_cache_flush_identifier(timeout, identifier);
  
    pthread_mutex_unlock(&cache_lock);
 -  return (0);
 +  return 0;
  } /* int rrd_flush */
  
  static int rrd_config(const char *key, const char *value) {
                        "be greater than 0.\n");
        ERROR("rrdtool: `CacheTimeout' must "
              "be greater than 0.\n");
 -      return (1);
 +      return 1;
      }
      cache_timeout = DOUBLE_TO_CDTIME_T(tmp);
    } else if (strcasecmp("CacheFlush", key) == 0) {
-     int tmp = atoi(value);
+     double tmp = atof(value);
      if (tmp < 0) {
        fprintf(stderr, "rrdtool: `CacheFlush' must "
                        "be greater than 0.\n");
        ERROR("rrdtool: `CacheFlush' must "
              "be greater than 0.\n");
 -      return (1);
 +      return 1;
      }
-     cache_flush_timeout = tmp;
+     cache_flush_timeout = DOUBLE_TO_CDTIME_T(tmp);
    } else if (strcasecmp("DataDir", key) == 0) {
      char *tmp;
      size_t len;
      tmp = strdup(value);
      if (tmp == NULL) {
        ERROR("rrdtool plugin: strdup failed.");
 -      return (1);
 +      return 1;
      }
  
      len = strlen(tmp);
      if (len == 0) {
        ERROR("rrdtool plugin: Invalid \"DataDir\" option.");
        sfree(tmp);
 -      return (1);
 +      return 1;
      }
  
      if (datadir != NULL) {
                        "be greater than 0.\n");
        ERROR("rrdtool: `RRARows' must "
              "be greater than 0.\n");
 -      return (1);
 +      return 1;
      }
      rrdcreate_config.rrarows = tmp;
    } else if (strcasecmp("RRATimespan", key) == 0) {
  
      value_copy = strdup(value);
      if (value_copy == NULL)
 -      return (1);
 +      return 1;
  
      dummy = value_copy;
      while ((ptr = strtok_r(dummy, ", \t", &saveptr)) != NULL) {
          fprintf(stderr, "rrdtool: realloc failed.\n");
          ERROR("rrdtool: realloc failed.\n");
          free(value_copy);
 -        return (1);
 +        return 1;
        }
        rrdcreate_config.timespans = tmp_alloc;
        rrdcreate_config.timespans[rrdcreate_config.timespans_num] = atoi(ptr);
                        "be in the range 0 to 1 (exclusive).");
        ERROR("rrdtool: `XFF' must "
              "be in the range 0 to 1 (exclusive).");
 -      return (1);
 +      return 1;
      }
      rrdcreate_config.xff = tmp;
    } else if (strcasecmp("WritesPerSecond", key) == 0) {
      if (wps < 0.0) {
        fprintf(stderr, "rrdtool: `WritesPerSecond' must be "
                        "greater than or equal to zero.");
 -      return (1);
 +      return 1;
      } else if (wps == 0.0) {
        write_rate = 0.0;
      } else {
        random_timeout = DOUBLE_TO_CDTIME_T(tmp);
      }
    } else {
 -    return (-1);
 +    return -1;
    }
 -  return (0);
 +  return 0;
  } /* int rrd_config */
  
  static int rrd_shutdown(void) {
  
    rrd_cache_destroy();
  
 -  return (0);
 +  return 0;
  } /* int rrd_shutdown */
  
  static int rrd_init(void) {
    int status;
  
    if (init_once != 0)
 -    return (0);
 +    return 0;
    init_once = 1;
  
    if (rrdcreate_config.heartbeat <= 0)
    if (cache == NULL) {
      pthread_mutex_unlock(&cache_lock);
      ERROR("rrdtool plugin: c_avl_create failed.");
 -    return (-1);
 +    return -1;
    }
  
    cache_flush_last = cdtime();
    if (cache_timeout == 0) {
+     random_timeout = 0;
      cache_flush_timeout = 0;
-   } else if (cache_flush_timeout < cache_timeout)
+   } else if (cache_flush_timeout < cache_timeout) {
+     INFO("rrdtool plugin: \"CacheFlush %.3f\" is less than \"CacheTimeout %.3f\". "
+          "Ajusting \"CacheFlush\" to %.3f seconds.",
+          CDTIME_T_TO_DOUBLE(cache_flush_timeout),
+          CDTIME_T_TO_DOUBLE(cache_timeout),
+          CDTIME_T_TO_DOUBLE(cache_timeout * 10));
      cache_flush_timeout = 10 * cache_timeout;
+   }
+   /* Assure that "cache_timeout + random_variation" is never negative. */
+   if (random_timeout > cache_timeout) {
+     INFO("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.",
+          CDTIME_T_TO_DOUBLE(cache_timeout));
+     random_timeout = cache_timeout;
+   }
  
    pthread_mutex_unlock(&cache_lock);
  
                             /* args = */ NULL, "rrdtool queue");
    if (status != 0) {
      ERROR("rrdtool plugin: Cannot create queue-thread.");
 -    return (-1);
 +    return -1;
    }
    queue_thread_running = 1;
  
          rrdcreate_config.heartbeat, rrdcreate_config.rrarows,
          rrdcreate_config.xff);
  
 -  return (0);
 +  return 0;
  } /* int rrd_init */
  
  void module_register(void) {