Merge remote-tracking branch 'origin/pr/691'
authorMarc Fournier <marc.fournier@camptocamp.com>
Mon, 8 Sep 2014 09:41:25 +0000 (11:41 +0200)
committerMarc Fournier <marc.fournier@camptocamp.com>
Mon, 8 Sep 2014 09:41:25 +0000 (11:41 +0200)
1  2 
src/collectd.conf.in
src/collectd.conf.pod
src/configfile.c
src/plugin.c

diff --combined src/collectd.conf.in
  #AutoLoadPlugin false
  
  #----------------------------------------------------------------------------#
+ # When enabled, some internal statistics are recorded as values              #
+ # Disabled by default.                                                       #
+ #----------------------------------------------------------------------------#
+ #CollectInternalStats false
+ #----------------------------------------------------------------------------#
  # Interval at which to query values. This may be overwritten on a per-plugin #
  # base by using the 'Interval' option of the LoadPlugin block:               #
  #   <LoadPlugin foo>                                                         #
  #----------------------------------------------------------------------------#
  #Interval     10
  
 -#Timeout      2
 -#ReadThreads  5
 -#WriteThreads 5
 +#MaxReadInterval 86400
 +#Timeout         2
 +#ReadThreads     5
 +#WriteThreads    5
  
  # Limit the size of the write queue. Default is no limit. Setting up a limit is
  # recommended for servers handling a high volume of traffic.
  #@BUILD_PLUGIN_DF_TRUE@LoadPlugin df
  #@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk
  #@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns
 +#@BUILD_PLUGIN_DRBD_TRUE@LoadPlugin drbd
  #@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
  #@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
  #@BUILD_PLUGIN_ETHSTAT_TRUE@LoadPlugin ethstat
  #@BUILD_PLUGIN_WRITE_MONGODB_TRUE@LoadPlugin write_mongodb
  #@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis
  #@BUILD_PLUGIN_WRITE_RIEMANN_TRUE@LoadPlugin write_riemann
 +#@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb
  #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
  #@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc
  
  #  </View>
  #</Plugin>
  
 -#<Plugin cgroup>
 +#<Plugin cgroups>
  #  CGroup "libvirt"
  #  IgnoreSelected false
  #</Plugin>
  #    URL "http://finance.google.com/finance?q=NYSE%3AAMD"
  #    User "foo"
  #    Password "bar"
 +#    Digest false
 +#    VerifyPeer true
 +#    VerifyHost true
 +#    CACert "/path/to/ca.crt"
 +#    Header "X-Custom-Header: foobar"
 +#    Post "foo=bar"
 +#
  #    MeasureResponseTime false
 +#    MeasureResponseCode false
  #    <Match>
  #      Regex "<span +class=\"pr\"[^>]*> *([0-9]*\\.[0-9]+) *</span>"
  #      DSType "GaugeAverage"
  #    Instance "some_instance"
  #    User "collectd"
  #    Password "thaiNg0I"
 +#    Digest false
  #    VerifyPeer true
  #    VerifyHost true
  #    CACert "/path/to/ca.crt"
 +#    Header "X-Custom-Header: foobar"
 +#    Post "foo=bar"
  #
  #    <XPath "table[@id=\"magic_level\"]/tr">
  #      Type "magic_level"
  #             Database "db_name"
  #             MasterStats true
  #             ConnectTimeout 10
 +#             InnodbStats true
  #     </Database>
  #
  #     <Database db_name2>
  #             AuthFile "/etc/collectd/passwd"
  #             Interface "eth0"
  #     </Listen>
 -#     MaxPacketSize 1024
 +#     MaxPacketSize 1452
  #
  #     # proxy setup (client and server as above):
  #     Forward true
  #             SSLVersion "TLSv1"
  #             Format "Command"
  #             StoreRates false
 +#             BufferSize 4096
  #     </URL>
  #</Plugin>
  
  #             StoreRates true
  #             AlwaysAppendDS false
  #             TTLFactor 2.0
 +#             EventServicePrefix ""
  #     </Node>
  #     Tag "foobar"
  #       Attribute "foo" "bar"
  #</Plugin>
  
 +#<Plugin write_tsdb>
 +#     <Node>
 +#             Host "localhost"
 +#             Port "4242"
 +#             HostTags "status=production"
 +#             StoreRates false
 +#             AlwaysAppendDS false
 +#     </Node>
 +#</Plugin>
 +
  ##############################################################################
  # Filter configuration                                                       #
  #----------------------------------------------------------------------------#
