Merge branch 'collectd-4.9' into collectd-4.10
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 17 Aug 2010 16:53:29 +0000 (18:53 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Tue, 17 Aug 2010 16:53:29 +0000 (18:53 +0200)
1  2 
src/collectd.conf.pod
src/configfile.c
src/curl_json.c
src/plugin.c
src/utils_match.c
src/utils_match.h

diff --combined src/collectd.conf.pod
@@@ -57,6 -57,33 +57,33 @@@ directory for the daemon
  Loads the plugin I<Plugin>. There must be at least one such line or B<collectd>
  will be mostly useless.
  
+ Starting with collectd 4.9, this may also be a block in which further options
+ affecting the behavior of B<LoadPlugin> may be specified. The following
+ options are allowed inside a B<LoadPlugin> block:
+   <LoadPlugin perl>
+     Globals true
+   </LoadPlugin>
+ =over 4
+ =item B<Globals> B<true|false>
+ If enabled, collectd will export all global symbols of the plugin (and of all
+ libraries loaded as dependencies of the plugin) and, thus, makes those symbols
+ available for resolving unresolved symbols in subsequently loaded plugins if
+ that is supported by your system. By default, this is disabled.
+ This is useful (or possibly even required), e.E<nbsp>g., when loading a plugin
+ that embeds some scripting language into the daemon (e.E<nbsp>g. the C<perl>
+ or C<python> plugins). Scripting languages usually provide means to load
+ extensions written in C. Those extensions require symbols provided by the
+ interpreter, which is loaded as a dependency of the respective collectd
+ plugin. See the documentation of those plugins (e.E<nbsp>g.,
+ L<collectd-perl(5)> or L<collectd-python(5)>) for details.
+ =back
  =item B<Include> I<Path>
  
  If I<Path> points to a file, includes that file. If I<Path> points to a
@@@ -102,16 -129,6 +129,16 @@@ Configures the interval in which to que
  values lead to a higher system load produced by collectd, while higher values
  lead to more coarse statistics.
  
 +=item B<Timeout> I<Iterations>
 +
 +Consider a value list "missing" when no update has been read or received for
 +I<Iterations> iterations. By default, I<collectd> considers a value list
 +missing when no update has been received for twice the update interval. Since
 +this setting uses iterations, the maximum allowed time without update depends
 +on the I<Interval> information contained in each value list. This is used in
 +the I<Threshold> configuration to dispatch notifications about missing values,
 +see L<"THRESHOLD CONFIGURATION"> below.
 +
  =item B<ReadThreads> I<Num>
  
  Number of threads to start for reading plugins. The default value is B<5>, but
@@@ -629,110 -646,6 +656,110 @@@ Type-instance to use. Defaults to the c
  
  =back
  
 +=head2 Plugin C<curl_xml>
 +
 +The B<curl_xml plugin> uses B<libcurl> (L<http://curl.haxx.se/>) and B<libxml2>
 +(L<http://xmlsoft.org/>) to retrieve XML data via cURL.
 +
 + <Plugin "curl_xml">
 +   <URL "http://localhost/stats.xml">
 +     Host "my_host"
 +     Instance "some_instance"
 +     User "collectd"
 +     Password "thaiNg0I"
 +     VerifyPeer true
 +     VerifyHost true
 +     CACert "/path/to/ca.crt"
 +
 +     <XPath "table[@id=\"magic_level\"]/tr">
 +       Type "magic_level"
 +       #InstancePrefix "prefix-"
 +       InstanceFrom "td[1]"
 +       ValuesFrom "td[2]/span[@class=\"level\"]"
 +     </XPath>
 +   </URL>
 + </Plugin>
 +
 +In the B<Plugin> block, there may be one or more B<URL> blocks, each defining a
 +URL to be fetched via HTTP (using libcurl). Within each B<URL> block there are
 +options which specify the connection parameters, for example authentication
 +information, and one or more B<XPath> blocks.
 +
 +Each B<XPath> block specifies how to get one type of information. The
 +string argument must be a valid XPath expression which returns a list
 +of "base elements". One value is dispatched for each "base element". The
 +I<type instance> and values are looked up using further I<XPath> expressions
 +that should be relative to the base element.
 +
 +Within the B<URL> block the following options are accepted:
 +
 +=over 4
 +
 +=item B<Host> I<Name>
 +
 +Use I<Name> as the host name when submitting values. Defaults to the global
 +host name setting.
 +
 +=item B<Instance> I<Instance>
 +
 +Use I<Instance> as the plugin instance when submitting values. Defaults to an
 +empty string (no plugin instance).
 +
 +=item B<User> I<User>
 +=item B<Password> I<Password>
 +=item B<VerifyPeer> B<true>|B<false>
 +=item B<VerifyHost> B<true>|B<false>
 +=item B<CACert> I<CA Cert File>
 +
 +These options behave exactly equivalent to the appropriate options of the
 +I<cURL> and I<cURL-JSON> plugins. Please see there for a detailed description.
 +
 +=item E<lt>B<XPath> I<XPath-expression>E<gt>
 +
 +Within each B<URL> block, there must be one or more B<XPath> blocks. Each
 +B<XPath> block specifies how to get one type of information. The string
 +argument must be a valid XPath expression which returns a list of "base
 +elements". One value is dispatched for each "base element".
 +
 +Within the B<XPath> block the following options are accepted:
 +
 +=over 4
 +
 +=item B<Type> I<Type>
 +
 +Specifies the I<Type> used for submitting patches. This determines the number
 +of values that are required / expected and whether the strings are parsed as
 +signed or unsigned integer or as double values. See L<types.db(5)> for details.
 +This option is required.
 +
 +=item B<InstancePrefix> I<InstancePrefix>
 +
 +Prefix the I<type instance> with I<InstancePrefix>. The values are simply
 +concatenated together without any separator.
 +This option is optional.
 +
 +=item B<InstanceFrom> I<InstanceFrom>
 +
 +Specifies a XPath expression to use for determining the I<type instance>. The
 +XPath expression must return exactly one element. The element's value is then
 +used as I<type instance>, possibly prefixed with I<InstancePrefix> (see above).
 +
 +This value is required. As a special exception, if the "base XPath expression"
 +(the argument to the B<XPath> block) returns exactly one argument, then this
 +option may be omitted.
 +
 +=item B<ValuesFrom> I<ValuesFrom> [I<ValuesFrom> ...]
 +
 +Specifies one or more XPath expression to use for reading the values. The
 +number of XPath expressions must match the number of data sources in the
 +I<type> specified with B<Type> (see above). Each XPath expression must return
 +exactly one element. The element's value is then parsed as a number and used as
 +value for the appropriate value in the value list dispatched to the daemon.
 +
 +=back
 +
 +=back
 +
  =head2 Plugin C<dbi>
  
  This plugin uses the B<dbi> library (L<http://libdbi.sourceforge.net/>) to
@@@ -1218,12 -1131,6 +1245,12 @@@ note that there are 1000 bytes in a kil
  
  Controls whether or not to recurse into subdirectories. Enabled by default.
  
 +=item B<IncludeHidden> I<true>|I<false>
 +
 +Controls whether or not to include "hidden" files and directories in the count.
 +"Hidden" files and directories are those, whose name begins with a dot.
 +Defaults to I<false>, i.e. by default hidden files and directories are ignored.
 +
  =back
  
  =head2 Plugin C<GenericJMX>
@@@ -1593,11 -1500,6 +1620,11 @@@ running in foreground- or non-daemon-mo
  
  Prefix all lines printed by the current time. Defaults to B<true>.
  
 +=item B<PrintSeverity> B<true>|B<false>
 +
 +When enabled, all lines are prefixed by the severity of the log message, for
 +example "warning". Defaults to B<false>.
 +
  =back
  
  B<Note>: There is no need to notify the daemon after moving or removing the
@@@ -1698,132 -1600,6 +1725,132 @@@ TCP-Port to connect to. Defaults to B<1
  
  =back
  
 +=head2 Plugin C<modbus>
 +
 +The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP 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).
 +
 +Synopsis:
 +
 + <Data "voltage-input-1">
 +   RegisterBase 0
 +   RegisterType float
 +   Type voltage
 +   Instance "input-1"
 + </Data>
 + 
 + <Data "voltage-input-2">
 +   RegisterBase 2
 +   RegisterType float
 +   Type voltage
 +   Instance "input-2"
 + </Data>
 + 
 + <Host "modbus.example.com">
 +   Address "192.168.0.42"
 +   Port    "502"
 +   Interval 60
 +   
 +   <Slave 1>
 +     Instance "power-supply"
 +     Collect  "voltage-input-1"
 +     Collect  "voltage-input-2"
 +   </Slave>
 + </Host>
 +
 +=over 4
 +
 +=item E<lt>B<Data> I<Name>E<gt> blocks
 +
 +Data blocks define a mapping between register numbers and the "types" used by
 +I<collectd>.
 +
 +Within E<lt>DataE<nbsp>/E<gt> blocks, the following options are allowed:
 +
 +=over 4
 +
 +=item B<RegisterBase> I<Number>
 +
 +Configures the base register to read from the device. If the option
 +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<Uint16>|B<Uint32>|B<Float>
 +
 +Specifies what kind of data is returned by the device. If the type is 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<Type> I<Type>
 +
 +Specifies the "type" (data set) to use when dispatching the value to
 +I<collectd>. Currently, only data sets with exactly one data source are
 +supported.
 +
 +=item B<Instance> I<Instance>
 +
 +Sets the type instance to use when dispatching the value to I<collectd>. If
 +unset, an empty string (no type instance) is used.
 +
 +=back
 +
 +=item E<lt>B<Host> I<Name>E<gt> blocks
 +
 +Host blocks are used to specify to which hosts to connect and what data to read
 +from their "slaves". The string argument I<Name> is used as hostname when
 +dispatching the values to I<collectd>.
 +
 +Within E<lt>HostE<nbsp>/E<gt> blocks, the following options are allowed:
 +
 +=over 4
 +
 +=item B<Address> I<Hostname>
 +
 +Specifies the node name (the actual network address) used to connect to the
 +host. This may be an IP address or a hostname. Please note that the used
 +I<libmodbus> library only supports IPv4 at the moment.
 +
 +=item B<Port> I<Service>
 +
 +Specifies the port used to connect to the host. The port can either be given as
 +a number or as a service name. Please note that the I<Service> argument must be
 +a string, even if ports are given in their numerical form. Defaults to "502".
 +
 +=item B<Interval> I<Interval>
 +
 +Sets the interval (in seconds) in which the values will be collected from this
 +host. By default the global B<Interval> setting will be used.
 +
 +=item E<lt>B<Slave> I<ID>E<gt>
 +
 +Over each TCP connection, multiple Modbus devices may be reached. The slave ID
 +is used to specify which device should be addressed. For each device you want
 +to query, one B<Slave> block must be given.
 +
 +Within E<lt>SlaveE<nbsp>/E<gt> blocks, the following options are allowed:
 +
 +=over 4
 +
 +=item B<Instance> I<Instance>
 +
 +Specify the plugin instance to use when dispatching the values to I<collectd>.
 +By default "slave_I<ID>" is used.
 +
 +=item B<Collect> I<DataName>
 +
 +Specifies which data to retrieve from the device. I<DataName> must be the same
 +string as the I<Name> argument passed to a B<Data> block. You can specify this
 +option multiple times to collect more than one value from a slave. At least one
 +B<Collect> option is mandatory.
 +
 +=back
 +
 +=back
 +
 +=back
 +
  =head2 Plugin C<mysql>
  
  The C<mysql plugin> requires B<mysqlclient> to be installed. It connects to
@@@ -2522,15 -2298,6 +2549,15 @@@ B<None> require this setting
  This feature is only available if the I<network> plugin was linked with
  I<libgcrypt>.
  
 +=item B<Interface> I<Interface name>
 +
 +Set the outgoing interface for IP packets. This applies at least
 +to IPv6 packets and if possible to IPv4. If this option is not applicable,
 +undefined or a non-existent interface name is specified, the default
 +behavior is to let the kernel choose the appropriate interface. Be warned
 +that the manual selection of an interface for unicast traffic is only
 +necessary in rare cases.
 +
  =back
  
  =item B<E<lt>Listen> I<Host> [I<Port>]B<E<gt>>
@@@ -2579,14 -2346,6 +2606,14 @@@ Each time a packet is received, the mod
  using L<stat(2)>. If the file has been changed, the contents is re-read. While
  the file is being read, it is locked using L<fcntl(2)>.
  
 +=item B<Interface> I<Interface name>
 +
 +Set the incoming interface for IP packets explicitly. This applies at least
 +to IPv6 packets and if possible to IPv4. If this option is not applicable,
 +undefined or a non-existent interface name is specified, the default
 +behavior is, to let the kernel choose the appropriate interface. Thus incoming
 +traffic gets only accepted, if it arrives on the given interface.
 +
  =back
  
  =item B<TimeToLive> I<1-255>
@@@ -2936,24 -2695,12 +2963,24 @@@ and the client's "common name" will be 
  when reading multiple status files. Enabling this option is recommended, but to
  maintain backwards compatibility this option is disabled by default.
  
 -=item B<Compression> B<true>|B<false>
 +=item B<CollectCompression> B<true>|B<false>
  
  Sets whether or not statistics about the compression used by OpenVPN should be
  collected. This information is only available in I<single> mode. Enabled by
  default.
  
 +=item B<CollectIndividualUsers> B<true>|B<false>
 +
 +Sets whether or not traffic information is collected for each connected client
 +individually. If set to false, currently no traffic data is collected at all
 +because aggregating this data in a save manner is tricky. Defaults to B<true>.
 +
 +=item B<CollectUserCount> B<true>|B<false>
 +
 +When enabled, the number of currently connected clients or users is collected.
 +This is especially interesting when B<CollectIndividualUsers> is disabled, but
 +can be configured independently from that option. Defaults to B<false>.
 +
  =back
  
  =head2 Plugin C<oracle>
@@@ -3023,83 -2770,6 +3050,83 @@@ refer to them from
  This plugin embeds a Perl-interpreter into collectd and provides an interface
  to collectd's plugin system. See L<collectd-perl(5)> for its documentation.
  
 +=head2 Plugin C<pinba>
 +
 +The I<Pinba plugin> receives profiling information from I<Pinba>, an extension
 +for the I<PHP> interpreter. At the end of executing a script, i.e. after a
 +PHP-based webpage has been delivered, the extension will send a UDP packet
 +containing timing information, peak memory usage and so on. The plugin will
 +wait for such packets, parse them and account the provided information, which
 +is then dispatched to the daemon once per interval.
 +
 +Synopsis:
 +
 + <Plugin pinba>
 +   Address "::0"
 +   Port "30002"
 +   # Overall statistics for the website.
 +   <View "www-total">
 +     Server "www.example.com"
 +   </View>
 +   # Statistics for www-a only
 +   <View "www-a">
 +     Host "www-a.example.com"
 +     Server "www.example.com"
 +   </View>
 +   # Statistics for www-b only
 +   <View "www-b">
 +     Host "www-b.example.com"
 +     Server "www.example.com"
 +   </View>
 + </Plugin>
 +
 +The plugin provides the following configuration options:
 +
 +=over 4
 +
 +=item B<Address> I<Node>
 +
 +Configures the address used to open a listening socket. By default, plugin will
 +bind to the I<any> address C<::0>.
 +
 +=item B<Port> I<Service>
 +
 +Configures the port (service) to bind to. By default the default Pinba port
 +"30002" will be used. The option accepts service names in addition to port
 +numbers and thus requires a I<string> argument.
 +
 +=item E<lt>B<View> I<Name>E<gt> block
 +
 +The packets sent by the Pinba extension include the hostname of the server, the
 +server name (the name of the virtual host) and the script that was executed.
 +Using B<View> blocks it is possible to separate the data into multiple groups
 +to get more meaningful statistics. Each packet is added to all matching groups,
 +so that a packet may be accounted for more than once.
 +
 +=over 4
 +
 +=item B<Host> I<Host>
 +
 +Matches the hostname of the system the webserver / script is running on. This
 +will contain the result of the L<gethostname(2)> system call. If not
 +configured, all hostnames will be accepted.
 +
 +=item B<Server> I<Server>
 +
 +Matches the name of the I<virtual host>, i.e. the contents of the
 +C<$_SERVER["SERVER_NAME"]> variable when within PHP. If not configured, all
 +server names will be accepted.
 +
 +=item B<Script> I<Script>
 +
 +Matches the name of the I<script name>, i.e. the contents of the
 +C<$_SERVER["SCRIPT_NAME"]> variable when within PHP. If not configured, all
 +script names will be accepted.
 +
 +=back
 +
 +=back
 +
  =head2 Plugin C<ping>
  
  The I<Ping> plugin starts a new thread which sends ICMP "ping" packets to the
@@@ -3153,7 -2823,7 +3180,7 @@@ operating systems
  
  =item B<MaxMissed> I<Packets>
  
 -Trigger a DNS resolv after the host has not replied to I<Packets> packets. This
 +Trigger a DNS resolve after the host has not replied to I<Packets> packets. This
  enables the use of dynamic DNS services (like dyndns.org) with the ping plugin.
  
  Default: B<-1> (disabled)
@@@ -3218,7 -2888,6 +3245,7 @@@ L<http://www.postgresql.org/docs/manual
      </Database>
  
      <Database bar>
 +      Interval 300
        Service "service_name"
        Query backend # predefined
        Query rt36_tickets
@@@ -3282,8 -2951,7 +3309,8 @@@ The username used to connect to the dat
  
  =item I<interval>
  
 -The interval collectd is using (as specified by the B<Interval> option).
 +The interval with which this database is queried (as specified by the database
 +specific or global B<Interval> options).
  
  =back
  
@@@ -3421,11 -3089,6 +3448,11 @@@ for details
  
  =over 4
  
 +=item B<Interval> I<seconds>
 +
 +Specify the interval with which the database should be queried. The default is
 +to use the global B<Interval> setting.
 +
  =item B<Host> I<hostname>
  
  Specify the hostname or IP of the PostgreSQL server to connect to. If the
@@@ -3706,8 -3369,6 +3733,8 @@@ multiple routers
        User "collectd"
        Password "secr3t"
        CollectInterface true
 +      CollectCPULoad true
 +      CollectMemory true
      </Router>
      <Router>
        Host "router1.example.com"
        Password "5ecret"
        CollectInterface true
        CollectRegistrationTable true
 +      CollectDF true
 +      CollectDisk true
      </Router>
    </Plugin>
  
@@@ -3754,29 -3413,6 +3781,29 @@@ present on the device. Defaults to B<fa
  When set to B<true>, information about wireless LAN connections will be
  collected. Defaults to B<false>.
  
 +=item B<CollectCPULoad> B<true>|B<false>
 +
 +When set to B<true>, information about the CPU usage will be collected. The
 +number is a dimensionless value where zero indicates no CPU usage at all.
 +Defaults to B<false>.
 +
 +=item B<CollectMemory> B<true>|B<false>
 +
 +When enabled, the amount of used and free memory will be collected. How used
 +memory is calculated is unknown, for example whether or not caches are counted
 +as used space.
 +Defaults to B<false>.
 +
 +=item B<CollectDF> B<true>|B<false>
 +
 +When enabled, the amount of used and free disk space will be collected.
 +Defaults to B<false>.
 +
 +=item B<CollectDisk> B<true>|B<false>
 +
 +When enabled, the number of sectors written and bad blocks will be collected.
 +Defaults to B<false>.
 +
  =back
  
  =head2 Plugin C<rrdcached>
@@@ -4109,7 -3745,6 +4136,7 @@@ user using (extended) regular expressio
        </Match>
        <Match>
          Regex "\\<R=local_user\\>"
 +        ExcludeRegex "\\<R=local_user\\>.*mail_spool defer"
          DSType "CounterInc"
          Type "counter"
          Instance "local_user"
@@@ -4144,13 -3779,6 +4171,13 @@@ want to match literal parentheses you n
  
    Regex "SPAM \\(Score: (-?[0-9]+\\.[0-9]+)\\)"
  
 +=item B<ExcludeRegex> I<regex>
 +
 +Sets an optional regular expression to use for excluding lines from the match.
 +An example which excludes all connections from localhost from the match:
 +
 +  ExcludeRegex "127\\.0\\.0\\.1"
 +
  =item B<DSType> I<Type>
  
  Sets how the values are cumulated. I<Type> is one of:
@@@ -4175,25 -3803,37 +4202,37 @@@ Use the last number found
  
  =item B<CounterSet>
  
- The matched number is a counter. Simply sets the internal counter to this
- value.
+ =item B<DeriveSet>
+ =item B<AbsoluteSet>
+ The matched number is a counter. Simply I<sets> the internal counter to this
+ value. Variants exist for C<COUNTER>, C<DERIVE>, and C<ABSOLUTE> data sources.
  
  =item B<CounterAdd>
  
- Add the matched value to the internal counter.
+ =item B<DeriveAdd>
+ Add the matched value to the internal counter. In case of B<DeriveAdd>, the
+ matched number may be negative, which will effectively subtract from the
+ internal counter.
  
  =item B<CounterInc>
  
- Increase the internal counter by one. This B<DSType> is the only one that does
- not use the matched subexpression, but simply counts the number of matched
+ =item B<DeriveInc>
+ Increase the internal counter by one. These B<DSType> are the only ones that do
+ 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.
  
  =back
  
  As you'd expect the B<Gauge*> types interpret the submatch as a floating point
- number, using L<strtod(3)>. The B<CounterSet> and B<CounterAdd> interpret the
- submatch as an integer using L<strtoll(3)>. B<CounterInc> does not use the
- submatch at all and it may be omitted in this case.
+ 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.
  
  =item B<Type> I<Type>
  
@@@ -4506,12 -4146,6 +4545,12 @@@ create output in the I<JavaScript Objec
  
  Defaults to B<Command>.
  
 +=item B<StoreRates> B<true|false>
 +
 +If set to B<true>, convert counter values to rates. If set to B<false> (the
 +default) counter values are stored as is, i.E<nbsp>e. as an increasing integer
 +number.
 +
  =back
  
  =head1 THRESHOLD CONFIGURATION
@@@ -4533,12 -4167,10 +4572,12 @@@ as a moving average or similar - at lea
  
  Also, all values that match a threshold are considered to be relevant or
  "interesting". As a consequence collectd will issue a notification if they are
 -not received for twice the last timeout of the values. If, for example, some
 -hosts sends it's CPU statistics to the server every 60 seconds, a notification
 -will be dispatched after about 120 seconds. It may take a little longer because
 -the timeout is checked only once each B<Interval> on the server.
 +not received for B<Timeout> iterations. The B<Timeout> configuration option is
 +explained in section L<"GLOBAL OPTIONS">. If, for example, B<Timeout> is set to
 +"2" (the default) and some hosts sends it's CPU statistics to the server every
 +60 seconds, a notification will be dispatched after about 120 seconds. It may
 +take a little longer because the timeout is checked only once each B<Interval>
 +on the server.
  
  When a value comes within range again or is received after it was missing, an
  "OKAY-notification" is dispatched.
@@@ -5021,12 -4653,6 +5060,12 @@@ Match values where the given regular ex
  the identifier of a value. If multiple regular expressions are given, B<all>
  regexen must match for a value to match.
  
 +=item B<Invert> B<false>|B<true>
 +
 +When set to B<true>, the result of the match is inverted, i.e. all value lists
 +where all regular expressions apply are not matched, all other value lists are
 +matched. Defaults to B<false>.
 +
  =back
  
  Example:
diff --combined src/configfile.c
@@@ -99,7 -99,6 +99,7 @@@ static cf_global_option_t cf_global_opt
        {"FQDNLookup",  NULL, "false"},
        {"Interval",    NULL, "10"},
        {"ReadThreads", NULL, "5"},
 +      {"Timeout",     NULL, "2"},
        {"PreCacheChain",  NULL, "PreCache"},
        {"PostCacheChain", NULL, "PostCache"}
  };
@@@ -701,11 -700,10 +701,10 @@@ static oconfig_item_t *cf_read_generic 
                if (status != 0)
                {
                        char errbuf[1024];
-                       ERROR ("configfile: stat (%s) failed: %s",
+                       WARNING ("configfile: stat (%s) failed: %s",
                                        path_ptr,
                                        sstrerror (errno, errbuf, sizeof (errbuf)));
-                       oconfig_free (root);
-                       return (NULL);
+                       continue;
                }
  
                if (S_ISREG (statbuf.st_mode))
                        temp = cf_read_dir (path_ptr, depth);
                else
                {
-                       ERROR ("configfile: %s is neither a file nor a "
+                       WARNING ("configfile: %s is neither a file nor a "
                                        "directory.", path);
                        continue;
                }
  
        wordfree (&we);
  
+       if (root->children == NULL)
+       {
+               oconfig_free (root);
+               return (NULL);
+       }
        return (root);
  } /* oconfig_item_t *cf_read_generic */
  /* #endif HAVE_WORDEXP_H */
@@@ -958,45 -962,6 +963,45 @@@ int cf_util_get_string (const oconfig_i
        return (0);
  } /* }}} int cf_util_get_string */
  
 +/* Assures the config option is a string and copies it to the provided buffer.
 + * Assures null-termination. */
 +int cf_util_get_string_buffer (const oconfig_item_t *ci, char *buffer, /* {{{ */
 +              size_t buffer_size)
 +{
 +      if ((ci == NULL) || (buffer == NULL) || (buffer_size < 1))
 +              return (EINVAL);
 +
 +      if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
 +      {
 +              ERROR ("cf_util_get_string_buffer: The %s option requires "
 +                              "exactly one string argument.", ci->key);
 +              return (-1);
 +      }
 +
 +      strncpy (buffer, ci->values[0].value.string, buffer_size);
 +      buffer[buffer_size - 1] = 0;
 +
 +      return (0);
 +} /* }}} int cf_util_get_string_buffer */
 +
 +/* Assures the config option is a number and returns it as an int. */
 +int cf_util_get_int (const oconfig_item_t *ci, int *ret_value) /* {{{ */
 +{
 +      if ((ci == NULL) || (ret_value == NULL))
 +              return (EINVAL);
 +
 +      if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
 +      {
 +              ERROR ("cf_util_get_int: The %s option requires "
 +                              "exactly one numeric argument.", ci->key);
 +              return (-1);
 +      }
 +
 +      *ret_value = (int) ci->values[0].value.number;
 +
 +      return (0);
 +} /* }}} int cf_util_get_int */
 +
  int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
  {
        if ((ci == NULL) || (ret_bool == NULL))
        if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
        {
                ERROR ("cf_util_get_boolean: The %s option requires "
 -                              "exactly one string argument.", ci->key);
 +                              "exactly one boolean argument.", ci->key);
                return (-1);
        }
  
diff --combined src/curl_json.c
@@@ -1,7 -1,7 +1,7 @@@
  /**
   * collectd - src/curl_json.c
   * Copyright (C) 2009       Doug MacEachern
-  * Copyright (C) 2006-2009  Florian octo Forster
+  * Copyright (C) 2006-2010  Florian octo Forster
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
@@@ -130,59 -130,57 +130,57 @@@ static int cj_get_type (cj_key_t *key
  }
  
  /* yajl callbacks */
- static int cj_cb_integer (void *ctx, long val)
+ #define CJ_CB_ABORT    0
+ #define CJ_CB_CONTINUE 1
+ /* "number" may not be null terminated, so copy it into a buffer before
+  * parsing. */
+ static int cj_cb_number (void *ctx,
+     const char *number, unsigned int number_len)
  {
+   char buffer[number_len + 1];
    cj_t *db = (cj_t *)ctx;
    cj_key_t *key = db->state[db->depth].key;
+   char *endptr;
+   value_t vt;
+   int type;
  
-   if (key != NULL)
-   {
-     value_t vt;
-     int type;
+   if (key == NULL)
+     return (CJ_CB_CONTINUE);
  
-     type = cj_get_type (key);
-     if (type == DS_TYPE_COUNTER)
-       vt.counter = (counter_t) val;
-     else if (type == DS_TYPE_GAUGE)
-       vt.gauge = (gauge_t) val;
-     else if (type == DS_TYPE_DERIVE)
-       vt.derive = (derive_t) val;
-     else if (type == DS_TYPE_ABSOLUTE)
-       vt.absolute = (absolute_t) val;
-     else
-       return 0;
+   memcpy (buffer, number, number_len);
+   buffer[sizeof (buffer) - 1] = 0;
  
-     cj_submit (db, key, &vt);
-   }
-   return 1;
- }
+   type = cj_get_type (key);
  
- static int cj_cb_double (void *ctx, double val)
- {
-   cj_t *db = (cj_t *)ctx;
-   cj_key_t *key = db->state[db->depth].key;
+   endptr = NULL;
+   errno = 0;
  
-   if (key != NULL)
+   if (type == DS_TYPE_COUNTER)
+     vt.counter = (counter_t) strtoull (buffer, &endptr, /* base = */ 0);
+   else if (type == DS_TYPE_GAUGE)
+     vt.gauge = (gauge_t) strtod (buffer, &endptr);
+   else if (type == DS_TYPE_DERIVE)
+     vt.derive = (derive_t) strtoll (buffer, &endptr, /* base = */ 0);
+   else if (type == DS_TYPE_ABSOLUTE)
+     vt.absolute = (absolute_t) strtoull (buffer, &endptr, /* base = */ 0);
+   else
    {
-     value_t vt;
-     int type;
-     type = cj_get_type (key);
-     if (type == DS_TYPE_COUNTER)
-       vt.counter = (counter_t) val;
-     else if (type == DS_TYPE_GAUGE)
-       vt.gauge = (gauge_t) val;
-     else if (type == DS_TYPE_DERIVE)
-       vt.derive = (derive_t) val;
-     else if (type == DS_TYPE_ABSOLUTE)
-       vt.absolute = (absolute_t) val;
-     else
-       return 0;
+     ERROR ("curl_json plugin: Unknown data source type: \"%s\"", key->type);
+     return (CJ_CB_ABORT);
+   }
  
-     cj_submit (db, key, &vt);
+   if ((endptr == &buffer[0]) || (errno != 0))
+   {
+     NOTICE ("curl_json plugin: Overflow while parsing number. "
+         "Ignoring this value.");
+     return (CJ_CB_CONTINUE);
    }
-   return 1;
- }
+   cj_submit (db, key, &vt);
+   return (CJ_CB_CONTINUE);
+ } /* int cj_cb_number */
  
  static int cj_cb_map_key (void *ctx, const unsigned char *val,
                              unsigned int len)
        db->state[db->depth].key = NULL;
    }
  
-   return 1;
+   return (CJ_CB_CONTINUE);
  }
  
  static int cj_cb_string (void *ctx, const unsigned char *val,
    char *ptr;
  
    if (db->depth != 1) /* e.g. _all_dbs */
-     return 1;
+     return (CJ_CB_CONTINUE);
  
    cj_cb_map_key (ctx, val, len); /* same logic */
  
      cj_curl_perform (db, curl);
      curl_easy_cleanup (curl);
    }
