Merge pull request #2986 from shastah/feature/curl-address-family
authorPavel Rochnyak <pavel2000@ngs.ru>
Wed, 15 May 2019 03:28:20 +0000 (10:28 +0700)
committerGitHub <noreply@github.com>
Wed, 15 May 2019 03:28:20 +0000 (10:28 +0700)
curl plugin: add AddressFamily

1  2 
src/collectd.conf.in
src/collectd.conf.pod
src/curl.c
src/curl_json.c
src/curl_xml.c

diff --combined src/collectd.conf.in
  #@BUILD_PLUGIN_WRITE_RIEMANN_TRUE@LoadPlugin write_riemann
  #@BUILD_PLUGIN_WRITE_SENSU_TRUE@LoadPlugin write_sensu
  #@BUILD_PLUGIN_WRITE_STACKDRIVER_TRUE@LoadPlugin write_stackdriver
 +#@BUILD_PLUGIN_WRITE_SYSLOG_TRUE@LoadPlugin write_syslog
  #@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb
  #@BUILD_PLUGIN_XENCPU_TRUE@LoadPlugin xencpu
  #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
  #<Plugin curl>
  #  <Page "stock_quotes">
  #    URL "http://finance.google.com/finance?q=NYSE%3AAMD"
+ #    AddressFamily "any"
  #    User "foo"
  #    Password "bar"
  #    Digest false
  
  #<Plugin curl_json>
  #  <URL "http://localhost:80/test.json">
+ #    AddressFamily "any"
  #    Instance "test_http_json"
  #    <Key "testArray/0">
  #      Type "gauge"
  # }
  ## See: http://wiki.apache.org/couchdb/Runtime_Statistics
  #  <URL "http://localhost:5984/_stats">
+ #    AddressFamily "ipv4"
  #    Instance "httpd"
  #    <Key "httpd/requests/count">
  #      Type "http_requests"
  #  </URL>
  ## Database status metrics:
  #  <URL "http://localhost:5984/_all_dbs">
+ #    AddressFamily "ipv6"
  #    Instance "dbs"
  #    <Key "*/doc_count">
  #      Type "gauge"
  
  #<Plugin curl_xml>
  #  <URL "http://localhost/stats.xml">
+ #    AddressFamily "any"
  #    Host "my_host"
  #    #Plugin "stats"
  #    Instance "some_instance"
  
  #<Plugin "intel_rdt">
  #  Cores "0-2"
 +#  Processes "sshd"
  #</Plugin>
  
  #<Plugin interface>
  #     Connection "xen:///"
  #     RefreshInterval 60
  #     Domain "name"
 +#     ReportBlockDevices true
 +#     ReportNetworkInterfaces true
  #     BlockDevice "name:device"
  #     BlockDeviceFormat target
  #     BlockDeviceFormatBasename false
  #     InterfaceDevice "name:device"
  #     IgnoreSelected false
  #     HostnameFormat name
 +#     HostnameMetadataXPath "/instance/name/text()"
 +#     HostnameMetadataNS "http://openstack.org/xmlns/libvirt/nova/1.0"
  #     InterfaceFormat name
  #     PluginInstanceFormat name
  #     Instances 1
 -#     ExtraStats "cpu_util disk disk_err domain_state fs_info job_stats_background pcpu perf vcpupin"
 +#     ExtraStats "cpu_util disk disk_err domain_state fs_info job_stats_background pcpu perf vcpupin disk_physical disk_allocation disk_capacity"
  #     PersistentNotification false
  #</Plugin>
  
  #    SeparateInstances false
  #    PreserveSeparator false
  #    DropDuplicateFields false
 +#    ReverseHost false
  #  </Node>
  #</Plugin>
  
  #  Url "https://monitoring.googleapis.com/v3"
  #</Plugin>
  
 +#<Plugin write_syslog>
 +#     <Node>
 +#             Host "localhost"
 +#             Port "44514"
 +#             Prefix "collectd"
 +#             MessageFormat "human"
 +#             HostTags ""
 +#             StoreRates false
 +#             AlwaysAppendDS false
 +#     </Node>
 +#</Plugin>
 +
  #<Plugin write_tsdb>
  #     <Node>
  #             Host "localhost"
