Merge branch 'collectd-5.8'
authorFlorian Forster <octo@collectd.org>
Sun, 10 Feb 2019 20:50:51 +0000 (21:50 +0100)
committerFlorian Forster <octo@collectd.org>
Sun, 10 Feb 2019 21:01:25 +0000 (22:01 +0100)
Conflicts:
src/sensors.c

1  2 
src/collectd.conf.pod
src/daemon/common.c
src/log_logstash.c
src/sensors.c
src/write_prometheus.c

diff --combined src/collectd.conf.pod
@@@ -530,9 -530,9 +530,9 @@@ are disabled by default
  =head2 Plugin C<amqp>
  
  The I<AMQP plugin> can be used to communicate with other instances of
 -I<collectd> or third party applications using an AMQP message broker. Values
 -are sent to or received from the broker, which handles routing, queueing and
 -possibly filtering out messages.
 +I<collectd> or third party applications using an AMQP 0.9.1 message broker.
 +Values are sent to or received from the broker, which handles routing,
 +queueing and possibly filtering out messages.
  
  B<Synopsis:>
  
@@@ -738,171 -738,6 +738,171 @@@ is preserved, i.e. passed through
  
  =back
  
 +=head2 Plugin C<amqp1>
 +
 +The I<AMQP1 plugin> can be used to communicate with other instances of
 +I<collectd> or third party applications using an AMQP 1.0 message
 +intermediary. Metric values or notifications are sent to the
 +messaging intermediary which may handle direct messaging or
 +queue based transfer.
 +
 +B<Synopsis:>
 +
 + <Plugin "amqp1">
 +   # Send values to an AMQP 1.0 intermediary
 +  <Transport "name">
 +    Host "localhost"
 +    Port "5672"
 +    User "guest"
 +    Password "guest"
 +    Address "collectd"
 +#    RetryDelay 1
 +    <Instance "some_name">
 +        Format "command"
 +        PreSettle false
 +        Notify false
 + #      StoreRates false
 + #      GraphitePrefix "collectd."
 + #      GraphiteEscapeChar "_"
 + #      GraphiteSeparateInstances false
 + #      GraphiteAlwaysAppendDS false
 + #      GraphitePreserveSeparator false
 +    </Instance>
 +  </Transport>
 + </Plugin>
 +
 +The plugin's configuration consists of a I<Transport> that configures
 +communications to the AMQP 1.0 messaging bus and one or more I<Instance>
 +corresponding to metric or event publishers to the messaging system.
 +
 +The address in the I<Transport> block concatenated with the name given in the
 +I<Instance> block starting tag will be used as the send-to address for
 +communications over the messaging link.
 +
 +The following options are accepted within each I<Transport> block:
 +
 +=over 4
 +
 +=item B<Host> I<Host>
 +
 +Hostname or IP-address of the AMQP 1.0 intermediary. Defaults to the
 +default behavior of the underlying communications library,
 +I<libqpid-proton>, which is "localhost".
 +
 +=item B<Port> I<Port>
 +
 +Service name or port number on which the AMQP 1.0 intermediary accepts
 +connections. This argument must be a string, even if the numeric form
 +is used. Defaults to "5672".
 +
 +=item B<User> I<User>
 +
 +=item B<Password> I<Password>
 +
 +Credentials used to authenticate to the AMQP 1.0 intermediary. By
 +default "guest"/"guest" is used.
 +
 +=item B<Address> I<Address>
 +
 +This option specifies the prefix for the send-to value in the message.
 +By default, "collectd" will be used.
 +
 +=item B<RetryDelay> I<RetryDelay>
 +
 +When the AMQP1 connection is lost, defines the time in seconds to wait
 +before attempting to reconnect. Defaults to 1, which implies attempt
 +to reconnect at 1 second intervals.
 +
 +=back
 +
 +The following options are accepted within each I<Instance> block:
 +
 +=over 4
 +
 +=item B<Format> B<Command>|B<JSON>|B<Graphite>
 +
 +Selects the format in which messages are sent to the intermediary. If set to
 +B<Command> (the default), values are sent as C<PUTVAL> commands which are
 +identical to the syntax used by the I<Exec> and I<UnixSock plugins>. In this
 +case, the C<Content-Type> header field will be set to C<text/collectd>.
 +
 +If set to B<JSON>, the values are encoded in the I<JavaScript Object Notation>,
 +an easy and straight forward exchange format. The C<Content-Type> header field
 +will be set to C<application/json>.
 +
 +If set to B<Graphite>, values are encoded in the I<Graphite> format, which is
 +"<metric> <value> <timestamp>\n". The C<Content-Type> header field will be set to
 +C<text/graphite>.
 +
 +A subscribing client I<should> use the C<Content-Type> header field to
 +determine how to decode the values.
 +
 +=item B<PreSettle> B<true>|B<false>
 +
 +If set to B<false> (the default), the plugin will wait for a message
 +acknowledgement from the messaging bus before sending the next
 +message. This indicates transfer of ownership to the messaging
 +system. If set to B<true>, the plugin will not wait for a message
 +acknowledgement and the message may be dropped prior to transfer of
 +ownership.
 +
 +=item B<Notify> B<true>|B<false>
 +
 +If set to B<false> (the default), the plugin will service the
 +instance write call back as a value list. If set to B<true> the
 +plugin will service the instance as a write notification callback
 +for alert formatting.
 +
 +=item B<StoreRates> B<true>|B<false>
 +
 +Determines whether or not C<COUNTER>, C<DERIVE> and C<ABSOLUTE> data sources
 +are converted to a I<rate> (i.e. a C<GAUGE> value). If set to B<false> (the
 +default), no conversion is performed. Otherwise the conversion is performed
 +using the internal value cache.
 +
 +Please note that currently this option is only used if the B<Format> option has
 +been set to B<JSON>.
 +
 +=item B<GraphitePrefix>
 +
 +A prefix can be added in the metric name when outputting in the I<Graphite> format.
 +It's added before the I<Host> name.
 +Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +
 +=item B<GraphitePostfix>
 +
 +A postfix can be added in the metric name when outputting in the I<Graphite> format.
 +It's added after the I<Host> name.
 +Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +
 +=item B<GraphiteEscapeChar>
 +
 +Specify a character to replace dots (.) in the host part of the metric name.
 +In I<Graphite> metric name, dots are used as separators between different
 +metric parts (host, plugin, type).
 +Default is "_" (I<Underscore>).
 +
 +=item B<GraphiteSeparateInstances> B<true>|B<false>
 +
 +If set to B<true>, the plugin instance and type instance will be in their own
 +path component, for example C<host.cpu.0.cpu.idle>. If set to B<false> (the
 +default), the plugin and plugin instance (and likewise the type and type
 +instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
 +
 +=item B<GraphiteAlwaysAppendDS> B<true>|B<false>
 +
 +If set to B<true>, append the name of the I<Data Source> (DS) to the "metric"
 +identifier. If set to B<false> (the default), this is only done when there is
 +more than one DS.
 +
 +=item B<GraphitePreserveSeparator> B<false>|B<true>
 +
 +If set to B<false> (the default) the C<.> (dot) character is replaced with
 +I<GraphiteEscapeChar>. Otherwise, if set to B<true>, the C<.> (dot) character
 +is preserved, i.e. passed through.
 +
 +=back
 +
  =head2 Plugin C<apache>
  
  To configure the C<apache>-plugin you first need to configure the Apache
@@@ -1662,10 -1497,6 +1662,10 @@@ installed) to get the current CPU frequ
  sure B<cpufreqd> (L<http://cpufreqd.sourceforge.net/>) or a similar tool is
  installed and an "cpu governor" (that's a kernel module) is loaded.
  
 +If the system has the I<cpufreq-stats> kernel module loaded, this plugin reports
 +the rate of p-state (cpu frequency) transitions and the percentage of time spent
 +in each p-state.
 +
  =head2 Plugin C<cpusleep>
  
  This plugin doesn't have any options. It reads CLOCK_BOOTTIME and
@@@ -1912,11 -1743,6 +1912,11 @@@ plugin below on how matches are defined
  B<MeasureResponseCode> options are set to B<true>, B<Match> blocks are
  optional.
  
 +=item B<Interval> I<Interval>
 +
 +Sets the interval (in seconds) in which the values will be collected from this
 +URL. By default the global B<Interval> setting will be used.
 +
  =item B<Timeout> I<Milliseconds>
  
  The B<Timeout> option sets the overall timeout for HTTP requests to B<URL>, in
@@@ -2113,11 -1939,6 +2113,11 @@@ Use I<Instance> as the plugin instance 
  May be overridden by B<PluginInstanceFrom> option inside B<XPath> blocks.
  Defaults to an empty string (no plugin instance).
  
 +=item B<Interval> I<Interval>
 +
 +Sets the interval (in seconds) in which the values will be collected from this
 +URL. By default the global B<Interval> setting will be used.
 +
  =item B<Namespace> I<Prefix> I<URL>
  
  If an XPath expression references namespaces, they must be specified
@@@ -3210,30 -3031,6 +3210,30 @@@ Pause to apply between attempts of conn
  
  =back
  
 +=head2 Plugin C<gpu_nvidia>
 +
 +Efficiently collects various statistics from the system's NVIDIA GPUs using the
 +NVML library. Currently collected are fan speed, core temperature, percent
 +load, percent memory used, compute and memory frequencies, and power
 +consumption.
 +
 +=over 4
 +
 +=item B<GPUIndex>
 +
 +If one or more of these options is specified, only GPUs at that index (as
 +determined by nvidia-utils through I<nvidia-smi>) have statistics collected.
 +If no instance of this option is specified, all GPUs are monitored.
 +
 +=item B<IgnoreSelected>
 +
 +If set to true, all detected GPUs B<except> the ones at indices specified by
 +B<GPUIndex> entries are collected. For greater clarity, setting IgnoreSelected
 +without any GPUIndex directives will result in B<no> statistics being
 +collected.
 +
 +=back
 +
  =head2 Plugin C<grpc>
  
  The I<grpc> plugin provides an RPC interface to submit values to or query
@@@ -3297,13 -3094,6 +3297,13 @@@ Whether to enable SSL for incoming conn
  Filenames specifying SSL certificate and key material to be used with SSL
  connections.
  
 +=item B<VerifyPeer> B<true>|B<false>
 +
 +When enabled, a valid client certificate is required to connect to the server.
 +When disabled, a client certifiacte is not requested and any unsolicited client
 +certificate is accepted.
 +Enabled by default.
 +
  =back
  
  =back
@@@ -3674,23 -3464,8 +3674,23 @@@ a notification is sent. Defaults to B<f
  
  If system event log (SEL) is enabled, plugin will listen for sensor threshold
  and discrete events. When event is received the notification is sent.
 +SEL event filtering can be configured using B<SELSensor> and B<SELIgnoreSelected>
 +config options.
  Defaults to B<false>.
  
 +=item B<SELSensor> I<SELSensor>
 +
 +Selects sensors to get events from or to ignore, depending on B<SELIgnoreSelected>.
 +
 +See F</"IGNORELISTS"> for details.
 +
 +=item B<SELIgnoreSelected> I<true>|I<false>
 +
 +If no configuration is given, the B<ipmi> plugin will pass events from all
 +sensors. This option enables you to do that: By setting B<SELIgnoreSelected>
 +to I<true> the effect of B<SELSensor> is inverted: All events from selected
 +sensors are ignored and all events from other sensors are passed.
 +
  =item B<SELClearEvent> I<true>|I<false>
  
  If SEL clear event is enabled, plugin will delete event from SEL list after
@@@ -4295,9 -4070,8 +4295,9 @@@ which the sizes of physical memory vary
  
  The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP or Modbus/RTU and
  reads register values. It supports reading single registers (unsigned 16E<nbsp>bit
 -values), large integer values (unsigned 32E<nbsp>bit values) and floating point
 -values (two registers interpreted as IEEE floats in big endian notation).
 +values), large integer values (unsigned 32E<nbsp>bit and 64E<nbsp>bit values) and
 +floating point values (two registers interpreted as IEEE floats in big endian
 +notation).
  
  B<Synopsis:>
  
     RegisterCmd ReadHolding
     Type voltage
     Instance "input-1"
 +   #Scale 1.0
 +   #Shift 0.0
   </Data>
  
   <Data "voltage-input-2">
@@@ -4367,22 -4139,11 +4367,22 @@@ Configures the base register to read fr
  B<RegisterType> has been set to B<Uint32> or B<Float>, this and the next
  register will be read (the register number is increased by one).
  
 -=item B<RegisterType> B<Int16>|B<Int32>|B<Uint16>|B<Uint32>|B<Float>
 -
 -Specifies what kind of data is returned by the device. If the type is B<Int32>,
 -B<Uint32> or B<Float>, two 16E<nbsp>bit registers will be read and the data is
 -combined into one value. Defaults to B<Uint16>.
 +=item B<RegisterType> B<Int16>|B<Int32>|B<Int64>|B<Uint16>|B<Uint32>|B<UInt64>|B<Float>|B<Int32LE>|B<Uint32LE>|B<FloatLE>
 +
 +Specifies what kind of data is returned by the device. This defaults to
 +B<Uint16>.  If the type is B<Int32>, B<Int32LE>, B<Uint32>, B<Uint32LE>,
 +B<Float> or B<FloatLE>, two 16E<nbsp>bit registers at B<RegisterBase>
 +and B<RegisterBase+1> will be read and the data is combined into one
 +32E<nbsp>value. For B<Int32>, B<Uint32> and B<Float> the most significant
 +16E<nbsp>bits are in the register at B<RegisterBase> and the least
 +significant 16E<nbsp>bits are in the register at B<RegisterBase+1>.
 +For B<Int32LE>, B<Uint32LE>, or B<Float32LE>, the high and low order
 +registers are swapped with the most significant 16E<nbsp>bits in
 +the B<RegisterBase+1> and the least significant 16E<nbsp>bits in
 +B<RegisterBase>. If the type is B<Int64> or B<UInt64>, four 16E<nbsp>bit
 +registers at B<RegisterBase>, B<RegisterBase+1>, B<RegisterBase+2> and
 +B<RegisterBase+3> will be read and the data combined into one
 +64E<nbsp>value.
  
  =item B<RegisterCmd> B<ReadHolding>|B<ReadInput>
  
@@@ -4397,19 -4158,9 +4397,19 @@@ supported
  
  =item B<Instance> I<Instance>
  
 -Sets the type instance to use when dispatching the value to I<collectd>. If
 +Sets the type instance to use when dispatching the value to I<Instance>. If
  unset, an empty string (no type instance) is used.
  
 +=item B<Scale> I<Value>
 +
 +The values taken from device 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 device after they have been multiplied by
 +B<Scale> value. The field is optional and the default value is B<0.0>.
 +
  =back
  
  =item E<lt>B<Host> I<Name>E<gt> blocks
@@@ -5333,9 -5084,8 +5333,9 @@@ When configuring with B<Interface> onl
  namely octets, packets, and errors. These statistics are collected by
  the C<interface> plugin, too, so using both at the same time is no benefit.
  
 -When configured with B<VerboseInterface> all counters B<except> the basic ones,
 -so that no data needs to be collected twice if you use the C<interface> plugin.
 +When configured with B<VerboseInterface> all counters B<except> the basic ones
 +will be collected, so that no data needs to be collected twice if you use the
 +C<interface> plugin.
  This includes dropped packets, received multicast packets, collisions and a
  whole zoo of differentiated RX and TX errors. You can try the following command
  to get an idea of what awaits you:
@@@ -5477,12 -5227,6 +5477,12 @@@ behavior is to let the kernel choose th
  that the manual selection of an interface for unicast traffic is only
  necessary in rare cases.
  
 +=item B<BindAddress> I<IP Address>
 +
 +Set the outgoing IP address for IP packets. This option can be used instead of
 +the I<Interface> option to explicitly define the IP address which will be used
 +to send Packets to the remote server. 
 +
  =item B<ResolveInterval> I<Seconds>
  
  Sets the interval at which to re-resolve the DNS for the I<Host>. This is
@@@ -6275,7 -6019,6 +6275,7 @@@ B<Synopsis:
     Address "127.0.0.1"
     Socket "/var/run/openvswitch/db.sock"
     Bridges "br0" "br_ext"
 +   InterfaceStats false
   </Plugin>
  
  The plugin provides the following configuration options:
@@@ -6309,59 -6052,6 +6309,59 @@@ omitted or is empty then all OVS bridge
  
  Default: empty (monitor all bridges)
  
 +=item B<InterfaceStats> B<false>|B<true>
 +
 +Indicates that the plugin should gather statistics for individual interfaces
 +in addition to ports.  This can be useful when monitoring an OVS setup with
 +bond ports, where you might wish to know individual statistics for the
 +interfaces included in the bonds.  Defaults to B<false>.
 +
 +=back
 +
 +=head2 Plugin C<pcie_errors>
 +
 +The I<pcie_errors> plugin collects PCI Express errors from Device Status in Capability
 +structure and from Advanced Error Reporting Extended Capability where available.
 +At every read it polls config space of PCI Express devices and dispatches
 +notification for every error that is set. It checks for new errors at every read.
 +The device is indicated in plugin_instance according to format "domain:bus:dev.fn".
 +Errors are divided into categories indicated by type_instance: "correctable", and
 +for uncorrectable errors "non_fatal" or "fatal".
 +Fatal errors are reported as I<NOTIF_FAILURE> and all others as I<NOTIF_WARNING>.
 +
 +B<Synopsis:>
 +
 +  <Plugin "pcie_errors">
 +    Source "sysfs"
 +    AccessDir "/sys/bus/pci"
 +    ReportMasked false
 +    PersistentNotifications false
 +  </Plugin>
 +
 +B<Options:>
 +
 +=over 4
 +
 +=item B<Source> B<sysfs>|B<proc>
 +
 +Use B<sysfs> or B<proc> to read data from /sysfs or /proc.
 +The default value is B<sysfs>.
 +
 +=item B<AccessDir> I<dir>
 +
 +Directory used to access device config space. It is optional and defaults to
 +/sys/bus/pci for B<sysfs> and to /proc/bus/pci for B<proc>.
 +
 +=item B<ReportMasked> B<false>|B<true>
 +
 +If true plugin will notify about errors that are set to masked in Error Mask register.
 +Such errors are not reported to the PCI Express Root Complex. Defaults to B<false>.
 +
 +=item B<PersistentNotifications> B<false>|B<true>
 +
 +If false plugin will dispatch notification only on set/clear of error.
 +The ones already reported will be ignored. Defaults to B<false>.
 +
  =back
  
  =head2 Plugin C<perl>
@@@ -6498,11 -6188,6 +6498,11 @@@ long string is used so that the packet 
  Sets the source address to use. I<host> may either be a numerical network
  address or a network hostname.
  
 +=item B<AddressFamily> I<af>
 +
 +Sets the address family to use. I<af> may be "any", "ipv4" or "ipv6". This
 +option will be ignored if you set a B<SourceAddress>.
 +
  =item B<Device> I<name>
  
  Sets the outgoing network device to be used. I<name> has to specify an
@@@ -7175,21 -6860,18 +7175,21 @@@ The statistics collected for matched pr
   - number of memory mapped files (under Linux)
   - io data (where available)
   - context switches (under Linux)
 - - minor and major pagefaults.
 + - minor and major pagefaults
 + - Delay Accounting information (Linux only, requires libmnl)
  
  B<Synopsis:>
  
   <Plugin processes>
 -   CollectFileDescriptor true
 -   CollectContextSwitch true
 +   CollectFileDescriptor  true
 +   CollectContextSwitch   true
 +   CollectDelayAccounting false
     Process "name"
     ProcessMatch "name" "regex"
     <Process "collectd">
 -     CollectFileDescriptor false
 -     CollectContextSwitch false
 +     CollectFileDescriptor  false
 +     CollectContextSwitch   false
 +     CollectDelayAccounting true
     </Process>
     <ProcessMatch "name" "regex">
       CollectFileDescriptor false
@@@ -7219,18 -6901,6 +7219,18 @@@ I<name> must not contain slashes
  Collect the number of context switches for matched processes.
  Disabled by default.
  
 +=item B<CollectDelayAccounting> I<Boolean>
 +
 +If enabled, collect Linux Delay Accounding information for matching processes.
 +Delay Accounting provides the time processes wait for the CPU to become
 +available, for I/O operations to finish, for pages to be swapped in and for
 +freed pages to be reclaimed. The metrics are reported as "seconds per second"
 +using the C<delay_rate> type, e.g. C<delay_rate-delay-cpu>.
 +Disabled by default.
 +
 +This option is only available on Linux, requires the C<libmnl> library and
 +requires the C<CAP_NET_ADMIN> capability at runtime.
 +
  =item B<CollectFileDescriptor> I<Boolean>
  
  Collect number of file descriptors of matched processes.
@@@ -7244,12 -6914,9 +7244,12 @@@ the Linux kernel
  
  =back
  
 -Options B<CollectContextSwitch> and B<CollectFileDescriptor> may be used inside
 -B<Process> and B<ProcessMatch> blocks - then they affect corresponding match
 -only. Otherwise they set the default value for subsequent matches.
 +The B<CollectContextSwitch>, B<CollectDelayAccounting>,
 +B<CollectFileDescriptor> and B<CollectMemoryMaps> options may be used inside
 +B<Process> and B<ProcessMatch> blocks. When used there, these options affect
 +reporting the corresponding processes only. Outside of B<Process> and
 +B<ProcessMatch> blocks these options set the default value for subsequent
 +matches.
  
  =head2 Plugin C<protocols>
  
@@@ -7316,7 -6983,6 +7316,7 @@@ multiple routers
        CollectRegistrationTable true
        CollectDF true
        CollectDisk true
 +      CollectHealth true
      </Router>
    </Plugin>
  
@@@ -7377,37 -7043,29 +7377,37 @@@ Defaults to B<false>
  When enabled, the number of sectors written and bad blocks will be collected.
  Defaults to B<false>.
  
 +=item B<CollectHealth> B<true>|B<false>
 +
 +When enabled, the health statistics will be collected. This includes the
 +voltage and temperature on supported hardware.
 +Defaults to B<false>.
 +
  =back
  
  =head2 Plugin C<redis>
  
 -The I<Redis plugin> connects to one or more Redis servers and gathers
 -information about each server's state. For each server there is a I<Node> block
 -which configures the connection parameters for this node.
 +The I<Redis plugin> connects to one or more Redis servers, gathers
 +information about each server's state and executes user-defined queries.
 +For each server there is a I<Node> block which configures the connection
 +parameters and set of user-defined queries for this node.
  
    <Plugin redis>
      <Node "example">
          Host "localhost"
          Port "6379"
 +        #Socket "/var/run/redis/redis.sock"
          Timeout 2000
 +        ReportCommandStats false
 +        ReportCpuUsage true
          <Query "LLEN myqueue">
 +          #Database 0
            Type "queue_length"
            Instance "myqueue"
 -        <Query>
 +        </Query>
      </Node>
    </Plugin>
  
 -The information shown in the synopsis above is the I<default configuration>
 -which is used by the plugin if no configuration is present.
 -
  =over 4
  
  =item B<Node> I<Nodename>
  The B<Node> block identifies a new Redis node, that is a new Redis instance
  running in an specified host and port. The name for node is a canonical
  identifier which is used as I<plugin instance>. It is limited to
 -64E<nbsp>characters in length.
 +128E<nbsp>characters in length.
 +
 +When no B<Node> is configured explicitly, plugin connects to "localhost:6379".
  
  =item B<Host> I<Hostname>
  
@@@ -7430,11 -7086,6 +7430,11 @@@ The B<Port> option is the TCP port on w
  connections. Either a service name of a port number may be given. Please note
  that numerical port numbers must be given as a string, too.
  
 +=item B<Socket> I<Path>
 +
 +Connect to Redis using the UNIX domain socket at I<Path>. If this
 +setting is given, the B<Hostname> and B<Port> settings are ignored.
 +
  =item B<Password> I<Password>
  
  Use I<Password> to authenticate when connecting to I<Redis>.
  =item B<Timeout> I<Milliseconds>
  
  The B<Timeout> option set the socket timeout for node response. Since the Redis
 -read function is blocking, you should keep this value as low as possible. Keep
 -in mind that the sum of all B<Timeout> values for all B<Nodes> should be lower
 -than B<Interval> defined globally.
 +read function is blocking, you should keep this value as low as possible.
 +It is expected what B<Timeout> values should be lower than B<Interval> defined
 +globally.
 +
 +Defaults to 2000 (2 seconds).
 +
 +=item B<ReportCommandStats> B<false>|B<true>
 +
 +Enables or disables reporting of statistics based on the command type, including
 +rate of command calls and average CPU time consumed by command processing.
 +Defaults to B<false>.
 +
 +=item B<ReportCpuUsage> B<true>|B<false>
 +
 +Enables or disables reporting of CPU consumption statistics.
 +Defaults to B<true>.
  
  =item B<Query> I<Querystring>
  
  The B<Query> block identifies a query to execute against the redis server.
 -There may be an arbitrary number of queries to execute.
 +There may be an arbitrary number of queries to execute. Each query should
 +return single string or integer.
  
  =item B<Type> I<Collectd type>
  
 -Within a query definition, a valid collectd type to use as when submitting
 +Within a query definition, a valid I<collectd type> to use as when submitting
  the result of the query. When not supplied, will default to B<gauge>.
  
 +Currently only types with one datasource are supported.
 +See L<types.db(5)> for more details on types and their configuration.
 +
  =item B<Instance> I<Type instance>
  
  Within a query definition, an optional type instance to use when submitting
  the result of the query. When not supplied will default to the escaped
 -command, up to 64 chars.
 +command, up to 128 chars.
 +
 +=item B<Database> I<Index>
 +
 +This index selects the Redis logical database to use for query. Defaults
 +to C<0>.
  
  =back
  
@@@ -7922,9 -7551,7 +7922,9 @@@ B<Synopsis:
        IndexOID "IF-MIB::ifIndex"
        SizeOID "IF-MIB::ifNumber"
        <Data "ifDescr">
 -        Instance true
 +        <IndexKey>
 +          Source "PluginInstance"
 +        </IndexKey>
          Plugin "interface"
          OIDs "IF-MIB::ifDescr"
        </Data>
          OIDs "IF-MIB::ifInOctets" "IF-MIB::ifOutOctets"
        </Data>
      </Table>
 +    <Table "CPUAffinityTable">
 +      <Data "DomainName">
 +        <IndexKey>
 +          Source "PluginInstance"
 +        </IndexKey>
 +        Plugin "virt"
 +        OIDs "LIBVIRT-HYPERVISOR-MIB::lvhAffinityDomainName"
 +      </Data>
 +      <Data "VCPU">
 +        Plugin "virt"
 +        <IndexKey>
 +          Source "TypeInstance"
 +          Regex "^vcpu_([0-9]{1,3})-cpu_[0-9]{1,3}$"
 +          Group 1
 +        </IndexKey>
 +        OIDs "LIBVIRT-HYPERVISOR-MIB::lvhVCPUIndex"
 +      </Data>
 +      <Data "CPU">
 +        Plugin "virt"
 +        <IndexKey>
 +          Source "TypeInstance"
 +          Regex "^vcpu_[0-9]{1,3}-cpu_([0-9]{1,3})$"
 +          Group 1
 +        </IndexKey>
 +        OIDs "LIBVIRT-HYPERVISOR-MIB::lvhCPUIndex"
 +      </Data>
 +      <Data "CPUAffinity">
 +        Plugin "virt"
 +        Type "cpu_affinity"
 +        OIDs "LIBVIRT-HYPERVISOR-MIB::lvhCPUAffinity"
 +      </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
 +=head3 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>
@@@ -7981,34 -7576,11 +7981,34 @@@ The following options can be set
  
  =over 4
  
 -=item B<Instance> I<true|false>
 +=item B<IndexKey> block
 +
 +B<IndexKey> block contains all data needed for proper index build of snmp table.
 +In case more than
 +one table B<Data> block has B<IndexKey> block present then multiple key index is
 +built. If B<Data> block defines scalar data type B<IndexKey> has no effect and can
 +be omitted.
 +
 +=over 8
 +
 +=item B<Source> I<String>
  
 -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.
 +B<Source> can be set to one of the following values: "Hostname", "Plugin",
 +"PluginInstance", "Type", "TypeInstance". This value indicates which field of
 +corresponding collectd metric is taken as a SNMP table index.
 +
 +=item B<Regex> I<String>
 +
 +B<Regex> option can also be used to parse strings or numbers out of
 +specific field. For example: type-instance field which is "vcpu1-cpu2" can be
 +parsed into two numeric fields CPU = 2 and VCPU = 1 and can be later used
 +as a table index.
 +
 +=item B<Group> I<Number>
 +
 +B<Group> number can be specified in case groups are used in regex.
 +
 +=back
  
  =item B<Plugin> I<String>
  
@@@ -8397,26 -7969,26 +8397,26 @@@ Sets how the values are cumulated. I<Ty
  
  =item B<GaugeAverage>
  
- Calculate the average.
+ Calculate the average of all values matched during the interval.
  
  =item B<GaugeMin>
  
Use the smallest number only.
Report the smallest value matched during the interval.
  
  =item B<GaugeMax>
  
Use the greatest number only.
Report the greatest value matched during the interval.
  
  =item B<GaugeLast>
  
Use the last number found.
Report the last value matched during the interval.
  
  =item B<GaugePersist>
  
- Use the last number found. The number is not reset at the end of an interval.
- It is continously reported until another number is matched. This is intended
for cases in which only state changes are reported, for example a thermometer
- that only reports the temperature when it changes.
+ Report the last matching value. The metric is I<not> reset to C<NaN> at the end
+ of an interval. It is continuously reported until another value is matched.
This is intended for cases in which only state changes are reported, for
example a thermometer that only reports the temperature when it changes.
  
  =item B<CounterSet>
  
@@@ -8447,6 -8019,9 +8447,9 @@@ Increase the internal counter by one. T
  not use the matched subexpression, but simply count the number of matched
  lines. Thus, you may use a regular expression without submatch in this case.
  
+ B<GaugeInc> is reset to I<zero> after every read, unlike other B<Gauge*>
+ metrics which are reset to C<NaN>.
  =item B<Distribution>
  
  Type to do calculations based on the distribution of values, primarily
@@@ -8520,8 -8095,12 +8523,12 @@@ The B<Gauge*> and B<Distribution> type
  point number, using L<strtod(3)>. The B<Counter*> and B<AbsoluteSet> types
  interpret the submatch as an unsigned integer using L<strtoull(3)>. The
  B<Derive*> types interpret the submatch as a signed integer using
- L<strtoll(3)>. B<CounterInc> and B<DeriveInc> do not use the submatch at all
- and it may be omitted in this case.
+ L<strtoll(3)>. B<CounterInc>, B<DeriveInc> and B<GaugeInc> do not use the
+ submatch at all and it may be omitted in this case.
+ The B<Gauge*> types, unless noted otherwise, are reset to C<NaN> after being
+ reported. In other words, B<GaugeAverage> reports the average of all values
+ matched since the last metric was reported (or C<NaN> if there was no match).
  
  =item B<Type> I<Type>
  
@@@ -8545,14 -8124,13 +8552,14 @@@ B<Synopsis:
     <Metric "snort-dropped">
         Type "percent"
         Instance "dropped"
 -       Index 1
 +       ValueFrom 1
     </Metric>
     <File "/var/log/snort/snort.stats">
         Plugin "snortstats"
         Instance "eth0"
         Interval 600
         Collect "snort-dropped"
 +       #TimeFrom 0
     </File>
   </Plugin>
  
@@@ -8874,33 -8452,6 +8881,33 @@@ dynamic number assigned by the kernel. 
  if there is only one package and C<pkgE<lt>nE<gt>-coreE<lt>mE<gt>> if there is
  more than one, where I<n> is the n-th core of package I<m>.
  
 +=item B<RestoreAffinityPolicy> I<AllCPUs>|I<Restore>
 +
 +Reading data from CPU has side-effect: collectd process's CPU affinity mask
 +changes. After reading data is completed, affinity mask needs to be restored.
 +This option allows to set restore policy.
 +
 +B<AllCPUs> (the default): Restore the affinity by setting affinity to any/all
 +CPUs.
 +
 +B<Restore>: Save affinity using sched_getaffinity() before reading data and
 +restore it after.
 +
 +On some systems, sched_getaffinity() will fail due to inconsistency of the CPU
 +set size between userspace and kernel. In these cases plugin will detect the
 +unsuccessful call and fail with an error, preventing data collection.
 +Most of configurations does not need to save affinity as Collectd process is
 +allowed to run on any/all available CPUs.
 +
 +If you need to save and restore affinity and get errors like 'Unable to save
 +the CPU affinity', setting 'possible_cpus' kernel boot option may also help.
 +
 +See following links for details:
 +
 +L<https://github.com/collectd/collectd/issues/1593>
 +L<https://sourceware.org/bugzilla/show_bug.cgi?id=15630>
 +L<https://bugzilla.kernel.org/show_bug.cgi?id=151821>
 +
  =back
  
  =head2 Plugin C<unixsock>
@@@ -9170,40 -8721,6 +9177,40 @@@ only on the host system
  
  Only I<Connection> is required.
  
 +Consider the following example config:
 +
 + <Plugin "virt">
 +   Connection "qemu:///system"
 +   HostnameFormat "hostname"
 +   InterfaceFormat "address"
 +   PluginInstanceFormat "name"
 + </Plugin>
 +
 +It will generate the following values:
 +
 +  node42.example.com/virt-instance-0006f26c/disk_octets-vda
 +  node42.example.com/virt-instance-0006f26c/disk_ops-vda
 +  node42.example.com/virt-instance-0006f26c/if_dropped-ca:fe:ca:fe:ca:fe
 +  node42.example.com/virt-instance-0006f26c/if_errors-ca:fe:ca:fe:ca:fe
 +  node42.example.com/virt-instance-0006f26c/if_octets-ca:fe:ca:fe:ca:fe
 +  node42.example.com/virt-instance-0006f26c/if_packets-ca:fe:ca:fe:ca:fe
 +  node42.example.com/virt-instance-0006f26c/memory-actual_balloon
 +  node42.example.com/virt-instance-0006f26c/memory-available
 +  node42.example.com/virt-instance-0006f26c/memory-last_update
 +  node42.example.com/virt-instance-0006f26c/memory-major_fault
 +  node42.example.com/virt-instance-0006f26c/memory-minor_fault
 +  node42.example.com/virt-instance-0006f26c/memory-rss
 +  node42.example.com/virt-instance-0006f26c/memory-swap_in
 +  node42.example.com/virt-instance-0006f26c/memory-swap_out
 +  node42.example.com/virt-instance-0006f26c/memory-total
 +  node42.example.com/virt-instance-0006f26c/memory-unused
 +  node42.example.com/virt-instance-0006f26c/memory-usable
 +  node42.example.com/virt-instance-0006f26c/virt_cpu_total
 +  node42.example.com/virt-instance-0006f26c/virt_vcpu-0
 +
 +You can get information on the metric's units from the online libvirt documentation.
 +For instance, I<virt_cpu_total> is in nanoseconds.
 +
  =over 4
  
  =item B<Connection> I<uri>
@@@ -9296,7 -8813,7 +9303,7 @@@ be set to C<var_lib_libvirt_images_imag
  Setting C<BlockDeviceFormatBasename true> will cause the I<type instance> to be
  set to C<image1.qcow2>.
  
 -=item B<HostnameFormat> B<name|uuid|hostname|...>
 +=item B<HostnameFormat> B<name|uuid|hostname|metadata...>
  
  When the virt plugin logs data, it sets the hostname of the collected data
  according to this setting. The default is to use the guest name as provided by
@@@ -9306,11 -8823,7 +9313,11 @@@ B<uuid> means use the guest's UUID. Thi
  same guest across migrations.
  
  B<hostname> means to use the global B<Hostname> setting, which is probably not
 -useful on its own because all guests will appear to have the same name.
 +useful on its own because all guests will appear to have the same name. This is
 +useful in conjunction with B<PluginInstanceFormat> though.
 +
 +B<metadata> means use information from guest's metadata. Use
 +B<HostnameMetadataNS> and B<HostnameMetadataXPath> to localize this information.
  
  You can also specify combinations of these fields. For example B<name uuid>
  means to concatenate the guest name and UUID (with a literal colon character
@@@ -9320,7 -8833,7 +9327,7 @@@ At the moment of writing (collectd-5.5)
  characters. In case when combination of fields exceeds 62 characters,
  hostname will be truncated without a warning.
  
 -=item B<InterfaceFormat> B<name>|B<address>
 +=item B<InterfaceFormat> B<name>|B<address>|B<number>
  
  When the virt plugin logs interface data, it sets the name of the collected
  data according to this setting. The default is to use the path as provided by
@@@ -9330,42 -8843,23 +9337,42 @@@ setting B<name>
  B<address> means use the interface's mac address. This is useful since the
  interface path might change between reboots of a guest or across migrations.
  
 -=item B<PluginInstanceFormat> B<name|uuid|none>
 +B<number> means use the interface's number in guest.
 +
 +=item B<PluginInstanceFormat> B<name|uuid|metadata|none>
  
  When the virt plugin logs data, it sets the plugin_instance of the collected
  data according to this setting. The default is to not set the plugin_instance.
  
  B<name> means use the guest's name as provided by the hypervisor.
  B<uuid> means use the guest's UUID.
 +B<metadata> means use information from guest's metadata.
  
  You can also specify combinations of the B<name> and B<uuid> fields.
  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>
 +=item B<HostnameMetadataNS> B<string>
  
 -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.
 +When B<metadata> is used in B<HostnameFormat> or B<PluginInstanceFormat>, this
 +selects in which metadata namespace we will pick the hostname. The default is
 +I<http://openstack.org/xmlns/libvirt/nova/1.0>.
 +
 +=item B<HostnameMetadataXPath> B<string>
 +
 +When B<metadata> is used in B<HostnameFormat> or B<PluginInstanceFormat>, this
 +describes where the hostname is located in the libvirt metadata. The default is
 +I</instance/name/text()>.
 +
 +=item B<ReportBlockDevices> B<true>|B<false>
 +
 +Enabled by default. Allows to disable stats reporting of block devices for
 +whole plugin.
 +
 +=item B<ReportNetworkInterfaces> B<true>|B<false>
 +
 +Enabled by default. Allows to disable stats reporting of network interfaces for
 +whole plugin.
  
  =item B<ExtraStats> B<string>
  
@@@ -9416,39 -8910,6 +9423,39 @@@ B<Note>: I<perf> metrics can't be colle
  
  =back
  
 +=item B<PersistentNotification> B<true>|B<false>
 +
 +Override default configuration to only send notifications when there is a change
 +in the lifecycle state of a domain. When set to true notifications will be sent
 +for every read cycle. Default is false. Does not affect the stats being
 +dispatched.
 +
 +=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.
 +
 +This option is only useful when domains are specially tagged.
 +If you are not sure, just use the default setting.
 +
 +The reader instance will only query the domains with attached matching tag.
 +Tags should have the form of 'virt-X' where X is the reader instance number,
 +starting from 0.
 +
 +The special-purpose reader instance #0, guaranteed to be always present,
 +will query all the domains with missing or unrecognized tag, so no domain will
 +ever be left out.
 +
 +Domain tagging is done with a custom attribute in the libvirt domain metadata
 +section. Value is selected by an XPath I</domain/metadata/ovirtmap/tag/text()>
 +expression in the I<http://ovirt.org/ovirtmap/tag/1.0> namespace.
 +(XPath and namespace values are not configurable yet).
 +
 +Tagging could be used by management applications to evenly spread the
 +load among the reader threads, or to pin on the same threads all
 +the libvirt domains which use the same shared storage, to minimize
 +the disruption in presence of storage outages.
 +
  =back
  
  =head2 Plugin C<vmem>
@@@ -9502,7 -8963,6 +9509,7 @@@ Synopsis
       Protocol "tcp"
       LogSendErrors true
       Prefix "collectd"
 +     UseTags false
     </Node>
   </Plugin>
  
@@@ -9540,20 -9000,13 +9547,20 @@@ approach and logging errors fills syslo
  
  =item B<Prefix> I<String>
  
 -When set, I<String> is added in front of the host name. Dots and whitespace are
 -I<not> escaped in this string (see B<EscapeCharacter> below).
 +When B<UseTags> is I<false>, B<Prefix> value is added in front of the host name.
 +When B<UseTags> is I<true>, B<Prefix> value is added in front of series name.
 +
 +Dots and whitespace are I<not> escaped in this string (see B<EscapeCharacter>
 +below).
  
  =item B<Postfix> I<String>
  
 -When set, I<String> is appended to the host name. Dots and whitespace are
 -I<not> escaped in this string (see B<EscapeCharacter> below).
 +When B<UseTags> is I<false>, B<Postfix> value appended to the host name.
 +When B<UseTags> is I<true>, B<Postgix> value appended to the end of series name
 +(before the first ; that separates the name from the tags).
 +
 +Dots and whitespace are I<not> escaped in this string (see B<EscapeCharacter>
 +below).
  
  =item B<EscapeCharacter> I<Char>
  
@@@ -9575,8 -9028,6 +9582,8 @@@ path component, for example C<host.cpu.
  default), the plugin and plugin instance (and likewise the type and type
  instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
  
 +Option value is not used when B<UseTags> is I<true>.
 +
  =item B<AlwaysAppendDS> B<false>|B<true>
  
  If set to B<true>, append the name of the I<Data Source> (DS) to the "metric"
@@@ -9589,31 -9040,12 +9596,31 @@@ If set to B<false> (the default) the C<
  I<EscapeCharacter>. Otherwise, if set to B<true>, the C<.> (dot) character
  is preserved, i.e. passed through.
  
 +Option value is not used when B<UseTags> is I<true>.
 +
  =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>.
  
 +=item B<UseTags> B<false>|B<true>
 +
 +If set to B<true>, Graphite metric names will be generated as tagged series.
 +This allows for much more flexibility than the traditional hierarchical layout.
 +
 +Example:
 +C<test.single;host=example.com;plugin=test;plugin_instance=foo;type=single;type_instance=bar>
 +
 +You can use B<Postfix> option to add more tags by specifying it like
 +C<;tag1=value1;tag2=value2>. Note what tagging support was added since Graphite
 +version 1.1.x.
 +
 +If set to B<true>, the B<SeparateInstances> and B<PreserveSeparator> settings
 +are not used.
 +
 +Default value: B<false>.
 +
  =back
  
  =head2 Plugin C<write_log>
@@@ -9782,13 -9214,6 +9789,13 @@@ B<Options:
  
  =over 4
  
 +=item B<Host> I<Host>
 +
 +Bind to the hostname / address I<Host>. By default, the plugin will bind to the
 +"any" address, i.e. accept packets sent to any of the hosts addresses.
 +
 +This option is supported only for libmicrohttpd newer than 0.9.0.
 +
  =item B<Port> I<Port>
  
  Port the embedded webserver should listen on. Defaults to B<9103>.
@@@ -10046,26 -9471,17 +10053,26 @@@ been set to B<JSON>
  =item B<GraphitePrefix> (B<Format>=I<Graphite> only)
  
  A prefix can be added in the metric name when outputting in the I<Graphite>
 -format. It's added before the I<Host> name.
 +format.
 +
 +When B<GraphiteUseTags> is I<false>, prefix is added before the I<Host> name.
  Metric name will be
  C<E<lt>prefixE<gt>E<lt>hostE<gt>E<lt>postfixE<gt>E<lt>pluginE<gt>E<lt>typeE<gt>E<lt>nameE<gt>>
  
 +When B<GraphiteUseTags> is I<true>, prefix is added in front of series name.
 +
  =item B<GraphitePostfix> (B<Format>=I<Graphite> only)
  
  A postfix can be added in the metric name when outputting in the I<Graphite>
 -format. It's added after the I<Host> name.
 +format.
 +
 +When B<GraphiteUseTags> is I<false>, postfix is added after the I<Host> name.
  Metric name will be
  C<E<lt>prefixE<gt>E<lt>hostE<gt>E<lt>postfixE<gt>E<lt>pluginE<gt>E<lt>typeE<gt>E<lt>nameE<gt>>
  
 +When B<GraphiteUseTags> is I<true>, prefix value appended to the end of series
 +name (before the first ; that separates the name from the tags).
 +
  =item B<GraphiteEscapeChar> (B<Format>=I<Graphite> only)
  
  Specify a character to replace dots (.) in the host part of the metric name.
@@@ -10080,8 -9496,6 +10087,8 @@@ path component, for example C<host.cpu.
  default), the plugin and plugin instance (and likewise the type and type
  instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
  
 +Option value is not used when B<GraphiteUseTags> is I<true>.
 +
  =item B<GraphiteAlwaysAppendDS> B<true>|B<false>
  
  If set to B<true>, append the name of the I<Data Source> (DS) to the "metric"
@@@ -10094,14 -9508,6 +10101,14 @@@ If set to B<false> (the default) the C<
  I<GraphiteEscapeChar>. Otherwise, if set to B<true>, the C<.> (dot) character
  is preserved, i.e. passed through.
  
 +Option value is not used when B<GraphiteUseTags> is I<true>.
 +
 +=item B<GraphiteUseTags> B<false>|B<true>
 +
 +If set to B<true> Graphite metric names will be generated as tagged series.
 +
 +Default value: B<false>.
 +
  =item B<StoreRates> B<true>|B<false>
  
  If set to B<true> (the default), convert counter values to rates. If set to
@@@ -10462,133 -9868,6 +10469,133 @@@ attribute for each metric being sent ou
  
  =back
  
 +=head2 Plugin C<write_stackdriver>
 +
 +The C<write_stackdriver> plugin writes metrics to the
 +I<Google Stackdriver Monitoring> service.
 +
 +This plugin supports two authentication methods: When configured, credentials
 +are read from the JSON credentials file specified with B<CredentialFile>.
 +Alternatively, when running on
 +I<Google Compute Engine> (GCE), an I<OAuth> token is retrieved from the
 +I<metadata server> and used to authenticate to GCM.
 +
 +B<Synopsis:>
 +
 + <Plugin write_stackdriver>
 +   CredentialFile "/path/to/service_account.json"
 +   <Resource "global">
 +     Label "project_id" "monitored_project"
 +   </Resource>
 + </Plugin>
 +
 +=over 4
 +
 +=item B<CredentialFile> I<file>
 +
 +Path to a JSON credentials file holding the credentials for a GCP service
 +account.
 +
 +If B<CredentialFile> is not specified, the plugin uses I<Application Default
 +Credentials>. That means which credentials are used depends on the environment:
 +
 +=over 4
 +
 +=item
 +
 +The environment variable C<GOOGLE_APPLICATION_CREDENTIALS> is checked. If this
 +variable is specified it should point to a JSON file that defines the
 +credentials.
 +
 +=item
 +
 +The path C<${HOME}/.config/gcloud/application_default_credentials.json> is
 +checked. This where credentials used by the I<gcloud> command line utility are
 +stored. You can use C<gcloud auth application-default login> to create these
 +credentials.
 +
 +Please note that these credentials are often of your personal account, not a
 +service account, and are therefore unfit to be used in a production
 +environment.
 +
 +=item
 +
 +When running on GCE, the built-in service account associated with the virtual
 +machine instance is used.
 +See also the B<Email> option below.
 +
 +=back
 +
 +=item B<Project> I<Project>
 +
 +The I<Project ID> or the I<Project Number> of the I<Stackdriver Account>. The
 +I<Project ID> is a string identifying the GCP project, which you can chose
 +freely when creating a new project. The I<Project Number> is a 12-digit decimal
 +number. You can look up both on the I<Developer Console>.
 +
 +This setting is optional. If not set, the project ID is read from the
 +credentials file or determined from the GCE's metadata service.
 +
 +=item B<Email> I<Email> (GCE only)
 +
 +Choses the GCE I<Service Account> used for authentication.
 +
 +Each GCE instance has a C<default> I<Service Account> but may also be
 +associated with additional I<Service Accounts>. This is often used to restrict
 +the permissions of services running on the GCE instance to the required
 +minimum. The I<write_stackdriver plugin> requires the
 +C<https://www.googleapis.com/auth/monitoring> scope. When multiple I<Service
 +Accounts> are available, this option selects which one is used by
 +I<write_stackdriver plugin>.
 +
 +=item B<Resource> I<ResourceType>
 +
 +Configures the I<Monitored Resource> to use when storing metrics.
 +More information on I<Monitored Resources> and I<Monitored Resource Types> are
 +available at L<https://cloud.google.com/monitoring/api/resources>.
 +
 +This block takes one string argument, the I<ResourceType>. Inside the block are
 +one or more B<Label> options which configure the resource labels.
 +
 +This block is optional. The default value depends on the runtime environment:
 +on GCE, the C<gce_instance> resource type is used, otherwise the C<global>
 +resource type ist used:
 +
 +=over 4
 +
 +=item
 +
 +B<On GCE>, defaults to the equivalent of this config:
 +
 +  <Resource "gce_instance">
 +    Label "project_id" "<project_id>"
 +    Label "instance_id" "<instance_id>"
 +    Label "zone" "<zone>"
 +  </Resource>
 +
 +The values for I<project_id>, I<instance_id> and I<zone> are read from the GCE
 +metadata service.
 +
 +=item
 +
 +B<Elsewhere>, i.e. not on GCE, defaults to the equivalent of this config:
 +
 +  <Resource "global">
 +    Label "project_id" "<Project>"
 +  </Resource>
 +
 +Where I<Project> refers to the value of the B<Project> option or the project ID
 +inferred from the B<CredentialFile>.
 +
 +=back
 +
 +=item B<Url> I<Url>
 +
 +URL of the I<Stackdriver Monitoring> API. Defaults to
 +C<https://monitoring.googleapis.com/v3>.
 +
 +=back
 +
  =head2 Plugin C<xencpu>
  
  This plugin collects metrics of hardware CPU load for machine running Xen
diff --combined src/daemon/common.c
   *   MichaÅ‚ MirosÅ‚aw <mirq-linux at rere.qmqm.pl>
  **/
  
 -#if HAVE_CONFIG_H
 -#include "config.h"
 -#endif
 -
  #include "collectd.h"
  
  #include "common.h"
  extern kstat_ctl_t *kc;
  #endif
  
 +#if !defined(MSG_DONTWAIT)
 +#if defined(MSG_NONBLOCK)
  /* AIX doesn't have MSG_DONTWAIT */
 -#ifndef MSG_DONTWAIT
  #define MSG_DONTWAIT MSG_NONBLOCK
 -#endif
 +#else
 +/* Windows doesn't have MSG_DONTWAIT or MSG_NONBLOCK */
 +#define MSG_DONTWAIT 0
 +#endif /* defined(MSG_NONBLOCK) */
 +#endif /* !defined(MSG_DONTWAIT) */
  
 -#if !HAVE_GETPWNAM_R
 +#if !HAVE_GETPWNAM_R && defined(HAVE_GETPWNAM)
  static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER;
  #endif
  
@@@ -339,6 -338,9 +339,9 @@@ int strjoin(char *buffer, size_t buffer
        buffer_req += sep_len;
      buffer_req += field_len;
  
+     if (buffer_size == 0)
+       continue;
      if ((i != 0) && (sep_len > 0)) {
        if (sep_len >= avail) {
          /* prevent subsequent iterations from writing to the
@@@ -418,7 -420,7 +421,7 @@@ int strunescape(char *buf, size_t buf_l
        continue;
  
      if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) {
 -      ERROR("string unescape: backslash found at end of string.");
 +      P_ERROR("string unescape: backslash found at end of string.");
        /* Ensure null-byte at the end of the buffer. */
        buf[i] = 0;
        return -1;
      /* Move everything after the position one position to the left.
       * Add a null-byte as last character in the buffer. */
      memmove(buf + i + 1, buf + i + 2, buf_len - i - 2);
 -    buf[buf_len - 1] = 0;
 +    buf[buf_len - 1] = '\0';
    }
    return 0;
  } /* int strunescape */
@@@ -545,8 -547,9 +548,8 @@@ int timeval_cmp(struct timeval tv0, str
  int check_create_dir(const char *file_orig) {
    struct stat statbuf;
  
 -  char file_copy[512];
 -  char dir[512];
 -  int dir_len = 512;
 +  char file_copy[PATH_MAX];
 +  char dir[PATH_MAX];
    char *fields[16];
    int fields_num;
    char *ptr;
  
    if ((len = strlen(file_orig)) < 1)
      return -1;
 -  else if (len >= sizeof(file_copy))
 +  else if (len >= sizeof(file_copy)) {
 +    ERROR("check_create_dir: name (%s) is too long.", file_orig);
      return -1;
 +  }
  
    /*
     * If `file_orig' ends in a slash the last component is a directory,
       * behavior.
       */
      if (fields[i][0] == '.') {
 -      ERROR("Cowardly refusing to create a directory that "
 -            "begins with a `.' (dot): `%s'",
 -            file_orig);
 +      P_ERROR("Cowardly refusing to create a directory that "
 +              "begins with a `.' (dot): `%s'",
 +              file_orig);
        return -2;
      }
  
       * Join the components together again
       */
      dir[0] = '/';
 -    if (strjoin(dir + path_is_absolute, (size_t)(dir_len - path_is_absolute),
 -                fields, (size_t)(i + 1), "/") < 0) {
 -      ERROR("strjoin failed: `%s', component #%i", file_orig, i);
 +    if (strjoin(dir + path_is_absolute,
 +                (size_t)(sizeof(dir) - path_is_absolute), fields,
 +                (size_t)(i + 1), "/") < 0) {
 +      P_ERROR("strjoin failed: `%s', component #%i", file_orig, i);
        return -1;
      }
  
            if (EEXIST == errno)
              continue;
  
 -          char errbuf[1024];
 -          ERROR("check_create_dir: mkdir (%s): %s", dir,
 -                sstrerror(errno, errbuf, sizeof(errbuf)));
 +          P_ERROR("check_create_dir: mkdir (%s): %s", dir, STRERRNO);
            return -1;
          } else {
 -          char errbuf[1024];
 -          ERROR("check_create_dir: stat (%s): %s", dir,
 -                sstrerror(errno, errbuf, sizeof(errbuf)));
 +          P_ERROR("check_create_dir: stat (%s): %s", dir, STRERRNO);
            return -1;
          }
        } else if (!S_ISDIR(statbuf.st_mode)) {
 -        ERROR("check_create_dir: `%s' exists but is not "
 -              "a directory!",
 -              dir);
 +        P_ERROR("check_create_dir: `%s' exists but is not "
 +                "a directory!",
 +                dir);
          return -1;
        }
        break;
@@@ -668,12 -672,12 +671,12 @@@ int get_kstat(kstat_t **ksp_ptr, char *
  
    *ksp_ptr = kstat_lookup(kc, module, instance, name);
    if (*ksp_ptr == NULL) {
 -    ERROR("get_kstat: Cound not find kstat %s", ident);
 +    P_ERROR("get_kstat: Cound not find kstat %s", ident);
      return -1;
    }
  
    if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) {
 -    ERROR("get_kstat: kstat %s has wrong type", ident);
 +    P_ERROR("get_kstat: kstat %s has wrong type", ident);
      *ksp_ptr = NULL;
      return -1;
    }
  #endif
  
    if (kstat_read(kc, *ksp_ptr, NULL) == -1) {
 -    ERROR("get_kstat: kstat %s could not be read", ident);
 +    P_ERROR("get_kstat: kstat %s could not be read", ident);
      return -1;
    }
  
    if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) {
 -    ERROR("get_kstat: kstat %s has wrong type", ident);
 +    P_ERROR("get_kstat: kstat %s has wrong type", ident);
      return -1;
    }
  
@@@ -701,12 -705,12 +704,12 @@@ long long get_kstat_value(kstat_t *ksp
    long long retval = -1LL;
  
    if (ksp == NULL) {
 -    ERROR("get_kstat_value (\"%s\"): ksp is NULL.", name);
 +    P_ERROR("get_kstat_value (\"%s\"): ksp is NULL.", name);
      return -1LL;
    } else if (ksp->ks_type != KSTAT_TYPE_NAMED) {
 -    ERROR("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
 -          "is not KSTAT_TYPE_NAMED (%#x).",
 -          name, (unsigned int)ksp->ks_type, (unsigned int)KSTAT_TYPE_NAMED);
 +    P_ERROR("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
 +            "is not KSTAT_TYPE_NAMED (%#x).",
 +            name, (unsigned int)ksp->ks_type, (unsigned int)KSTAT_TYPE_NAMED);
      return -1LL;
    }
  
    else if (kn->data_type == KSTAT_DATA_UINT64)
      retval = (long long)kn->value.ui64; /* XXX: Might overflow! */
    else
 -    WARNING("get_kstat_value: Not a numeric value: %s", name);
 +    P_WARNING("get_kstat_value: Not a numeric value: %s", name);
  
    return retval;
  }
@@@ -860,7 -864,7 +863,7 @@@ int format_name(char *ret, int ret_len
  
  int format_values(char *ret, size_t ret_len, /* {{{ */
                    const data_set_t *ds, const value_list_t *vl,
 -                  _Bool store_rates) {
 +                  bool store_rates) {
    size_t offset = 0;
    int status;
    gauge_t *rates = NULL;
        }
        BUFFER_ADD(":" GAUGE_FORMAT, rates[i]);
      } else if (ds->ds[i].type == DS_TYPE_COUNTER)
 -      BUFFER_ADD(":%llu", vl->values[i].counter);
 +      BUFFER_ADD(":%" PRIu64, (uint64_t)vl->values[i].counter);
      else if (ds->ds[i].type == DS_TYPE_DERIVE)
        BUFFER_ADD(":%" PRIi64, vl->values[i].derive);
      else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
@@@ -1013,7 -1017,7 +1016,7 @@@ int parse_value(const char *value_orig
    value_len = strlen(value);
  
    while ((value_len > 0) && isspace((int)value[value_len - 1])) {
 -    value[value_len - 1] = 0;
 +    value[value_len - 1] = '\0';
      value_len--;
    }
  
  
    default:
      sfree(value);
 -    ERROR("parse_value: Invalid data source type: %i.", ds_type);
 +    P_ERROR("parse_value: Invalid data source type: %i.", ds_type);
      return -1;
    }
  
    if (value == endptr) {
 -    ERROR("parse_value: Failed to parse string as %s: \"%s\".",
 -          DS_TYPE_TO_STRING(ds_type), value);
 +    P_ERROR("parse_value: Failed to parse string as %s: \"%s\".",
 +            DS_TYPE_TO_STRING(ds_type), value);
      sfree(value);
      return -1;
    } else if ((NULL != endptr) && ('\0' != *endptr))
 -    INFO("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
 -         "Input string was \"%s\".",
 -         endptr, DS_TYPE_TO_STRING(ds_type), value_orig);
 +    P_INFO("parse_value: Ignoring trailing garbage \"%s\" after %s value. "
 +           "Input string was \"%s\".",
 +           endptr, DS_TYPE_TO_STRING(ds_type), value_orig);
  
    sfree(value);
    return 0;
@@@ -1133,9 -1137,6 +1136,9 @@@ int parse_value_file(char const *path, 
  #if !HAVE_GETPWNAM_R
  int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen,
                 struct passwd **pwbufp) {
 +#ifndef HAVE_GETPWNAM
 +  return -1;
 +#else
    int status = 0;
    struct passwd *pw;
  
    pthread_mutex_unlock(&getpwnam_r_lock);
  
    return status;
 +#endif /* HAVE_GETPWNAM */
  } /* int getpwnam_r */
  #endif /* !HAVE_GETPWNAM_R */
  
@@@ -1217,7 -1217,9 +1220,7 @@@ int walk_directory(const char *dir, dir
    failure = 0;
  
    if ((dh = opendir(dir)) == NULL) {
 -    char errbuf[1024];
 -    ERROR("walk_directory: Cannot open '%s': %s", dir,
 -          sstrerror(errno, errbuf, sizeof(errbuf)));
 +    P_ERROR("walk_directory: Cannot open '%s': %s", dir, STRERRNO);
      return -1;
    }
  
@@@ -1257,7 -1259,7 +1260,7 @@@ ssize_t read_file_contents(const char *
  
    ret = (ssize_t)fread(buf, 1, bufsize, fh);
    if ((ret == 0) && (ferror(fh) != 0)) {
 -    ERROR("read_file_contents: Reading file \"%s\" failed.", filename);
 +    P_ERROR("read_file_contents: Reading file \"%s\" failed.", filename);
      ret = -1;
    }
  
@@@ -1416,8 -1418,8 +1419,8 @@@ int service_name_to_port_number(const c
  
    status = getaddrinfo(/* node = */ NULL, service_name, &ai_hints, &ai_list);
    if (status != 0) {
 -    ERROR("service_name_to_port_number: getaddrinfo failed: %s",
 -          gai_strerror(status));
 +    P_ERROR("service_name_to_port_number: getaddrinfo failed: %s",
 +            gai_strerror(status));
      return -1;
    }
  
@@@ -1455,7 -1457,7 +1458,7 @@@ void set_sock_opts(int sockfd) /* {{{ *
    status = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype,
                        &(socklen_t){sizeof(socktype)});
    if (status != 0) {
 -    WARNING("set_sock_opts: failed to determine socket type");
 +    P_WARNING("set_sock_opts: failed to determine socket type");
      return;
    }
  
      status =
          setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int));
      if (status != 0)
 -      WARNING("set_sock_opts: failed to set socket keepalive flag");
 +      P_WARNING("set_sock_opts: failed to set socket keepalive flag");
  
  #ifdef TCP_KEEPIDLE
      int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
      status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle,
                          sizeof(tcp_keepidle));
      if (status != 0)
 -      WARNING("set_sock_opts: failed to set socket tcp keepalive time");
 +      P_WARNING("set_sock_opts: failed to set socket tcp keepalive time");
  #endif
  
  #ifdef TCP_KEEPINTVL
      status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepintvl,
                          sizeof(tcp_keepintvl));
      if (status != 0)
 -      WARNING("set_sock_opts: failed to set socket tcp keepalive interval");
 +      P_WARNING("set_sock_opts: failed to set socket tcp keepalive interval");
  #endif
    }
  } /* }}} void set_sock_opts */
@@@ -1563,12 -1565,12 +1566,12 @@@ int check_capability(int arg) /* {{{ *
      return -1;
  
    if (!(cap = cap_get_proc())) {
 -    ERROR("check_capability: cap_get_proc failed.");
 +    P_ERROR("check_capability: cap_get_proc failed.");
      return -1;
    }
  
    if (cap_get_flag(cap, cap_value, CAP_EFFECTIVE, &cap_flag_value) < 0) {
 -    ERROR("check_capability: cap_get_flag failed.");
 +    P_ERROR("check_capability: cap_get_flag failed.");
      cap_free(cap);
      return -1;
    }
  #else
  int check_capability(__attribute__((unused)) int arg) /* {{{ */
  {
 -  WARNING("check_capability: unsupported capability implementation. "
 -          "Some plugin(s) may require elevated privileges to work properly.");
 +  P_WARNING("check_capability: unsupported capability implementation. "
 +            "Some plugin(s) may require elevated privileges to work properly.");
    return 0;
  } /* }}} int check_capability */
  #endif /* HAVE_CAPABILITY */
diff --combined src/log_logstash.c
@@@ -49,7 -49,7 +49,7 @@@ static int log_level = LOG_INFO
  
  static pthread_mutex_t file_lock = PTHREAD_MUTEX_INITIALIZER;
  
 -static char *log_file = NULL;
 +static char *log_file;
  
  static const char *config_keys[] = {"LogLevel", "File"};
  static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
@@@ -75,7 -75,7 +75,7 @@@ static int log_logstash_config(const ch
  static void log_logstash_print(yajl_gen g, int severity,
                                 cdtime_t timestamp_time) {
    FILE *fh;
 -  _Bool do_close = 0;
 +  bool do_close = false;
    struct tm timestamp_tm;
    char timestamp_str[64];
    const unsigned char *buf;
      fh = stderr;
    } else if (strcasecmp(log_file, "stdout") == 0) {
      fh = stdout;
 -    do_close = 0;
 +    do_close = false;
    } else if (strcasecmp(log_file, "stderr") == 0) {
      fh = stderr;
 -    do_close = 0;
 +    do_close = false;
    } else {
      fh = fopen(log_file, "a");
 -    do_close = 1;
 +    do_close = true;
    }
  
    if (fh == NULL) {
 -    char errbuf[1024];
      fprintf(stderr, "log_logstash plugin: fopen (%s) failed: %s\n", log_file,
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +            STRERRNO);
    } else {
      fprintf(fh, "%s\n", buf);
      if (do_close) {
@@@ -182,22 -183,14 +182,14 @@@ err
  
  static void log_logstash_log(int severity, const char *msg,
                               user_data_t __attribute__((unused)) * user_data) {
-   yajl_gen g;
- #if !defined(HAVE_YAJL_V2)
-   yajl_gen_config conf = {};
-   conf.beautify = 0;
- #endif
    if (severity > log_level)
      return;
  
  #if HAVE_YAJL_V2
-   g = yajl_gen_alloc(NULL);
+   yajl_gen g = yajl_gen_alloc(NULL);
  #else
-   g = yajl_gen_alloc(&conf, NULL);
+   yajl_gen g = yajl_gen_alloc(&(yajl_gen_config){0}, NULL);
  #endif
    if (g == NULL) {
      fprintf(stderr, "Could not allocate JSON generator.\n");
      return;
diff --combined src/sensors.c
  #define SENSORS_API_VERSION 0x000
  #endif
  
 -/*
 - * The sensors library prior to version 3.0 (internal version 0x400) didn't
 - * report the type of values, only a name. The following lists are there to
 - * convert from the names to the type. They are not used with the new
 - * interface.
 - */
 -#if SENSORS_API_VERSION < 0x400
 -static char *sensor_type_name_map[] = {
 -#define SENSOR_TYPE_VOLTAGE 0
 -    "voltage",
 -#define SENSOR_TYPE_FANSPEED 1
 -    "fanspeed",
 -#define SENSOR_TYPE_TEMPERATURE 2
 -    "temperature",
 -#define SENSOR_TYPE_POWER 3
 -    "power",
 -#define SENSOR_TYPE_UNKNOWN 4
 -    NULL};
 -
 -struct sensors_labeltypes_s {
 -  char *label;
 -  int type;
 -};
 -typedef struct sensors_labeltypes_s sensors_labeltypes_t;
 -
 -/* finite list of known labels extracted from lm_sensors */
 -static sensors_labeltypes_t known_features[] = {
 -    {"fan1", SENSOR_TYPE_FANSPEED},
 -    {"fan2", SENSOR_TYPE_FANSPEED},
 -    {"fan3", SENSOR_TYPE_FANSPEED},
 -    {"fan4", SENSOR_TYPE_FANSPEED},
 -    {"fan5", SENSOR_TYPE_FANSPEED},
 -    {"fan6", SENSOR_TYPE_FANSPEED},
 -    {"fan7", SENSOR_TYPE_FANSPEED},
 -    {"AIN2", SENSOR_TYPE_VOLTAGE},
 -    {"AIN1", SENSOR_TYPE_VOLTAGE},
 -    {"in10", SENSOR_TYPE_VOLTAGE},
 -    {"in9", SENSOR_TYPE_VOLTAGE},
 -    {"in8", SENSOR_TYPE_VOLTAGE},
 -    {"in7", SENSOR_TYPE_VOLTAGE},
 -    {"in6", SENSOR_TYPE_VOLTAGE},
 -    {"in5", SENSOR_TYPE_VOLTAGE},
 -    {"in4", SENSOR_TYPE_VOLTAGE},
 -    {"in3", SENSOR_TYPE_VOLTAGE},
 -    {"in2", SENSOR_TYPE_VOLTAGE},
 -    {"in0", SENSOR_TYPE_VOLTAGE},
 -    {"CPU_Temp", SENSOR_TYPE_TEMPERATURE},
 -    {"remote_temp", SENSOR_TYPE_TEMPERATURE},
 -    {"temp1", SENSOR_TYPE_TEMPERATURE},
 -    {"temp2", SENSOR_TYPE_TEMPERATURE},
 -    {"temp3", SENSOR_TYPE_TEMPERATURE},
 -    {"temp4", SENSOR_TYPE_TEMPERATURE},
 -    {"temp5", SENSOR_TYPE_TEMPERATURE},
 -    {"temp6", SENSOR_TYPE_TEMPERATURE},
 -    {"temp7", SENSOR_TYPE_TEMPERATURE},
 -    {"temp", SENSOR_TYPE_TEMPERATURE},
 -    {"Vccp2", SENSOR_TYPE_VOLTAGE},
 -    {"Vccp1", SENSOR_TYPE_VOLTAGE},
 -    {"vdd", SENSOR_TYPE_VOLTAGE},
 -    {"vid5", SENSOR_TYPE_VOLTAGE},
 -    {"vid4", SENSOR_TYPE_VOLTAGE},
 -    {"vid3", SENSOR_TYPE_VOLTAGE},
 -    {"vid2", SENSOR_TYPE_VOLTAGE},
 -    {"vid1", SENSOR_TYPE_VOLTAGE},
 -    {"vid", SENSOR_TYPE_VOLTAGE},
 -    {"vin4", SENSOR_TYPE_VOLTAGE},
 -    {"vin3", SENSOR_TYPE_VOLTAGE},
 -    {"vin2", SENSOR_TYPE_VOLTAGE},
 -    {"vin1", SENSOR_TYPE_VOLTAGE},
 -    {"voltbatt", SENSOR_TYPE_VOLTAGE},
 -    {"volt12", SENSOR_TYPE_VOLTAGE},
 -    {"volt5", SENSOR_TYPE_VOLTAGE},
 -    {"vrm", SENSOR_TYPE_VOLTAGE},
 -    {"5.0V", SENSOR_TYPE_VOLTAGE},
 -    {"5V", SENSOR_TYPE_VOLTAGE},
 -    {"3.3V", SENSOR_TYPE_VOLTAGE},
 -    {"2.5V", SENSOR_TYPE_VOLTAGE},
 -    {"2.0V", SENSOR_TYPE_VOLTAGE},
 -    {"12V", SENSOR_TYPE_VOLTAGE},
 -    {"power1", SENSOR_TYPE_POWER}};
 -static int known_features_num = STATIC_ARRAY_SIZE(known_features);
 -/* end new naming */
 -#endif /* SENSORS_API_VERSION < 0x400 */
 -
  static const char *config_keys[] = {"Sensor", "IgnoreSelected",
                                      "SensorConfigFile", "UseLabels"};
  static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
  
+ #if SENSORS_API_VERSION < 0x400
+ typedef struct featurelist {
+   const sensors_chip_name *chip;
+   const sensors_feature_data *data;
+   int type;
+   struct featurelist *next;
+ } featurelist_t;
+ #ifndef SENSORS_CONF_PATH
+ #define SENSORS_CONF_PATH "/etc/sensors.conf"
+ #endif
+ static char *conffile = SENSORS_CONF_PATH;
+ /* #endif SENSORS_API_VERSION < 0x400 */
+ #elif (SENSORS_API_VERSION >= 0x400)
  typedef struct featurelist {
    const sensors_chip_name *chip;
    const sensors_feature *feature;
    struct featurelist *next;
  } featurelist_t;
  
 -static char *conffile = NULL;
 -static _Bool use_labels = 0;
 +static char *conffile;
 +static bool use_labels;
+ #endif
  
 -static featurelist_t *first_feature = NULL;
 +static featurelist_t *first_feature;
  static ignorelist_t *sensor_list;
  
 -#if SENSORS_API_VERSION < 0x400
 -/* full chip name logic borrowed from lm_sensors */
 -static int sensors_snprintf_chip_name(char *buf, size_t buf_size,
 -                                      const sensors_chip_name *chip) {
 -  int status = -1;
 -
 -  if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA) {
 -    status = snprintf(buf, buf_size, "%s-isa-%04x", chip->prefix, chip->addr);
 -  } else if (chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY) {
 -    status = snprintf(buf, buf_size, "%s-%s-%04x", chip->prefix, chip->busname,
 -                      chip->addr);
 -  } else {
 -    status = snprintf(buf, buf_size, "%s-i2c-%d-%02x", chip->prefix, chip->bus,
 -                      chip->addr);
 -  }
 -
 -  return status;
 -} /* int sensors_snprintf_chip_name */
 -
 -static int sensors_feature_name_to_type(const char *name) {
 -  /* Yes, this is slow, but it's only ever done during initialization, so
 -   * it's a one time cost.. */
 -  for (int i = 0; i < known_features_num; i++)
 -    if (strcasecmp(known_features[i].label, name) == 0)
 -      return known_features[i].type;
 -
 -  return SENSOR_TYPE_UNKNOWN;
 -} /* int sensors_feature_name_to_type */
 -#endif
 -
  static int sensors_config(const char *key, const char *value) {
    if (sensor_list == NULL)
      sensor_list = ignorelist_create(1);
      ignorelist_set_invert(sensor_list, 1);
      if (IS_TRUE(value))
        ignorelist_set_invert(sensor_list, 0);
-   } else if (strcasecmp(key, "UseLabels") == 0) {
+   }
+ #if (SENSORS_API_VERSION >= 0x400)
+   else if (strcasecmp(key, "UseLabels") == 0) {
 -    use_labels = IS_TRUE(value) ? 1 : 0;
 +    use_labels = IS_TRUE(value);
-   } else {
+   }
+ #endif
+   else {
      return -1;
    }
  
@@@ -112,7 -246,7 +132,7 @@@ static void sensors_free_features(void
  }
  
  static int sensors_load_conf(void) {
 -  static int call_once = 0;
 +  static int call_once;
  
    FILE *fh = NULL;
    featurelist_t *last_feature = NULL;
    if (conffile != NULL) {
      fh = fopen(conffile, "r");
      if (fh == NULL) {
 -      char errbuf[1024];
 -      ERROR("sensors plugin: fopen(%s) failed: %s", conffile,
 -            sstrerror(errno, errbuf, sizeof(errbuf)));
 +      ERROR("sensors plugin: fopen(%s) failed: %s", conffile, STRERRNO);
        return -1;
      }
    }
      return -1;
    }
  
+ #if SENSORS_API_VERSION < 0x400
+   chip_num = 0;
+   while ((chip = sensors_get_detected_chips(&chip_num)) != NULL) {
+     int feature_num0 = 0;
+     int feature_num1 = 0;
+     while (42) {
+       const sensors_feature_data *feature;
+       int feature_type;
+       featurelist_t *fl;
+       feature = sensors_get_all_features(*chip, &feature_num0, &feature_num1);
+       /* Check if all features have been read. */
+       if (feature == NULL)
+         break;
+       /* "master features" only */
+       if (feature->mapping != SENSORS_NO_MAPPING) {
+         DEBUG("sensors plugin: sensors_load_conf: "
+               "Ignoring subfeature `%s', "
+               "because (feature->mapping "
+               "!= SENSORS_NO_MAPPING).",
+               feature->name);
+         continue;
+       }
+       /* skip ignored in sensors.conf */
+       if (sensors_get_ignored(*chip, feature->number) == 0) {
+         DEBUG("sensors plugin: sensors_load_conf: "
+               "Ignoring subfeature `%s', "
+               "because "
+               "`sensors_get_ignored' told "
+               "me so.",
+               feature->name);
+         continue;
+       }
+       feature_type = sensors_feature_name_to_type(feature->name);
+       if (feature_type == SENSOR_TYPE_UNKNOWN) {
+         DEBUG("sensors plugin: sensors_load_conf: "
+               "Ignoring subfeature `%s', "
+               "because its type is "
+               "unknown.",
+               feature->name);
+         continue;
+       }
+       fl = calloc(1, sizeof(*fl));
+       if (fl == NULL) {
+         ERROR("sensors plugin: calloc failed.");
+         continue;
+       }
+       fl->chip = chip;
+       fl->data = feature;
+       fl->type = feature_type;
+       if (first_feature == NULL)
+         first_feature = fl;
+       else
+         last_feature->next = fl;
+       last_feature = fl;
+     } /* while sensors_get_all_features */
+   }   /* while sensors_get_detected_chips */
+ /* #endif SENSORS_API_VERSION < 0x400 */
+ #elif (SENSORS_API_VERSION >= 0x400)
    chip_num = 0;
    while ((chip = sensors_get_detected_chips(NULL, &chip_num)) != NULL) {
      const sensors_feature *feature;
  #if SENSORS_API_VERSION >= 0x402
            (feature->type != SENSORS_FEATURE_CURR) &&
  #endif
 +#if SENSORS_API_VERSION >= 0x431
 +          (feature->type != SENSORS_FEATURE_HUMIDITY) &&
 +#endif
            (feature->type != SENSORS_FEATURE_POWER)) {
          DEBUG("sensors plugin: sensors_load_conf: "
                "Ignoring feature `%s', "
  #if SENSORS_API_VERSION >= 0x402
              (subfeature->type != SENSORS_SUBFEATURE_CURR_INPUT) &&
  #endif
 +#if SENSORS_API_VERSION >= 0x431
 +            (subfeature->type != SENSORS_SUBFEATURE_HUMIDITY_INPUT) &&
 +#endif
              (subfeature->type != SENSORS_SUBFEATURE_POWER_INPUT))
            continue;
  
        } /* while (subfeature) */
      }   /* while (feature) */
    }     /* while (chip) */
+ #endif /* (SENSORS_API_VERSION >= 0x400) */
  
    if (first_feature == NULL) {
      sensors_cleanup();
@@@ -258,6 -457,30 +347,30 @@@ static int sensors_read(void) 
    if (sensors_load_conf() != 0)
      return -1;
  
+ #if SENSORS_API_VERSION < 0x400
+   for (featurelist_t *fl = first_feature; fl != NULL; fl = fl->next) {
+     double value;
+     int status;
+     char plugin_instance[DATA_MAX_NAME_LEN];
+     char type_instance[DATA_MAX_NAME_LEN];
+     status = sensors_get_feature(*fl->chip, fl->data->number, &value);
+     if (status < 0)
+       continue;
+     status = sensors_snprintf_chip_name(plugin_instance,
+                                         sizeof(plugin_instance), fl->chip);
+     if (status < 0)
+       continue;
+     sstrncpy(type_instance, fl->data->name, sizeof(type_instance));
+     sensors_submit(plugin_instance, sensor_type_name_map[fl->type],
+                    type_instance, value);
+   } /* for fl = first_feature .. NULL */
+ /* #endif SENSORS_API_VERSION < 0x400 */
+ #elif (SENSORS_API_VERSION >= 0x400)
    for (featurelist_t *fl = first_feature; fl != NULL; fl = fl->next) {
      double value;
      int status;
      else if (fl->feature->type == SENSORS_FEATURE_CURR)
        type = "current";
  #endif
 +#if SENSORS_API_VERSION >= 0x431
 +    else if (fl->feature->type == SENSORS_FEATURE_HUMIDITY)
 +      type = "humidity";
 +#endif
      else
        continue;
  
      sensors_submit(plugin_instance, type, type_instance, value);
    } /* for fl = first_feature .. NULL */
+ #endif /* (SENSORS_API_VERSION >= 0x400) */
  
    return 0;
  } /* int sensors_read */
diff --combined src/write_prometheus.c
  static c_avl_tree_t *metrics;
  static pthread_mutex_t metrics_lock = PTHREAD_MUTEX_INITIALIZER;
  
 +static char *httpd_host = NULL;
  static unsigned short httpd_port = 9103;
  static struct MHD_Daemon *httpd;
  
  static cdtime_t staleness_delta = PROMETHEUS_DEFAULT_STALENESS_DELTA;
  
 -/* Unfortunately, protoc-c doesn't export it's implementation of varint, so we
 +/* Unfortunately, protoc-c doesn't export its implementation of varint, so we
   * need to implement our own. */
  static size_t varint(uint8_t buffer[static VARINT_UINT32_BYTES],
                       uint32_t value) {
@@@ -245,8 -244,9 +245,8 @@@ static int http_handler(void *cls, stru
  
    char const *accept = MHD_lookup_connection_value(connection, MHD_HEADER_KIND,
                                                     MHD_HTTP_HEADER_ACCEPT);
 -  _Bool want_proto =
 -      (accept != NULL) &&
 -      (strstr(accept, "application/vnd.google.protobuf") != NULL);
 +  bool want_proto = (accept != NULL) &&
 +                    (strstr(accept, "application/vnd.google.protobuf") != NULL);
  
    uint8_t scratch[4096] = {0};
    ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(scratch);
@@@ -689,7 -689,7 +689,7 @@@ static char *metric_family_name(data_se
   * necessary. */
  static Io__Prometheus__Client__MetricFamily *
  metric_family_get(data_set_t const *ds, value_list_t const *vl, size_t ds_index,
 -                  _Bool allocate) {
 +                  bool allocate) {
    char *name = metric_family_name(ds, vl, ds_index);
    if (name == NULL) {
      ERROR("write_prometheus plugin: Allocating metric family name failed.");
@@@ -747,7 -747,7 +747,7 @@@ static int prom_open_socket(int addrfam
    snprintf(service, sizeof(service), "%hu", httpd_port);
  
    struct addrinfo *res;
 -  int status = getaddrinfo(NULL, service,
 +  int status = getaddrinfo(httpd_host, service,
                             &(struct addrinfo){
                                 .ai_flags = AI_PASSIVE | AI_ADDRCONFIG,
                                 .ai_family = addrfamily,
  
    int fd = -1;
    for (struct addrinfo *ai = res; ai != NULL; ai = ai->ai_next) {
-     fd = socket(ai->ai_family, ai->ai_socktype | SOCK_CLOEXEC, 0);
+     int flags = ai->ai_socktype;
+ #ifdef SOCK_CLOEXEC
+     flags |= SOCK_CLOEXEC;
+ #endif
+     fd = socket(ai->ai_family, flags, 0);
      if (fd == -1)
        continue;
  
 -    int tmp = 1;
 -    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) != 0) {
 -      char errbuf[1024];
 -      WARNING("write_prometheus: setsockopt(SO_REUSEADDR) failed: %s",
 -              sstrerror(errno, errbuf, sizeof(errbuf)));
 +    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) != 0) {
 +      WARNING("write_prometheus plugin: setsockopt(SO_REUSEADDR) failed: %s",
 +              STRERRNO);
        close(fd);
        fd = -1;
        continue;
        continue;
      }
  
 +    char str_node[NI_MAXHOST];
 +    char str_service[NI_MAXSERV];
 +
 +    getnameinfo(ai->ai_addr, ai->ai_addrlen, str_node, sizeof(str_node),
 +                str_service, sizeof(str_service),
 +                NI_NUMERICHOST | NI_NUMERICSERV);
 +
 +    INFO("write_prometheus plugin: Listening on [%s]:%s.", str_node,
 +         str_service);
      break;
    }
  
@@@ -807,9 -805,7 +812,9 @@@ static struct MHD_Daemon *prom_start_da
    if (fd == -1)
      fd = prom_open_socket(PF_INET);
    if (fd == -1) {
 -    ERROR("write_prometheus plugin: Opening a listening socket failed.");
 +    ERROR("write_prometheus plugin: Opening a listening socket for [%s]:%hu "
 +          "failed.",
 +          (httpd_host != NULL) ? httpd_host : "::", httpd_port);
      return NULL;
    }
  
@@@ -856,15 -852,7 +861,15 @@@ static int prom_config(oconfig_item_t *
    for (int i = 0; i < ci->children_num; i++) {
      oconfig_item_t *child = ci->children + i;
  
 -    if (strcasecmp("Port", child->key) == 0) {
 +    if (strcasecmp("Host", child->key) == 0) {
 +#if MHD_VERSION >= 0x00090000
 +      cf_util_get_string(child, &httpd_host);
 +#else
 +      ERROR("write_prometheus plugin: Option `Host' not supported. Please "
 +            "upgrade libmicrohttpd to at least 0.9.0");
 +      return -1;
 +#endif
 +    } else if (strcasecmp("Port", child->key) == 0) {
        int status = cf_util_get_port_number(child);
        if (status > 0)
          httpd_port = (unsigned short)status;
@@@ -892,6 -880,7 +897,6 @@@ static int prom_init() 
    if (httpd == NULL) {
      httpd = prom_start_daemon();
      if (httpd == NULL) {
 -      ERROR("write_prometheus plugin: MHD_start_daemon() failed.");
        return -1;
      }
      DEBUG("write_prometheus plugin: Successfully started microhttpd %s",
@@@ -907,7 -896,7 +912,7 @@@ static int prom_write(data_set_t const 
  
    for (size_t i = 0; i < ds->ds_num; i++) {
      Io__Prometheus__Client__MetricFamily *fam =
 -        metric_family_get(ds, vl, i, /* allocate = */ 1);
 +        metric_family_get(ds, vl, i, /* allocate = */ true);
      if (fam == NULL)
        continue;
  
@@@ -934,7 -923,7 +939,7 @@@ static int prom_missing(value_list_t co
  
    for (size_t i = 0; i < ds->ds_num; i++) {
      Io__Prometheus__Client__MetricFamily *fam =
 -        metric_family_get(ds, vl, i, /* allocate = */ 0);
 +        metric_family_get(ds, vl, i, /* allocate = */ false);
      if (fam == NULL)
        continue;
  
@@@ -984,8 -973,6 +989,8 @@@ static int prom_shutdown() 
    }
    pthread_mutex_unlock(&metrics_lock);
  
 +  sfree(httpd_host);
 +
    return 0;
  }