-   return 1;
+   return (CJ_CB_CONTINUE);
  }
  
  static int cj_cb_start (void *ctx)
    if (++db->depth >= YAJL_MAX_DEPTH)
    {
      ERROR ("curl_json plugin: %s depth exceeds max, aborting.", db->url);
-     return 0;
+     return (CJ_CB_ABORT);
    }
-   return 1;
+   return (CJ_CB_CONTINUE);
  }
  
  static int cj_cb_end (void *ctx)
    cj_t *db = (cj_t *)ctx;
    db->state[db->depth].tree = NULL;
    --db->depth;
-   return 1;
+   return (CJ_CB_CONTINUE);
  }
  
  static int cj_cb_start_map (void *ctx)
@@@ -287,9 -285,9 +285,9 @@@ static int cj_cb_end_array (void * ctx
  static yajl_callbacks ycallbacks = {
    NULL, /* null */
    NULL, /* boolean */
-   cj_cb_integer,
-   cj_cb_double,
-   NULL, /* number */
+   NULL, /* integer */
+   NULL, /* double */
+   cj_cb_number,
    cj_cb_string,
    cj_cb_start_map,
    cj_cb_map_key,
@@@ -673,7 -671,7 +671,7 @@@ static int cj_config_add_url (oconfig_i
      ssnprintf (cb_name, sizeof (cb_name), "curl_json-%s-%s",
                 db->instance, db->url);
  
 -    plugin_register_complex_read (cb_name, cj_read,
 +    plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read,
                                    /* interval = */ NULL, &ud);
    }
    else
@@@ -777,7 -775,8 +775,8 @@@ static int cj_curl_perform (cj_t *db, C
    curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
  
-   if (rc != 200)
+   /* The response code is zero if a non-HTTP transport was used. */
+   if ((rc != 0) && (rc != 200))
    {
      ERROR ("curl_json plugin: curl_easy_perform failed with response code %ld (%s)",
             rc, url);
diff --combined src/plugin.c
@@@ -59,7 -59,6 +59,7 @@@ struct read_func_
  #define rf_callback rf_super.cf_callback
  #define rf_udata rf_super.cf_udata
        callback_func_t rf_super;
 +      char rf_group[DATA_MAX_NAME_LEN];
        char rf_name[DATA_MAX_NAME_LEN];
        int rf_type;
        struct timespec rf_interval;
@@@ -776,7 -775,6 +776,7 @@@ int plugin_register_read (const char *n
        rf->rf_callback = (void *) callback;
        rf->rf_udata.data = NULL;
        rf->rf_udata.free_func = NULL;
 +      rf->rf_group[0] = '\0';
        sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
        rf->rf_type = RF_SIMPLE;
        rf->rf_interval.tv_sec = 0;
        return (plugin_insert_read (rf));
  } /* int plugin_register_read */
  
 -int plugin_register_complex_read (const char *name,
 +int plugin_register_complex_read (const char *group, const char *name,
                plugin_read_cb callback,
                const struct timespec *interval,
                user_data_t *user_data)
  
        memset (rf, 0, sizeof (read_func_t));
        rf->rf_callback = (void *) callback;
 +      if (group != NULL)
 +              sstrncpy (rf->rf_group, group, sizeof (rf->rf_group));
 +      else
 +              rf->rf_group[0] = '\0';
        sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
        rf->rf_type = RF_COMPLEX;
        if (interval != NULL)
@@@ -957,67 -951,6 +957,67 @@@ int plugin_unregister_read (const char 
        return (0);
  } /* }}} int plugin_unregister_read */
  
 +static int compare_read_func_group (llentry_t *e, void *ud) /* {{{ */
 +{
 +      read_func_t *rf    = e->value;
 +      char        *group = ud;
 +
 +      return strcmp (rf->rf_group, (const char *)group);
 +} /* }}} int compare_read_func_group */
 +
 +int plugin_unregister_read_group (const char *group) /* {{{ */
 +{
 +      llentry_t *le;
 +      read_func_t *rf;
 +
 +      int found = 0;
 +
 +      if (group == NULL)
 +              return (-ENOENT);
 +
 +      pthread_mutex_lock (&read_lock);
 +
 +      if (read_list == NULL)
 +      {
 +              pthread_mutex_unlock (&read_lock);
 +              return (-ENOENT);
 +      }
 +
 +      while (42)
 +      {
 +              le = llist_search_custom (read_list,
 +                              compare_read_func_group, (void *)group);
 +
 +              if (le == NULL)
 +                      break;
 +
 +              ++found;
 +
 +              llist_remove (read_list, le);
 +
 +              rf = le->value;
 +              assert (rf != NULL);
 +              rf->rf_type = RF_REMOVE;
 +
 +              llentry_destroy (le);
 +
 +              DEBUG ("plugin_unregister_read_group: "
 +                              "Marked `%s' (group `%s') for removal.",
 +                              rf->rf_name, group);
 +      }
 +
 +      pthread_mutex_unlock (&read_lock);
 +
 +      if (found == 0)
 +      {
 +              WARNING ("plugin_unregister_read_group: No such "
 +                              "group of read function: %s", group);
 +              return (-ENOENT);
 +      }
 +
 +      return (0);
 +} /* }}} int plugin_unregister_read_group */
 +
  int plugin_unregister_write (const char *name)
  {
        return (plugin_unregister (list_write, name));
@@@ -1374,7 -1307,12 +1374,12 @@@ int plugin_dispatch_values (value_list_
  
        if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0)
        {
-               INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type);
+               char ident[6 * DATA_MAX_NAME_LEN];
+               FORMAT_VL (ident, sizeof (ident), vl);
+               INFO ("plugin_dispatch_values: Dataset not found: %s "
+                               "(from \"%s\"), check your types.db!",
+                               vl->type, ident);
                return (-1);
        }
  
diff --combined src/utils_match.c
  #include <regex.h>
  
  #define UTILS_MATCH_FLAGS_FREE_USER_DATA 0x01
 +#define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02
  
  struct cu_match_s
  {
    regex_t regex;
 +  regex_t excluderegex;
    int flags;
  
    int (*callback) (const char *str, char * const *matches, size_t matches_num,
@@@ -83,7 -81,7 +83,7 @@@ static int default_callback (const cha
      if (matches_num < 2)
        return (-1);
  
-     value = strtod (matches[1], &endptr);
+     value = (gauge_t) strtod (matches[1], &endptr);
      if (matches[1] == endptr)
        return (-1);
  
      if (matches_num < 2)
        return (-1);
  
-     value = strtoll (matches[1], &endptr, 0);
+     value = (counter_t) strtoull (matches[1], &endptr, 0);
      if (matches[1] == endptr)
        return (-1);
  
      if (matches_num < 2)
        return (-1);
  
-     value = strtoll (matches[1], &endptr, 0);
+     value = (derive_t) strtoll (matches[1], &endptr, 0);
      if (matches[1] == endptr)
        return (-1);
  
      if (matches_num < 2)
        return (-1);
  
-     value = strtoll (matches[1], &endptr, 0);
+     value = (absolute_t) strtoull (matches[1], &endptr, 0);
      if (matches[1] == endptr)
        return (-1);
  
  /*
   * Public functions
   */
 -cu_match_t *match_create_callback (const char *regex,
 +cu_match_t *match_create_callback (const char *regex, const char *excluderegex,
                int (*callback) (const char *str,
                  char * const *matches, size_t matches_num, void *user_data),
                void *user_data)
    cu_match_t *obj;
    int status;
  
 -  DEBUG ("utils_match: match_create_callback: regex = %s", regex);
 +  DEBUG ("utils_match: match_create_callback: regex = %s, excluderegex = %s",
 +       regex, excluderegex);
  
    obj = (cu_match_t *) malloc (sizeof (cu_match_t));
    if (obj == NULL)
      return (NULL);
    }
  
 +  if (excluderegex && strcmp(excluderegex, "") != 0) {
 +    status = regcomp (&obj->excluderegex, excluderegex, REG_EXTENDED);
 +    if (status != 0)
 +    {
 +      ERROR ("Compiling the excluding regular expression \"%s\" failed.",
 +             excluderegex);
 +      sfree (obj);
 +      return (NULL);
 +    }
 +    obj->flags |= UTILS_MATCH_FLAGS_EXCLUDE_REGEX;
 +  }
 +
    obj->callback = callback;
    obj->user_data = user_data;
  
    return (obj);
  } /* cu_match_t *match_create_callback */
  
 -cu_match_t *match_create_simple (const char *regex, int match_ds_type)
 +cu_match_t *match_create_simple (const char *regex,
 +                               const char *excluderegex, int match_ds_type)
  {
    cu_match_value_t *user_data;
    cu_match_t *obj;
    memset (user_data, '\0', sizeof (cu_match_value_t));
    user_data->ds_type = match_ds_type;
  
 -  obj = match_create_callback (regex, default_callback, user_data);
 +  obj = match_create_callback (regex, excluderegex,
 +                             default_callback, user_data);
    if (obj == NULL)
    {
      sfree (user_data);
@@@ -303,17 -286,6 +303,17 @@@ int match_apply (cu_match_t *obj, cons
    if ((obj == NULL) || (str == NULL))
      return (-1);
  
 +  if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) {
 +    status = regexec (&obj->excluderegex, str,
 +                    STATIC_ARRAY_SIZE (re_match), re_match,
 +                    /* eflags = */ 0);
 +    /* Regex did match, so exclude this line */
 +    if (status == 0) {
 +      DEBUG("ExludeRegex matched, don't count that line\n");
 +      return (0);
 +    }
 +  }
 +
    status = regexec (&obj->regex, str,
        STATIC_ARRAY_SIZE (re_match), re_match,
        /* eflags = */ 0);
diff --combined src/utils_match.h
  /*
   * Defines
   */
- #define UTILS_MATCH_DS_TYPE_GAUGE   0x10
- #define UTILS_MATCH_DS_TYPE_COUNTER 0x20
- #define UTILS_MATCH_DS_TYPE_DERIVE 0x30
- #define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x40
+ #define UTILS_MATCH_DS_TYPE_GAUGE    0x10
+ #define UTILS_MATCH_DS_TYPE_COUNTER  0x20
+ #define UTILS_MATCH_DS_TYPE_DERIVE   0x40
+ #define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x80
  
  #define UTILS_MATCH_CF_GAUGE_AVERAGE 0x01
  #define UTILS_MATCH_CF_GAUGE_MIN     0x02
@@@ -82,10 -82,8 +82,10 @@@ typedef struct cu_match_value_s cu_matc
   *  then only the submatch (the part in the parenthesis) will be passed to the
   *  callback. If there is no submatch, then the entire string is passed to the
   *  callback.
 + *  The optional `excluderegex' allows to exclude the line from the match, if
 + *  the excluderegex matches.
   */
 -cu_match_t *match_create_callback (const char *regex,
 +cu_match_t *match_create_callback (const char *regex, const char *excluderegex,
                int (*callback) (const char *str,
                  char * const *matches, size_t matches_num, void *user_data),
                void *user_data);
   *    The function will not search for anything in the string and increase
   *    value.counter by one.
   */
 -cu_match_t *match_create_simple (const char *regex, int ds_type);
 +cu_match_t *match_create_simple (const char *regex,
 +                               const char *excluderegex, int ds_type);
  
  /*
   * NAME