diff --combined src/collectd.conf.pod
@@@ -1656,24 -1656,15 +1656,24 @@@ Defaults to B<true>
  
  =head2 Plugin C<cpufreq>
  
 -This plugin doesn't have any options. It reads
 +This plugin is available on Linux and FreeBSD only.  It doesn't have any
 +options.  On Linux it reads
  F</sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq> (for the first CPU
  installed) to get the current CPU frequency. If this file does not exist make
  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.
 +On Linux, 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.
 +
 +On FreeBSD it does a sysctl dev.cpu.0.freq and submits this as instance 0.
 +At this time FreeBSD only has one frequency setting for all cores.
 +See the BUGS section in the FreeBSD man page for cpufreq(4) for more details.
 +
 +On FreeBSD the plugin checks the success of sysctl dev.cpu.0.freq and
 +unregisters the plugin when this fails.  A message will be logged to indicate
 +this.
  
  =head2 Plugin C<cpusleep>
  
@@@ -1804,6 -1795,7 +1804,7 @@@ finance page and dispatch the value to 
      <Page "stock_quotes">
        Plugin "quotes"
        URL "http://finance.google.com/finance?q=NYSE%3AAMD"
+       AddressFamily "any"
        User "foo"
        Password "bar"
        Digest false
@@@ -1844,6 -1836,18 +1845,18 @@@ Defaults to C<curl>
  URL of the web site to retrieve. Since a regular expression will be used to
  extract information from this data, non-binary data is a big plus here ;)
  
+ =item B<AddressFamily> I<Type>
+ IP version to resolve URL to. Useful in cases when hostname in URL resolves
+ to both IPv4 and IPv6 addresses, and you are interested in using one of them
+ specifically.
+ Use C<ipv4> to enforce IPv4, C<ipv6> to enforce IPv6, or C<any> to keep the
+ default behavior of resolving addresses to all IP versions your system allows.
+ If C<libcurl> is compiled without IPv6 support, using C<ipv6> will result in
+ a warning and fallback to C<any>.
+ If C<Type> cannot be parsed, a warning will be printed and the whole B<Page>
+ block will be ignored.
  =item B<User> I<Name>
  
  Username to use if authorization is required to read the page.
@@@ -1955,6 -1959,7 +1968,7 @@@ C<_stats> runtime statistics module of 
  
    <Plugin curl_json>
      <URL "http://localhost:5984/_stats">
+       AddressFamily "any"
        Instance "httpd"
        <Key "httpd/requests/count">
          Type "http_requests"
@@@ -1999,6 -2004,18 +2013,18 @@@ The following options are valid within 
  
  =over 4
  
+ =item B<AddressFamily> I<Type>
+ IP version to resolve URL to. Useful in cases when hostname in URL resolves
+ to both IPv4 and IPv6 addresses, and you are interested in using one of them
+ specifically.
+ Use C<ipv4> to enforce IPv4, C<ipv6> to enforce IPv6, or C<any> to keep the
+ default behavior of resolving addresses to all IP versions your system allows.
+ If C<libcurl> is compiled without IPv6 support, using C<ipv6> will result in
+ a warning and fallback to C<any>.
+ If C<Type> cannot be parsed, a warning will be printed and the whole B<URL>
+ block will be ignored.
  =item B<Host> I<Name>
  
  Use I<Name> as the host name when submitting values. Defaults to the global
@@@ -2070,6 -2087,7 +2096,7 @@@ The B<curl_xml plugin> uses B<libcurl> 
  
   <Plugin "curl_xml">
     <URL "http://localhost/stats.xml">
+      AddressFamily "any"
       Host "my_host"
       #Plugin "curl_xml"
       Instance "some_instance"