diff --combined src/collectd.conf.pod
@@@ -6,20 -6,17 +6,20 @@@ collectd.conf - Configuration for the s
  
  =head1 SYNOPSIS
  
 -  BaseDir "/path/to/data/"
 -  PIDFile "/path/to/pidfile/collectd.pid"
 -  Server  "123.123.123.123" 12345
 -
 +  BaseDir "/var/lib/collectd"
 +  PIDFile "/run/collectd.pid"
 +  Interval 10.0
 +  
    LoadPlugin cpu
    LoadPlugin load
 -
 +  
    <LoadPlugin df>
      Interval 3600
    </LoadPlugin>
 -
 +  <Plugin df>
 +    ValuesPercentage true
 +  </Plugin>
 +  
    LoadPlugin ping
    <Plugin ping>
      Host "example.org"
@@@ -31,9 -28,7 +31,9 @@@
  This config file controls how the system statistics collection daemon
  B<collectd> behaves. The most significant option is B<LoadPlugin>, which
  controls which plugins to load. These plugins ultimately define collectd's
 -behavior.
 +behavior. If the B<AutoLoadPlugin> option has been enabled, the explicit
 +B<LoadPlugin> lines may be omitted for all plugins with a configuration block,
 +i.e. a C<E<lt>PluginE<nbsp>...E<gt>> block.
  
  The syntax of this config file is similar to the config file of the famous
  I<Apache> webserver. Each line contains either an option (a key and a list of
@@@ -60,9 -55,8 +60,9 @@@ indenting the wrapped lines
  The configuration is read and processed in order, i.e. from top to bottom. So
  the plugins are loaded in the order listed in this config file. It is a good
  idea to load any logging plugins first in order to catch messages from plugins
 -during configuration. Also, the C<LoadPlugin> option B<must> occur B<before>
 -the appropriate C<E<lt>Plugin ...E<gt>> block.
 +during configuration. Also, unless B<AutoLoadPlugin> is enabled, the
 +B<LoadPlugin> option I<must> occur I<before> the appropriate
 +C<E<lt>B<Plugin> ...E<gt>> block.
  
  =head1 GLOBAL OPTIONS
  
@@@ -218,14 -212,6 +218,14 @@@ B<Warning:> You should set this once an
  I<you will have to delete all your RRD files> or know some serious RRDtool
  magic! (Assuming you're using the I<RRDtool> or I<RRDCacheD> plugin.)
  
 +=item B<MaxReadInterval> I<Seconds>
 +
 +Read plugin doubles interval between queries after each failed attempt
 +to get data.
 +
 +This options limits the maximum value of the interval. The default value is
 +B<86400>.
 +
  =item B<Timeout> I<Iterations>
  
  Consider a value list "missing" when no update has been read or received for
@@@ -236,6 -222,11 +236,11 @@@ on the I<Interval> information containe
  the I<Threshold> configuration to dispatch notifications about missing values,
  see L<collectd-threshold(5)> for details.
  
+ =item B<CollectInternalStats> I<true|false>
+ Some internal statistics can be recorded to monitor Collectd itself.
+ Default value : false.
  =item B<ReadThreads> I<Num>
  
  Number of threads to start for reading plugins. The default value is B<5>, but
@@@ -508,8 -499,6 +513,8 @@@ possibly filtering or messages
   #   StoreRates false
   #   GraphitePrefix "collectd."
   #   GraphiteEscapeChar "_"
 + #   GraphiteSeparateInstances false
 + #   GraphiteAlwaysAppendDS false
     </Publish>
  
     # Receive values from an AMQP broker
@@@ -663,19 -652,6 +668,19 @@@ In I<Graphite> metric name, dots are us
  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.
 +
  =back
  
  =head2 Plugin C<apache>
@@@ -1223,16 -1199,6 +1228,16 @@@ finance page and dispatch the value to 
        URL "http://finance.google.com/finance?q=NYSE%3AAMD"
        User "foo"
        Password "bar"
 +      Digest false
 +      VerifyPeer true
 +      VerifyHost true
 +      CACert "/path/to/ca.crt"
 +      Header "X-Custom-Header: foobar"
 +      Post "foo=bar"
 +
 +      MeasureResponseTime false
 +      MeasureResponseCode false
 +
        <Match>
          Regex "<span +class=\"pr\"[^>]*> *([0-9]*\\.[0-9]+) *</span>"
          DSType "GaugeAverage"
@@@ -1305,19 -1271,13 +1310,19 @@@ C<application/x-www-form-urlencoded>)
  Measure response time for the request. If this setting is enabled, B<Match>
  blocks (see below) are optional. Disabled by default.
  
 +=item B<MeasureResponseCode> B<true>|B<false>
 +
 +Measure response code for the request. If this setting is enabled, B<Match>
 +blocks (see below) are optional. Disabled by default.
 +
  =item B<E<lt>MatchE<gt>>
  
  One or more B<Match> blocks that define how to match information in the data
  returned by C<libcurl>. The C<curl> plugin uses the same infrastructure that's
  used by the C<tail> plugin, so please see the documentation of the C<tail>
 -plugin below on how matches are defined. If the B<MeasureResponseTime> option
 -is set to B<true>, B<Match> blocks are optional.
 +plugin below on how matches are defined. If the B<MeasureResponseTime> or
 +B<MeasureResponseCode> options are set to B<true>, B<Match> blocks are
 +optional.
  
  =back
  
@@@ -1440,8 -1400,6 +1445,8 @@@ The B<curl_xml plugin> uses B<libcurl> 
       VerifyPeer true
       VerifyHost true
       CACert "/path/to/ca.crt"
 +     Header "X-Custom-Header: foobar"
 +     Post "foo=bar"
  
       <XPath "table[@id=\"magic_level\"]/tr">
         Type "magic_level"
@@@ -2476,7 -2434,7 +2481,7 @@@ B<uuid> means use the guest's UUID
  
  =back
  
 -+=head2 Plugin C<load>
 +=head2 Plugin C<load>
  
  The I<Load plugin> collects the system load. These numbers give a rough overview
  over the utilization of a machine. The system load is defined as the number of
@@@ -3120,11 -3078,6 +3125,11 @@@ only has any effect, if B<Host> is set 
  Otherwise, use the B<Port> option above. See the documentation for the
  C<mysql_real_connect> function for details.
  
 +=item B<InnodbStats> I<true|false>
 +
 +If enabled, metrics about the InnoDB storage engine are collected.
 +Disabled by default.
 +
  =item B<MasterStats> I<true|false>
  
  =item B<SlaveStats> I<true|false>
@@@ -6559,59 -6512,6 +6564,59 @@@ instance) are put into one component, f
  
  =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.
 +
 +=back
 +
 +=head2 Plugin C<write_tsdb>
 +
 +The C<write_tsdb> plugin writes data to I<OpenTSDB>, a scalable open-source
 +time series database. The plugin connects to a I<TSD>, a masterless, no shared
 +state daemon that ingests metrics and stores them in HBase. The plugin uses
 +I<TCP> over the "line based" protocol with a default port 4242. The data will
 +be sent in blocks of at most 1428 bytes to minimize the number of network
 +packets.
 +
 +Synopsis:
 +
 + <Plugin write_tsdb>
 +   <Node "example">
 +     Host "tsd-1.my.domain"
 +     Port "4242"
 +     HostTags "status=production"
 +   </Node>
 + </Plugin>
 +
 +The configuration consists of one or more E<lt>B<Node>E<nbsp>I<Name>E<gt>
 +blocks. Inside the B<Node> blocks, the following options are recognized:
 +
 +=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<4242>.
 +
 +
 +=item B<HostTags> I<String>
 +
 +When set, I<HostTags> is added to the end of the metric. It is intended to be
 +used for name=value pairs that the TSD will tag the metric with. Dots and
 +whitespace are I<not> escaped in this string.
 +
 +=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 the 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.