@@@ -2106,6 -2124,18 +2133,18 @@@ Within the B<URL> block the following o
  
  =over 4
  
+ =item B<AddressFamily> I<Type>
+ IP version to resolve URL to. Useful in cases when hostname in URL resolves
+ to both IPv4 and IPv6 addresses, and you are interested in using one of them
+ specifically.
+ Use C<ipv4> to enforce IPv4, C<ipv6> to enforce IPv6, or C<any> to keep the
+ default behavior of resolving addresses to all IP versions your system allows.
+ If C<libcurl> is compiled without IPv6 support, using C<ipv6> will result in
+ a warning and fallback to C<any>.
+ If C<Type> cannot be parsed, a warning will be printed and the whole B<URL>
+ block will be ignored.
  =item B<Host> I<Name>
  
  Use I<Name> as the host name when submitting values. Defaults to the global
@@@ -3507,7 -3537,6 +3546,7 @@@ B<Synopsis:
  
    <Plugin "intel_rdt">
      Cores "0-2" "3,4,6" "8-10,15"
 +    Processes "sshd,qemu-system-x86" "bash"
    </Plugin>
  
  B<Options:>
@@@ -3523,10 -3552,11 +3562,10 @@@ recommended to set interval higher tha
  
  =item B<Cores> I<cores groups>
  
 -All events are reported on a per core basis. Monitoring of the events can be
 -configured for group of cores (aggregated statistics). This field defines groups
 -of cores on which to monitor supported events. The field is represented as list
 -of strings with core group values. Each string represents a list of cores in a
 -group. Allowed formats are:
 +Monitoring of the events can be configured for group of cores
 +(aggregated statistics). This field defines groups of cores on which to monitor
 +supported events. The field is represented as list of strings with core group
 +values. Each string represents a list of cores in a group. Allowed formats are:
      0,1,2,3
      0-10,20-18
      1,3,5-8,10,0x10-12
  If an empty string is provided as value for this field default cores
  configuration is applied - a separate group is created for each core.
  
 +=item B<Processes> I<process names groups>
 +
 +Monitoring of the events can be configured for group of processes
 +(aggregated statistics). This field defines groups of processes on which to
 +monitor supported events. The field is represented as list of strings with
 +process names group values. Each string represents a list of processes in a
 +group. Allowed format is:
 +    sshd,bash,qemu
 +
  =back
  
  B<Note:> By default global interval is used to retrieve statistics on monitored
@@@ -4462,12 -4483,6 +4501,12 @@@ For Modbus/RTU, specifies the path to t
  For Modbus/RTU, specifies the baud rate of the serial device.
  Note, connections currently support only 8/N/1.
  
 +=item B<UARTType> I<UARTType>
 +
 +For Modbus/RTU, specifies the type of the serial device.
 +RS232, RS422 and RS485 are supported. Defaults to RS232.
 +Available only on Linux systems with libmodbus>=2.9.4.
 +
  =item B<Interval> I<Interval>
  
  Sets the interval (in seconds) in which the values will be collected from this
@@@ -5357,9 -5372,8 +5396,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:
@@@ -6299,7 -6313,6 +6338,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:
@@@ -6333,13 -6346,6 +6372,13 @@@ 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>
@@@ -8421,26 -8427,26 +8460,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>
  
@@@ -8471,9 -8477,6 +8510,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
@@@ -8547,12 -8550,8 +8586,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>
  