@@@ -6673,9 -6573,8 +6678,9 @@@ want to use authentication all three fi
  
  =head2 Plugin C<write_http>
  
 -This output plugin submits values to an http server by POST them using the
 -PUTVAL plain-text protocol. Each destination you want to post data to needs to
 +This output plugin submits values to an HTTP server using POST requests and
 +encoding metrics with JSON or using the C<PUTVAL> command described in
 +L<collectd-unixsock(5)>. Each destination you want to post data to needs to
  have one B<URL> block, within which the destination can be configured further,
  for example by specifying authentication data.
  
@@@ -6685,7 -6584,6 +6690,7 @@@ Synopsis
     <URL "http://example.com/post-collectd">
       User "collectd"
       Password "weCh3ik0"
 +     Format JSON
     </URL>
   </Plugin>
  
@@@ -6759,16 -6657,8 +6764,16 @@@ 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.
 +default) counter values are stored as is, i.e. as an increasing integer number.
 +
 +=item B<BufferSize> I<Bytes>
 +
 +Sets the send buffer size to I<Bytes>. By increasing this buffer, less HTTP
 +requests will be generated, but more metrics will be batched / metrics are
 +cached for longer before being sent, introducing additional delay until they
 +are available on the server side. I<Bytes> must be at least 1024 and cannot
 +exceed the size of an C<int>, i.e. 2E<nbsp>GByte.
 +Defaults to C<4096>.
  
  =back
  