@@@ -9276,51 -9275,13 +9315,51 @@@ surrounded by I</.../> and collectd wa
  
  The default is to collect statistics for all domains and all their devices.
  
 -Example:
 +B<Note:> B<BlockDevice> and B<InterfaceDevice> options are related to
 +corresponding B<*Format> options. Specifically, B<BlockDevice> filtering depends
 +on B<BlockDeviceFormat> setting - if user wants to filter block devices by
 +'target' name then B<BlockDeviceFormat> option has to be set to 'target' and
 +B<BlockDevice> option must be set to a valid block device target
 +name("/:hdb/"). Mixing formats and filter values from different worlds (i.e.,
 +using 'target' name as B<BlockDevice> value with B<BlockDeviceFormat> set to
 +'source') may lead to unexpected results (all devices filtered out or all
 +visible, depending on the value of B<IgnoreSelected> option).
 +Similarly, option B<InterfaceDevice> is related to B<InterfaceFormat> setting
 +(i.e., when user wants to use MAC address as a filter then B<InterfaceFormat>
 +has to be set to 'address' - using wrong type here may filter out all of the
 +interfaces).
 +
 +B<Example 1:>
 +
 +Ignore all I<hdb> devices on any domain, but other block devices (eg. I<hda>)
 +will be collected:
  
   BlockDevice "/:hdb/"
   IgnoreSelected "true"
 + BlockDeviceFormat "target"
  
 -Ignore all I<hdb> devices on any domain, but other block devices (eg. I<hda>)
 -will be collected.
 +B<Example 2:>
 +
 +Collect metrics only for block device on 'baremetal0' domain when its
 +'source' matches given path:
 +
 + BlockDevice "baremetal0:/var/lib/libvirt/images/baremetal0.qcow2"
 + BlockDeviceFormat source
 +
 +As you can see it is possible to filter devices/interfaces using
 +various formats - for block devices 'target' or 'source' name can be
 +used.  Interfaces can be filtered using 'name', 'address' or 'number'.
 +
 +B<Example 3:>
 +
 +Collect metrics only for domains 'baremetal0' and 'baremetal1' and
 +ignore any other domain:
 +
 + Domain "baremetal0"
 + Domain "baremetal1"
 +
 +It is possible to filter multiple block devices/domains/interfaces by
 +adding multiple filtering entries in separate lines.
  
  =item B<BlockDeviceFormat> B<target>|B<source>
  
@@@ -9351,11 -9312,6 +9390,11 @@@ to C<sda>
  Setting C<BlockDeviceFormat source> will cause the I<type instance> to be set
  to C<var_lib_libvirt_images_image1.qcow2>.
  
 +B<Note:> this option determines also what field will be used for
 +filtering over block devices (filter value in B<BlockDevice>
 +will be applied to target or source). More info about filtering
 +block devices can be found in the description of B<BlockDevice>.
 +
  =item B<BlockDeviceFormatBasename> B<false>|B<true>
  
  The B<BlockDeviceFormatBasename> controls whether the full path or the
@@@ -9370,7 -9326,7 +9409,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
@@@ -9383,9 -9339,6 +9422,9 @@@ B<hostname> means to use the global B<H
  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
  between, thus I<"foo:1234-1234-1234-1234">).
@@@ -9394,7 -9347,7 +9433,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
@@@ -9404,47 -9357,23 +9443,47 @@@ 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.
 +
 +B<Note:> this option determines also what field will be used for
 +filtering over interface device (filter value in B<InterfaceDevice>
 +will be applied to name, address or number).  More info about filtering
 +interfaces can be found in the description of B<InterfaceDevice>.
 +
 +=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>
  
@@@ -9466,7 -9395,9 +9505,7 @@@ 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<domain_state>: report domain state and reason as 'domain_state' metric.
  
  =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>
@@@ -9491,53 -9422,14 +9530,53 @@@ B<Note>: I<perf> metrics can't be colle
  
  =item B<vcpupin>: report pinning of domain VCPUs to host physical CPUs.
  
 +=item B<disk_physical>: report 'disk_physical' statistic for disk device.
 +B<Note>: This statistic is only reported for disk devices with 'source'
 +property available.
 +
 +=item B<disk_allocation>: report 'disk_allocation' statistic for disk device.
 +B<Note>: This statistic is only reported for disk devices with 'source'
 +property available.
 +
 +=item B<disk_capacity>: report 'disk_capacity' statistic for disk device.
 +B<Note>: This statistic is only reported for disk devices with 'source'
 +property available.
 +
  =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>
@@@ -9592,7 -9484,6 +9631,7 @@@ Synopsis
       LogSendErrors true
       Prefix "collectd"
       UseTags false
 +     ReverseHost false
     </Node>
   </Plugin>
  
@@@ -9704,30 -9595,6 +9743,30 @@@ are not used
  
  Default value: B<false>.
  
 +=item B<ReverseHost> B<false>|B<true>
 +
 +If set to B<true>, the (dot separated) parts of the B<host> field of the
 +I<value list> will be rewritten in reverse order. The rewrite happens I<before>
 +special characters are replaced with the B<EscapeCharacter>.
 +
 +This option might be convenient if the metrics are presented with Graphite in a
 +DNS like tree structure (probably without replacing dots in hostnames).
 +
 +Example:
 + Hostname "node3.cluster1.example.com"
 + LoadPlugin "cpu"
 + LoadPlugin "write_graphite"
 + <Plugin "write_graphite">
 +  <Node "graphite.example.com">
 +   EscapeCharacter "."
 +   ReverseHost true
 +  </Node>
 + </Plugin>
 +
 + result on the wire: com.example.cluster1.node3.cpu-0.cpu-idle 99.900993 1543010932
 +
 +Default value: B<false>.
 +
  =back
  
  =head2 Plugin C<write_log>
@@@ -10703,141 -10570,6 +10742,141 @@@ C<https://monitoring.googleapis.com/v3>
  
  =back
  
 +=head2 Plugin C<write_syslog>
 +
 +The C<write_syslog> plugin writes data in I<syslog> format log messages.
 +It implements the basic syslog protocol, RFC 5424, extends it with
 +content-based filtering, rich filtering capabilities,
 +flexible configuration options and adds features such as using TCP for transport.
 +The plugin can connect to a I<Syslog> daemon, like syslog-ng and rsyslog, that will
 +ingest metrics, transform and ship them to the specified output.
 +The plugin uses I<TCP> over the "line based" protocol with a default port 44514.
 +The data will be sent in blocks of at most 1428 bytes to minimize the number of
 +network packets.
 +
 +Synopsis:
 +
 + <Plugin write_syslog>
 +   ResolveInterval 60
 +   ResolveJitter 60
 +   <Node "example">
 +     Host "syslog-1.my.domain"
 +     Port "44514"
 +     Prefix "collectd"
 +     MessageFormat "human"
 +     HostTags ""
 +   </Node>
 + </Plugin>
 +
 +The configuration consists of one or more E<lt>B<Node>E<nbsp>I<Name>E<gt>
 +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 syslog node, it will request the hostname from
 +DNS. This can become a problem if the syslog 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_syslog 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_syslog 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
 +
 +=item B<Host> I<Address>
 +
 +Hostname or address to connect to. Defaults to C<localhost>.
 +
 +=item B<Port> I<Service>
 +
 +Service name or port number to connect to. Defaults to C<44514>.
 +
 +
 +=item B<HostTags> I<String>
 +
 +When set, I<HostTags> is added to the end of the metric.
 +It is intended to be used for adding additional metadata to tag the metric with.
 +Dots and whitespace are I<not> escaped in this string.
 +
 +Examples:
 +
 +When MessageFormat is set to "human".
 +
 +  ["prefix1" "example1"="example1_v"]["prefix2" "example2"="example2_v"]"
 +
 +When MessageFormat is set to "JSON", text should be in JSON format.
 +Escaping the quotation marks is required.
 +
 +  HostTags "\"prefix1\": {\"example1\":\"example1_v\",\"example2\":\"example2_v\"}"
 +
 +=item B<MessageFormat> I<String>
 +
 +I<MessageFormat> selects the format in which messages are sent to the
 +syslog deamon, human or JSON. Defaults to human.
 +
 +Syslog message format:
 +
 +<priority>VERSION ISOTIMESTAMP HOSTNAME APPLICATION PID MESSAGEID STRUCTURED-DATA MSG
 +
 +The difference between the message formats are in the STRUCTURED-DATA and MSG parts.
 +
 +Human format:
 +
 +  <166>1 ISOTIMESTAMP HOSTNAME collectd PID MESSAGEID
 +  ["collectd" "value": "v1" "plugin"="plugin_v" "plugin_instance"="plugin_instance_v"
 +  "type_instance"="type_instance_v" "type"="type_v" "ds_name"="ds_name_v" "interval"="interval_v" ]
 +  "host_tag_example"="host_tag_example_v" plugin_v.type_v.ds_name_v="v1"
 +
 +JSON format:
 +
 +  <166>1 ISOTIMESTAMP HOSTNAME collectd PID MESSAGEID STRUCTURED-DATA
 +  {
 +    "collectd": {
 +    "time": time_as_epoch, "interval": interval_v, "plugin": "plugin_v",
 +    "plugin_instance": "plugin_instance_v", "type":"type_v",
 +    "type_instance": "type_instance_v", "plugin_v": {"type_v": v1}
 +    } , "host":"host_v", "host_tag_example": "host_tag_example_v"
 +  }
 +
 +=item B<StoreRates> B<false>|B<true>
 +
 +If set to B<true>, convert counter values to rates. If set to B<false>
 +(the default) counter values are stored as is, as an increasing
 +integer number.
 +
 +=item B<AlwaysAppendDS> B<false>|B<true>
 +
 +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<Prefix> I<String>
 +
 +When set, I<Prefix> is added to all metrics names as a prefix. It is intended in
 +case you want to be able to define the source of the specific metric. Dots and
 +whitespace are I<not> escaped in this string.
 +
 +=back
 +
  =head2 Plugin C<xencpu>
  
  This plugin collects metrics of hardware CPU load for machine running Xen