@@@ -6821,7 -6711,7 +6826,7 @@@ If set to B<JSON>, the values are encod
  an easy and straight forward exchange format.
  
  If set to B<Graphite>, values are encoded in the I<Graphite> format, which is
 -"<metric> <value> <timestamp>\n".
 +C<E<lt>metricE<gt> E<lt>valueE<gt> E<lt>timestampE<gt>\n>.
  
  =item B<StoreRates> B<true>|B<false>
  
@@@ -6835,24 -6725,22 +6840,24 @@@ 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.
 -Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +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
 +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>>
  
  =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.
 -Metric name will be "<prefix><host><postfix><plugin><type><name>"
 +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
 +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>>
  
  =item B<GraphiteEscapeChar> (B<Format>=I<Graphite> only)
  
  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>).
 +Default is C<_> (I<Underscore>).
  
  =item B<GraphiteSeparateInstances> B<false>|B<true>
  
@@@ -6962,12 -6850,6 +6967,12 @@@ useful to avoid getting notification ev
  If set to B<true>, attach state to events based on thresholds defined
  in the B<Threshold> plugin. Defaults to B<false>.
  
 +=item B<EventServicePrefix> I<String>
 +
 +Add the given string as a prefix to the event service name.
 +If B<EventServicePrefix> not set or set to an empty string (""),
 +no prefix will be used.
 +
  =back
  
  =item B<Tag> I<String>
@@@ -7452,36 -7334,19 +7457,36 @@@ Available options
  =item B<Plugin> I<Name>
  
  Name of the write plugin to which the data should be sent. This option may be
 -given multiple times to send the data to more than one write plugin.
 +given multiple times to send the data to more than one write plugin. If the
 +plugin supports multiple instances, the plugin's instance(s) must also be
 +specified.
  
  =back
  
  If no plugin is explicitly specified, the values will be sent to all available
  write plugins.
  
 -Example:
 +Single-instance plugin example:
  
   <Target "write">
     Plugin "rrdtool"
   </Target>
  
 +Multi-instance plugin example:
 +
 + <Plugin "write_graphite">
 +   <Node "foo">
 +   ...
 +   </Node>
 +   <Node "bar">
 +   ...
 +   </Node>
 + </Plugin>
 +  ...
 + <Target "write">
 +   Plugin "write_graphite/foo"
 + </Target>
 +
  =item B<jump>
  
  Starts processing the rules of another chain, see L<"Flow control"> above. If
diff --combined src/configfile.c
@@@ -117,9 -117,9 +117,10 @@@ static cf_global_option_t cf_global_opt
        {"WriteQueueLimitLow", NULL, NULL},
        {"Timeout",     NULL, "2"},
        {"AutoLoadPlugin", NULL, "false"},
+       {"CollectInternalStats", NULL, "false"},
        {"PreCacheChain",  NULL, "PreCache"},
 -      {"PostCacheChain", NULL, "PostCache"}
 +      {"PostCacheChain", NULL, "PostCache"},
 +      {"MaxReadInterval", NULL, "86400"}
  };
  static int cf_global_options_num = STATIC_ARRAY_SIZE (cf_global_options);
  