@@@ -11826,7 -11558,7 +11865,7 @@@ be an FQDN
  =head1 IGNORELISTS
  
  B<Ignorelists> are a generic framework to either ignore some metrics or report
 -specific metircs only. Plugins usually provide one or more options to specify
 +specific metrics only. Plugins usually provide one or more options to specify
  the items (mounts points, devices, ...) and the boolean option
  C<IgnoreSelected>.
  
diff --combined src/curl.c
  
  #include "collectd.h"
  
 -#include "common.h"
  #include "plugin.h"
 -#include "utils_curl_stats.h"
 -#include "utils_match.h"
 +#include "utils/common/common.h"
 +#include "utils/curl_stats/curl_stats.h"
 +#include "utils/match/match.h"
  #include "utils_time.h"
  
  #include <curl/curl.h>
@@@ -57,6 -57,7 +57,7 @@@ struct web_page_s /* {{{ *
    char *instance;
  
    char *url;
+   int address_family;
    char *user;
    char *pass;
    char *credentials;
@@@ -345,6 -346,7 +346,7 @@@ static int cc_page_init_curl(web_page_
    curl_easy_setopt(wp->curl, CURLOPT_ERRORBUFFER, wp->curl_errbuf);
    curl_easy_setopt(wp->curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(wp->curl, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(wp->curl, CURLOPT_IPRESOLVE, wp->address_family);
  
    if (wp->user != NULL) {
  #ifdef HAVE_CURLOPT_USERNAME
@@@ -411,6 -413,7 +413,7 @@@ static int cc_config_add_page(oconfig_i
    }
    page->plugin_name = NULL;
    page->url = NULL;
+   page->address_family = CURL_IPRESOLVE_WHATEVER;
    page->user = NULL;
    page->pass = NULL;
    page->digest = false;
        status = cf_util_get_string(child, &page->plugin_name);
      else if (strcasecmp("URL", child->key) == 0)
        status = cf_util_get_string(child, &page->url);
-     else if (strcasecmp("User", child->key) == 0)
+     else if (strcasecmp("AddressFamily", child->key) == 0) {
+       char *af = NULL;
+       status = cf_util_get_string(child, &af);
+       if (status != 0 || af == NULL) {
+         WARNING("curl plugin: Cannot parse value of `%s' "
+                 "for instance `%s'.",
+                 child->key, page->instance);
+       } else if (strcasecmp("any", af) == 0) {
+         page->address_family = CURL_IPRESOLVE_WHATEVER;
+       } else if (strcasecmp("ipv4", af) == 0) {
+         page->address_family = CURL_IPRESOLVE_V4;
+       } else if (strcasecmp("ipv6", af) == 0) {
+         /* If curl supports ipv6, use it. If not, log a warning and
+          * fall back to default - don't set status to non-zero.
+          */
+         curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
+         if (curl_info->features & CURL_VERSION_IPV6)
+           page->address_family = CURL_IPRESOLVE_V6;
+         else
+           WARNING("curl plugin: IPv6 not supported by this libCURL. "
+                   "Using fallback `any'.");
+       } else {
+         WARNING("curl plugin: Unsupported value of `%s' "
+                 "for instance `%s'.",
+                 child->key, page->instance);
+         status = -1;
+       }
+     } else if (strcasecmp("User", child->key) == 0)
        status = cf_util_get_string(child, &page->user);
      else if (strcasecmp("Password", child->key) == 0)
        status = cf_util_get_string(child, &page->pass);
diff --combined src/curl_json.c
  
  #include "collectd.h"
  
 -#include "common.h"
  #include "plugin.h"
 -#include "utils_avltree.h"
 +#include "utils/avltree/avltree.h"
 +#include "utils/common/common.h"
 +#include "utils/curl_stats/curl_stats.h"
  #include "utils_complain.h"
 -#include "utils_curl_stats.h"
  
  #include <sys/types.h>
  #include <sys/un.h>
@@@ -88,6 -88,7 +88,7 @@@ struct cj_s /* {{{ *
    char *sock;
  
    char *url;
+   int address_family;
    char *user;
    char *pass;
    char *credentials;
@@@ -236,7 -237,7 +237,7 @@@ static int cj_cb_number(void *ctx, cons
    /* Create a null-terminated version of the string. */
    char buffer[number_len + 1];
    memcpy(buffer, number, number_len);
 -  buffer[sizeof(buffer) - 1] = 0;
 +  buffer[sizeof(buffer) - 1] = '\0';
  
    if (db->state[db->depth].entry == NULL ||
        db->state[db->depth].entry->type != KEY) {
@@@ -272,7 -273,7 +273,7 @@@ static int cj_cb_map_key(void *ctx, uns
    char name[in_name_len + 1];
  
    memmove(name, in_name, in_name_len);
 -  name[sizeof(name) - 1] = 0;
 +  name[sizeof(name) - 1] = '\0';
  
    if (cj_load_key(ctx, name) != 0)
      return CJ_CB_ABORT;
@@@ -582,6 -583,7 +583,7 @@@ static int cj_init_curl(cj_t *db) /* {{
    curl_easy_setopt(db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf);
    curl_easy_setopt(db->curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(db->curl, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(db->curl, CURLOPT_IPRESOLVE, db->address_family);
  
    if (db->user != NULL) {
  #ifdef HAVE_CURLOPT_USERNAME
@@@ -649,6 -651,7 +651,7 @@@ static int cj_config_add_url(oconfig_it
    }
  
    db->timeout = -1;
+   db->address_family = CURL_IPRESOLVE_WHATEVER;
  
    if (strcasecmp("URL", ci->key) == 0)
      status = cf_util_get_string(ci, &db->url);
        db->stats = curl_stats_from_config(child);
        if (db->stats == NULL)
          status = -1;
+     } else if (db->url && strcasecmp("AddressFamily", child->key) == 0) {
+       char *af = NULL;
+       status = cf_util_get_string(child, &af);
+       if (status != 0 || af == NULL) {
+         WARNING("curl_json plugin: Cannot parse value of `%s' for URL `%s'.",
+                 child->key, db->url);
+       } else if (strcasecmp("any", af) == 0) {
+         db->address_family = CURL_IPRESOLVE_WHATEVER;
+       } else if (strcasecmp("ipv4", af) == 0) {
+         db->address_family = CURL_IPRESOLVE_V4;
+       } else if (strcasecmp("ipv6", af) == 0) {
+         /* If curl supports ipv6, use it. If not, log a warning and
+          * fall back to default - don't set status to non-zero.
+          */
+         curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
+         if (curl_info->features & CURL_VERSION_IPV6)
+           db->address_family = CURL_IPRESOLVE_V6;
+         else
+           WARNING("curl_json plugin: IPv6 not supported by this libCURL. "
+                   "Using fallback `any'.");
+       } else {
+         WARNING("curl_json plugin: Unsupported value of `%s' for URL `%s'.",
+                 child->key, db->url);
+         status = -1;
+       }
      } else {
        WARNING("curl_json plugin: Option `%s' not allowed here.", child->key);
        status = -1;
diff --combined src/curl_xml.c
@@@ -21,9 -21,9 +21,9 @@@
  
  #include "collectd.h"
  
 -#include "common.h"
  #include "plugin.h"
 -#include "utils_curl_stats.h"
 +#include "utils/common/common.h"
 +#include "utils/curl_stats/curl_stats.h"
  #include "utils_llist.h"
  
  #include <libxml/parser.h>
@@@ -76,6 -76,7 +76,7 @@@ struct cx_s /* {{{ *
    char *host;
  
    char *url;
+   int address_family;
    char *user;
    char *pass;
    char *credentials;
@@@ -736,6 -737,7 +737,7 @@@ static int cx_init_curl(cx_t *db) /* {{
    curl_easy_setopt(db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf);
    curl_easy_setopt(db->curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(db->curl, CURLOPT_MAXREDIRS, 50L);
+   curl_easy_setopt(db->curl, CURLOPT_IPRESOLVE, db->address_family);
  
    if (db->user != NULL) {
  #ifdef HAVE_CURLOPT_USERNAME
@@@ -814,6 -816,7 +816,7 @@@ static int cx_config_add_url(oconfig_it
    }
  
    db->timeout = -1;
+   db->address_family = CURL_IPRESOLVE_WHATEVER;
  
    int status = cf_util_get_string(ci, &db->url);
    if (status != 0) {
        db->stats = curl_stats_from_config(child);
        if (db->stats == NULL)
          status = -1;
+     } else if (strcasecmp("AddressFamily", child->key) == 0) {
+       char *af = NULL;
+       status = cf_util_get_string(child, &af);
+       if (status != 0 || af == NULL) {
+         WARNING("curl_xml plugin: Cannot parse value of `%s' for URL `%s'.",
+                 child->key, db->url);
+       } else if (strcasecmp("any", af) == 0) {
+         db->address_family = CURL_IPRESOLVE_WHATEVER;
+       } else if (strcasecmp("ipv4", af) == 0) {
+         db->address_family = CURL_IPRESOLVE_V4;
+       } else if (strcasecmp("ipv6", af) == 0) {
+         /* If curl supports ipv6, use it. If not, log a warning and
+          * fall back to default - don't set status to non-zero.
+          */
+         curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
+         if (curl_info->features & CURL_VERSION_IPV6)
+           db->address_family = CURL_IPRESOLVE_V6;
+         else
+           WARNING("curl_xml plugin: IPv6 not supported by this libCURL. "
+                   "Using fallback `any'.");
+       } else {
+         WARNING("curl_xml plugin: Unsupported value of `%s' for URL `%s'.",
+                 child->key, db->url);
+         status = -1;
+       }
      } else {
        WARNING("curl_xml plugin: Option `%s' not allowed here.", child->key);
        status = -1;