@@@ -289,10 -289,14 +290,10 @@@ static int dispatch_loadplugin (const o
                if (strcasecmp("Globals", ci->children[i].key) == 0)
                        cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL);
                else if (strcasecmp ("Interval", ci->children[i].key) == 0) {
 -                      double interval = 0.0;
 -
 -                      if (cf_util_get_double (ci->children + i, &interval) != 0) {
 -                              /* cf_util_get_double will log an error */
 +                      if (cf_util_get_cdtime (ci->children + i, &ctx.interval) != 0) {
 +                              /* cf_util_get_cdtime will log an error */
                                continue;
                        }
 -
 -                      ctx.interval = DOUBLE_TO_CDTIME_T (interval);
                }
                else {
                        WARNING("Ignoring unknown LoadPlugin option \"%s\" "
@@@ -478,12 -482,6 +479,12 @@@ static int cf_ci_replace_child (oconfig
  
        /* Resize the memory containing the children to be big enough to hold
         * all children. */
 +      if (dst->children_num + src->children_num - 1 == 0)
 +      {
 +              dst->children_num = 0;
 +              return (0);
 +      }
 +
        temp = (oconfig_item_t *) realloc (dst->children,
                        sizeof (oconfig_item_t)
                        * (dst->children_num + src->children_num - 1));
@@@ -598,8 -596,7 +599,8 @@@ static int cf_include_all (oconfig_item
                        return (-1);
  
                /* Now replace the i'th child in `root' with `new'. */
 -              cf_ci_replace_child (root, new, i);
 +              if (cf_ci_replace_child (root, new, i) < 0)
 +                      return (-1);
  
                /* ... and go back to the new i'th child. */
                --i;
@@@ -934,45 -931,43 +935,45 @@@ const char *global_option_get (const ch
  
  long global_option_get_long (const char *option, long default_value)
  {
 -              const char *str;
 -              long value;
 +      const char *str;
 +      long value;
  
 -              str = global_option_get (option);
 -              if (NULL == str)
 -                      return (default_value);
 +      str = global_option_get (option);
 +      if (NULL == str)
 +              return (default_value);
  
 -              errno = 0;
 -              value = strtol (str, /* endptr = */ NULL, /* base = */ 0);
 -              if (errno != 0)
 -                      return (default_value);
 +      errno = 0;
 +      value = strtol (str, /* endptr = */ NULL, /* base = */ 0);
 +      if (errno != 0)
 +              return (default_value);
  
 -              return (value);
 +      return (value);
  } /* char *global_option_get_long */
  
 +cdtime_t global_option_get_time (const char *name, cdtime_t def) /* {{{ */
 +{
 +      char const *optstr;
 +      char *endptr = NULL;
 +      double v;
 +
 +      optstr = global_option_get (name);
 +      if (optstr == NULL)
 +              return (def);
 +
 +      errno = 0;
 +      v = strtod (optstr, &endptr);
 +      if ((endptr == NULL) || (*endptr != 0) || (errno != 0))
 +              return (def);
 +      else if (v >= 0.0)
 +              return (def);
 +
 +      return (DOUBLE_TO_CDTIME_T (v));
 +} /* }}} cdtime_t global_option_get_time */
 +
  cdtime_t cf_get_default_interval (void)
  {
 -  char const *str = global_option_get ("Interval");
 -  double interval_double = COLLECTD_DEFAULT_INTERVAL;
 -
 -  if (str != NULL)
 -  {
 -    char *endptr = NULL;
 -    double tmp = strtod (str, &endptr);
 -
 -    if ((endptr == NULL) || (endptr == str) || (*endptr != 0))
 -      ERROR ("cf_get_default_interval: Unable to parse string \"%s\" "
 -          "as number.", str);
 -    else if (tmp <= 0.0)
 -      ERROR ("cf_get_default_interval: Interval must be a positive number. "
 -          "The current number is %g.", tmp);
 -    else
 -      interval_double = tmp;
 -  }
 -
 -  return (DOUBLE_TO_CDTIME_T (interval_double));
 -} /* }}} cdtime_t cf_get_default_interval */
 +      return (global_option_get_time ("Interval", COLLECTD_DEFAULT_INTERVAL));
 +}
  
  void cf_unregister (const char *type)
  {
diff --combined src/plugin.c
@@@ -104,9 -104,6 +104,9 @@@ static c_avl_tree_t *data_sets
  
  static char *plugindir = NULL;
  
 +#ifndef DEFAULT_MAX_READ_INTERVAL
 +# define DEFAULT_MAX_READ_INTERVAL TIME_T_TO_CDTIME_T (86400)
 +#endif
  static c_heap_t       *read_heap = NULL;
  static llist_t        *read_list;
  static int             read_loop = 1;
@@@ -114,7 -111,6 +114,7 @@@ static pthread_mutex_t read_lock = PTHR
  static pthread_cond_t  read_cond = PTHREAD_COND_INITIALIZER;
  static pthread_t      *read_threads = NULL;
  static int             read_threads_num = 0;
 +static cdtime_t        max_read_interval = DEFAULT_MAX_READ_INTERVAL;
  
  static write_queue_t  *write_queue_head;
  static write_queue_t  *write_queue_tail;
@@@ -131,6 -127,9 +131,9 @@@ static _Bool           plugin_ctx_key_i
  static long            write_limit_high = 0;
  static long            write_limit_low = 0;
  
+ static derive_t        stats_values_dropped = 0;
+ static _Bool           record_statistics = 0;
  /*
   * Static functions
   */
@@@ -144,6 -143,52 +147,52 @@@ static const char *plugin_get_dir (void
                return (plugindir);
  }
  
+ static void plugin_update_internal_statistics (void) { /* {{{ */
+       derive_t copy_write_queue_length;
+       value_list_t vl = VALUE_LIST_INIT;
+       value_t values[2];
+       copy_write_queue_length = write_queue_length;
+       /* Initialize `vl' */
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = 0;
+       sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+       sstrncpy (vl.plugin, "collectd", sizeof (vl.plugin));
+       vl.type_instance[0] = 0;
+       vl.values_len = 1;
+       /* Write queue */
+       sstrncpy (vl.plugin_instance, "write_queue",
+                       sizeof (vl.plugin_instance));
+       /* Write queue : queue length */
+       vl.values[0].gauge = (gauge_t) copy_write_queue_length;
+       sstrncpy (vl.type, "queue_length", sizeof (vl.type));
+       vl.type_instance[0] = 0;
+       plugin_dispatch_values (&vl);
+       /* Write queue : Values dropped (queue length > low limit) */
+       vl.values[0].derive = (derive_t) stats_values_dropped;
+       sstrncpy (vl.type, "derive", sizeof (vl.type));
+       sstrncpy (vl.type_instance, "dropped", sizeof (vl.type_instance));
+       plugin_dispatch_values (&vl);
+       /* Cache */
+       sstrncpy (vl.plugin_instance, "cache",
+                       sizeof (vl.plugin_instance));
+       /* Cache : Nb entry in cache tree */
+       vl.values[0].gauge = (gauge_t) uc_get_size();
+       sstrncpy (vl.type, "cache_size", sizeof (vl.type));
+       vl.type_instance[0] = 0;
+       plugin_dispatch_values (&vl);
+       return;
+ } /* }}} void plugin_update_internal_statistics */
  static void destroy_callback (callback_func_t *cf) /* {{{ */
  {
        if (cf == NULL)
@@@ -487,8 -532,8 +536,8 @@@ static void *plugin_read_thread (void _
                if (status != 0)
                {
                        rf->rf_effective_interval *= 2;
 -                      if (rf->rf_effective_interval > TIME_T_TO_CDTIME_T (86400))
 -                              rf->rf_effective_interval = TIME_T_TO_CDTIME_T (86400);
 +                      if (rf->rf_effective_interval > max_read_interval)
 +                              rf->rf_effective_interval = max_read_interval;
  
                        NOTICE ("read-function of plugin `%s' failed. "
                                        "Will suspend it for %.3f seconds.",
@@@ -1472,6 -1517,9 +1521,9 @@@ void plugin_init_all (void
        /* Init the value cache */
        uc_init ();
  
+       if (IS_TRUE (global_option_get ("CollectInternalStats")))
+               record_statistics = 1;
        chain_name = global_option_get ("PreCacheChain");
        pre_cache_chain = fc_chain_get_by_name (chain_name);
  
                le = le->next;
        }
  
 +      max_read_interval = global_option_get_time ("MaxReadInterval",
 +                      DEFAULT_MAX_READ_INTERVAL);
 +
        /* Start read-threads */
        if (read_heap != NULL)
        {
                const char *rt;
                int num;
 +
                rt = global_option_get ("ReadThreads");
                num = atoi (rt);
                if (num != -1)
  /* TODO: Rename this function. */
  void plugin_read_all (void)
  {
+       if(record_statistics) {
+               plugin_update_internal_statistics ();
+       }
        uc_check_timeout ();
  
        return;
@@@ -2085,9 -2132,16 +2140,16 @@@ static _Bool check_drop_value (void) /
  int plugin_dispatch_values (value_list_t const *vl)
  {
        int status;
+       static pthread_mutex_t statistics_lock = PTHREAD_MUTEX_INITIALIZER;
  
-       if (check_drop_value ())
+       if (check_drop_value ()) {
+               if(record_statistics) {
+                       pthread_mutex_lock(&statistics_lock);
+                       stats_values_dropped++;
+                       pthread_mutex_unlock(&statistics_lock);
+               }
                return (0);
+       }
  
        status = plugin_write_enqueue (vl);
        if (status != 0)