Merge branch 'collectd-4.7'
authorFlorian Forster <sifnfors@informatik.stud.uni-erlangen.de>
Mon, 6 Jul 2009 11:45:41 +0000 (13:45 +0200)
committerFlorian Forster <sifnfors@informatik.stud.uni-erlangen.de>
Mon, 6 Jul 2009 11:45:41 +0000 (13:45 +0200)
1  2 
configure.in
src/Makefile.am
src/collectd.conf.in
src/collectd.conf.pod
src/common.c
src/dns.c
src/gmond.c
src/java.c
src/libcollectdclient/client.c
src/utils_cache.c

diff --combined configure.in
@@@ -1540,7 -1540,7 +1540,7 @@@ the
                if test "x$TMPDIR" != "x"
                then
                        AC_MSG_RESULT([found in $TMPDIR])
-                       JAVA_LDFLAGS="$JAVA_LDFLAGS -L$TMPDIR"
+                       JAVA_LDFLAGS="$JAVA_LDFLAGS -L$TMPDIR -Wl,-rpath -Wl,$TMPDIR"
                else
                        AC_MSG_RESULT([not found])
                fi
@@@ -2966,57 -2966,6 +2966,57 @@@ AC_DEFINE_UNQUOTED(HAVE_LIBXMMS, [$with
  AM_CONDITIONAL(BUILD_WITH_LIBXMMS, test "x$with_libxmms" = "xyes")
  # }}}
  
 +# --with-libyajl {{{
 +with_libyajl_cppflags=""
 +with_libyajl_ldflags=""
 +AC_ARG_WITH(libyajl, [AS_HELP_STRING([--with-libyajl@<:@=PREFIX@:>@], [Path to libyajl.])],
 +[
 +      if test "x$withval" != "xno" && test "x$withval" != "xyes"
 +      then
 +              with_libyajl_cppflags="-I$withval/include"
 +              with_libyajl_ldflags="-L$withval/lib"
 +              with_libyajl="yes"
 +      else
 +              with_libyajl="$withval"
 +      fi
 +],
 +[
 +      with_libyajl="yes"
 +])
 +if test "x$with_libyajl" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libyajl_cppflags"
 +
 +      AC_CHECK_HEADERS(yajl/yajl_parse.h, [with_libyajl="yes"], [with_libyajl="no (yajl/yajl_parse.h not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +fi
 +if test "x$with_libyajl" = "xyes"
 +then
 +      SAVE_CPPFLAGS="$CPPFLAGS"
 +      SAVE_LDFLAGS="$LDFLAGS"
 +      CPPFLAGS="$CPPFLAGS $with_libyajl_cppflags"
 +      LDFLAGS="$LDFLAGS $with_libyajl_ldflags"
 +
 +      AC_CHECK_LIB(yajl, yajl_alloc, [with_libyajl="yes"], [with_libyajl="no (Symbol 'yajl_alloc' not found)"])
 +
 +      CPPFLAGS="$SAVE_CPPFLAGS"
 +      LDFLAGS="$SAVE_LDFLAGS"
 +fi
 +if test "x$with_libyajl" = "xyes"
 +then
 +      BUILD_WITH_LIBYAJL_CPPFLAGS="$with_libyajl_cppflags"
 +      BUILD_WITH_LIBYAJL_LDFLAGS="$with_libyajl_ldflags"
 +      BUILD_WITH_LIBYAJL_LIBS="-lyajl"
 +      AC_SUBST(BUILD_WITH_LIBYAJL_CPPFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBYAJL_LDFLAGS)
 +      AC_SUBST(BUILD_WITH_LIBYAJL_LIBS)
 +      AC_DEFINE(HAVE_LIBYAJL, 1, [Define if libyajl is present and usable.])
 +fi
 +AM_CONDITIONAL(BUILD_WITH_LIBYAJL, test "x$with_libyajl" = "xyes")
 +# }}}
 +
  # pkg-config --exists 'libxml-2.0'; pkg-config --exists libvirt {{{
  with_libxml2="no (pkg-config isn't available)"
  with_libxml2_cflags=""
@@@ -3349,7 -3298,6 +3349,7 @@@ plugin_ascent="no
  plugin_battery="no"
  plugin_bind="no"
  plugin_conntrack="no"
 +plugin_couchdb="no"
  plugin_cpu="no"
  plugin_cpufreq="no"
  plugin_df="no"
        plugin_ipmi="yes"
  fi
  
 +if test "x$with_libcurl" = "xyes" && test "x$with_libyajl" = "xyes"
 +then
 +      plugin_couchdb="yes"
 +fi
 +
  if test "x$have_processor_info" = "xyes"
  then
        plugin_cpu="yes"
@@@ -3619,7 -3562,6 +3619,7 @@@ AC_PLUGIN([ascent],      [$plugin_ascen
  AC_PLUGIN([battery],     [$plugin_battery],    [Battery statistics])
  AC_PLUGIN([bind],        [$plugin_bind],       [ISC Bind nameserver statistics])
  AC_PLUGIN([conntrack],   [$plugin_conntrack],  [nf_conntrack statistics])
 +AC_PLUGIN([couchdb],     [$plugin_couchdb],    [CouchDB statistics])
  AC_PLUGIN([cpufreq],     [$plugin_cpufreq],    [CPU frequency statistics])
  AC_PLUGIN([cpu],         [$plugin_cpu],        [CPU usage statistics])
  AC_PLUGIN([csv],         [yes],                [CSV output plugin])
@@@ -3661,7 -3603,6 +3661,7 @@@ AC_PLUGIN([notify_desktop], [$with_libn
  AC_PLUGIN([notify_email], [$with_libesmtp],    [Email notifier])
  AC_PLUGIN([ntpd],        [yes],                [NTPd statistics])
  AC_PLUGIN([nut],         [$with_libupsclient], [Network UPS tools statistics])
 +AC_PLUGIN([olsrd],       [yes],                [olsrd statistics])
  AC_PLUGIN([onewire],     [$with_libowcapi],    [OneWire sensor statistics])
  AC_PLUGIN([openvpn],     [yes],                [OpenVPN client statistics])
  AC_PLUGIN([oracle],      [$with_oracle],       [Oracle plugin])
@@@ -3869,6 -3810,7 +3869,7 @@@ Configuration
      libcurl . . . . . . . $with_libcurl
      libdbi  . . . . . . . $with_libdbi
      libesmtp  . . . . . . $with_libesmtp
+     libganglia  . . . . . $with_libganglia
      libgcrypt . . . . . . $with_libgcrypt
      libiokit  . . . . . . $with_libiokit
      libiptc . . . . . . . $with_libiptc
      libvirt . . . . . . . $with_libvirt
      libxml2 . . . . . . . $with_libxml2
      libxmms . . . . . . . $with_libxmms
 +    libyajl . . . . . . . $with_libyajl
      oracle  . . . . . . . $with_oracle
  
    Features:
      battery . . . . . . . $enable_battery
      bind  . . . . . . . . $enable_bind
      conntrack . . . . . . $enable_conntrack
 +    couchdb . . . . . . . $enable_couchdb
      cpu . . . . . . . . . $enable_cpu
      cpufreq . . . . . . . $enable_cpufreq
      csv . . . . . . . . . $enable_csv
      notify_email  . . . . $enable_notify_email
      ntpd  . . . . . . . . $enable_ntpd
      nut . . . . . . . . . $enable_nut
 +    olsrd . . . . . . . . $enable_olsrd
      onewire . . . . . . . $enable_onewire
      openvpn . . . . . . . $enable_openvpn
      oracle  . . . . . . . $enable_oracle
diff --combined src/Makefile.am
@@@ -173,21 -173,6 +173,21 @@@ collectd_LDADD += "-dlopen" conntrack.l
  collectd_DEPENDENCIES += conntrack.la
  endif
  
 +if BUILD_PLUGIN_COUCHDB
 +pkglib_LTLIBRARIES += couchdb.la
 +couchdb_la_SOURCES = couchdb.c
 +couchdb_la_CFLAGS = $(AM_CFLAGS)
 +couchdb_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBYAJL_LDFLAGS)
 +couchdb_la_CPPFLAGS = $(BUILD_WITH_LIBYAJL_CPPFLAGS)
 +couchdb_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
 +if BUILD_WITH_LIBCURL
 +couchdb_la_CFLAGS += $(BUILD_WITH_LIBCURL_CFLAGS)
 +couchdb_la_LIBADD += $(BUILD_WITH_LIBCURL_LIBS)
 +endif
 +collectd_LDADD += "-dlopen" couchdb.la
 +collectd_DEPENDENCIES += couchdb.la
 +endif
 +
  if BUILD_PLUGIN_CPU
  pkglib_LTLIBRARIES += cpu.la
  cpu_la_SOURCES = cpu.c
@@@ -653,18 -638,6 +653,18 @@@ collectd_LDADD += "-dlopen" nut.l
  collectd_DEPENDENCIES += nut.la
  endif
  
 +if BUILD_PLUGIN_OLSRD
 +pkglib_LTLIBRARIES += olsrd.la
 +olsrd_la_SOURCES = olsrd.c
 +olsrd_la_LDFLAGS = -module -avoid-version
 +olsrd_la_LIBADD = 
 +if BUILD_WITH_LIBSOCKET
 +olsrd_la_LIBADD += -lsocket
 +endif
 +collectd_LDADD += "-dlopen" olsrd.la
 +collectd_DEPENDENCIES += olsrd.la
 +endif
 +
  if BUILD_PLUGIN_ONEWIRE
  pkglib_LTLIBRARIES += onewire.la
  onewire_la_SOURCES = onewire.c
@@@ -722,7 -695,7 +722,7 @@@ pkglib_LTLIBRARIES += ping.l
  ping_la_SOURCES = ping.c
  ping_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOPING_CPPFLAGS)
  ping_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBOPING_LDFLAGS)
- ping_la_LIBADD = -loping
+ ping_la_LIBADD = -loping -lm
  collectd_LDADD += "-dlopen" ping.la
  collectd_DEPENDENCIES += ping.la
  endif
@@@ -791,8 -764,8 +791,8 @@@ if BUILD_PLUGIN_SENSOR
  pkglib_LTLIBRARIES += sensors.la
  sensors_la_SOURCES = sensors.c
  sensors_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBSENSORS_CFLAGS)
- sensors_la_LDFLAGS = -module -avoid-version
- sensors_la_LIBADD = $(BUILD_WITH_LIBSENSORS_LDFLAGS)
+ sensors_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBSENSORS_LDFLAGS)
+ sensors_la_LIBADD = -lsensors
  collectd_LDADD += "-dlopen" sensors.la
  collectd_DEPENDENCIES += sensors.la
  endif
diff --combined src/collectd.conf.in
@@@ -57,7 -57,6 +57,7 @@@ FQDNLookup   tru
  #@BUILD_PLUGIN_BATTERY_TRUE@LoadPlugin battery
  #@BUILD_PLUGIN_BIND_TRUE@LoadPlugin bind
  #@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack
 +#@BUILD_PLUGIN_COUCHDB_TRUE@LoadPlugin couchdb
  @BUILD_PLUGIN_CPU_TRUE@@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
  #@BUILD_PLUGIN_CPUFREQ_TRUE@LoadPlugin cpufreq
  @LOAD_PLUGIN_CSV@LoadPlugin csv
@@@ -95,7 -94,6 +95,7 @@@
  #@BUILD_PLUGIN_NOTIFY_EMAIL_TRUE@LoadPlugin notify_email
  #@BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
  #@BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
 +#@BUILD_PLUGIN_OLSRD_TRUE@LoadPlugin olsrd
  #@BUILD_PLUGIN_ONEWIRE_TRUE@LoadPlugin onewire
  #@BUILD_PLUGIN_OPENVPN_TRUE@LoadPlugin openvpn
  #@BUILD_PLUGIN_ORACLE_TRUE@LoadPlugin oracle
  #  </View>
  #</Plugin>
  
 +#<Plugin couchdb>
 +## See: http://wiki.apache.org/couchdb/Runtime_Statistics
 +#  <URL "http://localhost:5984/_stats">
 +#    Instance "httpd"
 +#    <Key "httpd/requests/count">
 +#      Type "http_requests"
 +#    </Key>
 +#
 +#    <Key "httpd_request_methods/*/count">
 +#      Type "http_request_methods"
 +#    </Key>
 +#
 +#    <Key "httpd_status_codes/*/count">
 +#      Type "http_response_codes"
 +#    </Key>
 +#  </URL>
 +## Database status metrics:
 +#  <URL "http://localhost:5984/_all_dbs">
 +#    Instance "dbs"
 +#    <Key "*/doc_count">
 +#      Type "gauge"
 +#    </Key>
 +#    <Key "*/doc_del_count">
 +#      Type "counter"
 +#    </Key>
 +#    <Key "*/disk_size">
 +#      Type "bytes"
 +#    </Key>
 +#  </URL>
 +#</Plugin>
 +
  #<Plugin csv>
  #     DataDir "@prefix@/var/lib/@PACKAGE_NAME@/csv"
  #     StoreRates false
  #     IgnoreSelected false
  #</Plugin>
  
+ #<Plugin ipmi>
+ #     Sensor "some_sensor"
+ #     Sensor "another_one"
+ #     IgnoreSelected false
+ #     NotifySensorAdd false
+ #     NotifySensorRemove true
+ #     NotifySensorNotPresent false
+ #</Plugin>
  #<Plugin iptables>
  #     Chain table chain
  #</Plugin>
  #     UPS "upsname@hostname:port"
  #</Plugin>
  
 +#<Plugin olsrd>
 +#     Host "127.0.0.1"
 +#     Port "2006"
 +#     CollectLinks "Summary"
 +#     CollectRoutes "Summary"
 +#     CollectTopology "Summary"
 +#</Plugin>
 +
  #<Plugin onewire>
  #     Device "-s localhost:4304"
  #     Sensor "F10FCA000800"
diff --combined src/collectd.conf.pod
@@@ -409,106 -409,6 +409,106 @@@ By default no detailed zone informatio
  
  =back
  
 +=head2 Plugin C<couchdb>
 +
 +The couchdb plugin uses B<libcurl> (L<http://curl.haxx.se/>) and B<libyajl>
 +(L<http://www.lloydforge.org/projects/yajl/>) to collect values from CouchDB
 +documents (stored JSON notation).
 +
 +The following example will collect several values from the built-in `_stats'
 +runtime statistics module (L<http://wiki.apache.org/couchdb/Runtime_Statistics>).
 +
 +  <Plugin couchdb>
 +    <URL "http://localhost:5984/_stats">
 +      Instance "httpd"
 +      <Key "httpd/requests/count">
 +        Type "http_requests"
 +      </Key>
 +
 +      <Key "httpd_request_methods/*/count">
 +        Type "http_request_methods"
 +      </Key>
 +
 +      <Key "httpd_status_codes/*/count">
 +        Type "http_response_codes"
 +      </Key>
 +    </URL>
 +  </Plugin>
 +
 +The following example will collect the status values from each database:
 +
 +  <URL "http://localhost:5984/_all_dbs">
 +    Instance "dbs"
 +    <Key "*/doc_count">
 +      Type "gauge"
 +    </Key>
 +    <Key "*/doc_del_count">
 +      Type "counter"
 +    </Key>
 +    <Key "*/disk_size">
 +      Type "bytes"
 +    </Key>
 +  </URL>
 +
 +In the B<Plugin> block, there may be one or more B<URL> blocks, each defining
 +a URL to be fetched via HTTP (libcurl) and one or more B<Key> blocks.
 +The B<Key> string argument must be in a path format, of which is used to collect
 +a value from a JSON map object.  If a B<Key> path element is that of a I<*> wildcard,
 +the values for all keys will be collectd.
 +
 +The following options are valid within B<URL> blocks:
 +
 +=over 4
 +
 +=item B<Instance> I<Instance>
 +
 +Sets the plugin instance to I<Instance>.
 +
 +=item B<User> I<Name>
 +
 +Username to use if authorization is required to read the page.
 +
 +=item B<Password> I<Password>
 +
 +Password to use if authorization is required to read the page.
 +
 +=item B<VerifyPeer> B<true>|B<false>
 +
 +Enable or disable peer SSL certificate verification. See
 +L<http://curl.haxx.se/docs/sslcerts.html> for details. Enabled by default.
 +
 +=item B<VerifyHost> B<true>|B<false>
 +
 +Enable or disable peer host name verification. If enabled, the plugin checks if
 +the C<Common Name> or a C<Subject Alternate Name> field of the SSL certificate
 +matches the host name provided by the B<URL> option. If this identity check
 +fails, the connection is aborted. Obviously, only works when connecting to a
 +SSL enabled server. Enabled by default.
 +
 +=item B<CACert> I<file>
 +
 +File that holds one or more SSL certificates. If you want to use HTTPS you will
 +possibly need this option. What CA certificates come bundled with C<libcurl>
 +and are checked by default depends on the distribution you use.
 +
 +=back
 +
 +The following options are valid within B<Key> blocks:
 +
 +=over 4
 +
 +=item B<Type> I<Type>
 +
 +Sets the type used to dispatch the values to the daemon. Detailed information
 +about types and their configuration can be found in L<types.db(5)>. This
 +option is mandatory.
 +
 +=item B<Instance> I<Instance>
 +
 +Type-instance to use. Defaults to the current map key or current string array element value.
 +
 +=back
 +
  =head2 Plugin C<cpufreq>
  
  This plugin doesn't have any options. It reads
@@@ -921,10 -821,6 +921,10 @@@ may not work on certain platforms, suc
  
  Ignore packets that originate from this address.
  
 +=item B<SelectNumericQueryTypes> B<true>|B<false>
 +
 +Enabled by default, collects unknown (and thus presented as numeric only) query types.
 +
  =back
  
  =head2 Plugin C<email>
@@@ -2006,55 -1902,6 +2006,55 @@@ L<upsc(8)>
  
  =back
  
 +=head2 Plugin C<olsrd>
 +
 +The I<olsrd> plugin connects to the TCP port opened by the I<txtinfo> plugin of
 +the Optimized Link State Routing daemon and reads information about the current
 +state of the meshed network.
 +
 +The following configuration options are understood:
 +
 +=over 4
 +
 +=item B<Host> I<Host>
 +
 +Connect to I<Host>. Defaults to B<"localhost">.
 +
 +=item B<Port> I<Port>
 +
 +Specifies the port to connect to. This must be a string, even if you give the
 +port as a number rather than a service name. Defaults to B<"2006">.
 +
 +=item B<CollectLinks> B<No>|B<Summary>|B<Detail>
 +
 +Specifies what information to collect about links, i.E<nbsp>e. direct
 +connections of the daemon queried. If set to B<No>, no information is
 +collected. If set to B<Summary>, the number of links and the average of all
 +I<link quality> (LQ) and I<neighbor link quality> (NLQ) values is calculated.
 +If set to B<Detail> LQ and NLQ are collected per link.
 +
 +Defaults to B<Detail>.
 +
 +=item B<CollectRoutes> B<No>|B<Summary>|B<Detail>
 +
 +Specifies what information to collect about routes of the daemon queried. If
 +set to B<No>, no information is collected. If set to B<Summary>, the number of
 +routes and the average I<metric> and I<ETX> is calculated. If set to B<Detail>
 +metric and ETX are collected per route.
 +
 +Defaults to B<Summary>.
 +
 +=item B<CollectTopology> B<No>|B<Summary>|B<Detail>
 +
 +Specifies what information to collect about the global topology. If set to
 +B<No>, no information is collected. If set to B<Summary>, the number of links
 +in the entire topology and the average I<link quality> (LQ) is calculated.
 +If set to B<Detail> LQ and NLQ are collected for each link in the entire topology.
 +
 +Defaults to B<Summary>.
 +
 +=back
 +
  =head2 Plugin C<onewire>
  
  B<EXPERIMENTAL!> See notes below.
@@@ -2324,7 -2171,7 +2324,7 @@@ L<http://www.postgresql.org/docs/manual
  The B<Query> block defines one database query which may later be used by a
  database definition. It accepts a single mandatory argument which specifies
  the name of the query. The names of all queries have to be unique (see the
- B<MinPGVersion> and B<MaxPGVersion> options below for an exception to this
+ B<MinVersion> and B<MaxVersion> options below for an exception to this
  rule). The following configuration options are available to define the query:
  
  In each B<Query> block, there is one or more B<Result> blocks. B<Result>
@@@ -2443,9 -2290,9 +2443,9 @@@ The order of the B<Column> options defi
  should be used. The first option specifies the data found in the first column,
  the second option that of the second column, and so on.
  
- =item B<MinPGVersion> I<version>
+ =item B<MinVersion> I<version>
  
- =item B<MaxPGVersion> I<version>
+ =item B<MaxVersion> I<version>
  
  Specify the minimum or maximum version of PostgreSQL that this query should be
  used with. Some statistics might only be available with certain versions of
@@@ -2457,6 -2304,13 +2457,13 @@@ The I<version> has to be specified as t
  and patch-level versions, each represented as two-decimal-digit numbers. For
  example, version 8.2.3 will become 80203.
  
+ =item B<MinPGVersion> I<version>
+ =item B<MaxPGVersion> I<version>
+ These are deprecated synonyms for B<MinVersion> and B<MaxVersion>
+ respectively. They will be removed in version 5 of collectd.
  =back
  
  The following predefined queries are available (the definitions can be found
diff --combined src/common.c
@@@ -837,41 -837,28 +837,41 @@@ int parse_identifier (char *str, char *
        return (0);
  } /* int parse_identifier */
  
 -int parse_value (const char *value, value_t *ret_value, const data_source_t ds)
 +int parse_value (const char *value, value_t *ret_value, int ds_type)
  {
 -      char *endptr = NULL;
 -
 -      if (DS_TYPE_COUNTER == ds.type)
 -              ret_value->counter = (counter_t)strtoll (value, &endptr, 0);
 -      else if (DS_TYPE_GAUGE == ds.type)
 -              ret_value->gauge = (gauge_t)strtod (value, &endptr);
 -      else {
 -              ERROR ("parse_value: Invalid data source \"%s\" "
 -                              "(type = %i).", ds.name, ds.type);
 -              return -1;
 -      }
 -
 -      if (value == endptr) {
 -              ERROR ("parse_value: Failed to parse string as number: %s.", value);
 -              return -1;
 -      }
 -      else if ((NULL != endptr) && ('\0' != *endptr))
 -              WARNING ("parse_value: Ignoring trailing garbage after number: %s.",
 -                              endptr);
 -      return 0;
 +  char *endptr = NULL;
 +
 +  switch (ds_type)
 +  {
 +    case DS_TYPE_COUNTER:
 +      ret_value->counter = (counter_t) strtoull (value, &endptr, 0);
 +      break;
 +
 +    case DS_TYPE_GAUGE:
 +      ret_value->gauge = (gauge_t) strtod (value, &endptr);
 +      break;
 +
 +    case DS_TYPE_DERIVE:
 +      ret_value->counter = (derive_t) strtoll (value, &endptr, 0);
 +      break;
 +
 +    case DS_TYPE_ABSOLUTE:
 +      ret_value->counter = (absolute_t) strtoull (value, &endptr, 0);
 +      break;
 +
 +    default:
 +      ERROR ("parse_value: Invalid data source type: %i.", ds_type);
 +      return -1;
 +  }
 +
 +  if (value == endptr) {
 +    ERROR ("parse_value: Failed to parse string as number: %s.", value);
 +    return -1;
 +  }
 +  else if ((NULL != endptr) && ('\0' != *endptr))
 +    WARNING ("parse_value: Ignoring trailing garbage after number: %s.",
 +        endptr);
 +  return 0;
  } /* int parse_value */
  
  int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
                dummy = NULL;
  
                if (i >= vl->values_len)
+               {
+                       /* Make sure i is invalid. */
+                       i = vl->values_len + 1;
                        break;
+               }
  
                if (i == -1)
                {
                {
                        if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE))
                                vl->values[i].gauge = NAN;
 -                      else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i]))
 +                      else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type))
                                return -1;
                }
  
diff --combined src/dns.c
+++ b/src/dns.c
@@@ -49,10 -49,9 +49,10 @@@ static const char *config_keys[] 
  {
        "Interface",
        "IgnoreSource",
 -      NULL
 +      "SelectNumericQueryTypes"
  };
 -static int config_keys_num = 2;
 +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 +static int select_numeric_qtype = 1;
  
  #define PCAP_SNAPLEN 1460
  static char   *pcap_device = NULL;
@@@ -159,13 -158,6 +159,13 @@@ static int dns_config (const char *key
                if (value != NULL)
                        ignore_list_add_name (value);
        }
 +      else if (strcasecmp (key, "SelectNumericQueryTypes") == 0)
 +      {
 +              if ((value != NULL) && IS_FALSE (value))
 +                      select_numeric_qtype = 0;
 +              else
 +                      select_numeric_qtype = 1;
 +      }
        else
        {
                return (-1);
@@@ -179,24 -171,13 +179,24 @@@ static void dns_child_callback (const r
        if (dns->qr == 0)
        {
                /* This is a query */
 +              int skip = 0;
 +              if (!select_numeric_qtype)
 +              {
 +                      const char *str = qtype_str(dns->qtype);
 +                      if ((str == NULL) || (str[0] == '#'))
 +                              skip = 1;
 +              }
 +
                pthread_mutex_lock (&traffic_mutex);
                tr_queries += dns->length;
                pthread_mutex_unlock (&traffic_mutex);
  
 -              pthread_mutex_lock (&qtype_mutex);
 -              counter_list_add (&qtype_list,  dns->qtype,  1);
 -              pthread_mutex_unlock (&qtype_mutex);
 +              if (skip == 0)
 +              {
 +                      pthread_mutex_lock (&qtype_mutex);
 +                      counter_list_add (&qtype_list, dns->qtype,  1);
 +                      pthread_mutex_unlock (&qtype_mutex);
 +              }
        }
        else
        {
@@@ -232,7 -213,7 +232,7 @@@ static void *dns_child_loop (void __att
        }
  
        /* Passing `pcap_device == NULL' is okay and the same as passign "any" */
-       DEBUG ("Creating PCAP object..");
+       DEBUG ("dns plugin: Creating PCAP object..");
        pcap_obj = pcap_open_live ((pcap_device != NULL) ? pcap_device : "any",
                        PCAP_SNAPLEN,
                        0 /* Not promiscuous */,
diff --combined src/gmond.c
@@@ -541,11 -541,6 +541,11 @@@ static int staging_entry_update (const 
      se->vl.values[ds_index].counter += value.counter;
    else if (ds_type == DS_TYPE_GAUGE)
      se->vl.values[ds_index].gauge = value.gauge;
 +  else if (ds_type == DS_TYPE_DERIVE)
 +    se->vl.values[ds_index].DERIVE += value.derive;
 +  else if (ds_type == DS_TYPE_ABSOLUTE)
 +    se->vl.values[ds_index].ABSOLUTE = value.absolute;
 +
    se->flags |= (0x01 << ds_index);
  
    /* Check if all values have been set and submit if so. */
@@@ -570,7 -565,6 +570,7 @@@ static int mc_handle_value_msg (Ganglia
  
    value_t value_counter;
    value_t value_gauge;
 +  value_t value_derive;
  
    /* Fill in `host', `name', `value_counter', and `value_gauge' according to
     * the value type, or return with an error. */
        name = msg_uint.metric_id.name;
        value_counter.counter = (counter_t) msg_uint.ui;
        value_gauge.gauge = (gauge_t) msg_uint.ui;
 +      value_derive.derive = (derive_t) msg_uint.ui;
        break;
      }
  
  
        endptr = NULL;
        errno = 0;
-       value_counter.counter = (counter_t) strtoll (msg_string.str,
+       value_counter.counter = (counter_t) strtoull (msg_string.str,
            &endptr, /* base = */ 0);
        if ((endptr == msg_string.str) || (errno != 0))
          value_counter.counter = -1;
        if ((endptr == msg_string.str) || (errno != 0))
          value_gauge.gauge = NAN;
  
 +      endptr = NULL;
 +      errno = 0;
 +      value_derive.derive = (derive_t) strtoll (msg_string.str,
 +          &endptr, /* base = */ 0);
 +      if ((endptr == msg_string.str) || (errno != 0))
 +        value_derive.derive = 0;
 +
        break;
      }
  
        name = msg_float.metric_id.name;
        value_counter.counter = (counter_t) msg_float.f;
        value_gauge.gauge = (gauge_t) msg_float.f;
 +      value_derive.derive = (derive_t) msg_float.f;
        break;
      }
  
        name = msg_double.metric_id.name;
        value_counter.counter = (counter_t) msg_double.d;
        value_gauge.gauge = (gauge_t) msg_double.d;
 +      value_derive.derive = (derive_t) msg_double.d;
        break;
      }
      default:
  
    map = metric_lookup (name);
    if (map != NULL)
 +  {
 +    value_t val_copy;
 +
 +    val_copy = value_counter;
 +    if (map->ds_type == DS_TYPE_GAUGE)
 +      val_copy = value_gauge;
 +    else if (map->ds_type == DS_TYPE_DERIVE)
 +      val_copy = value_derive;
 +
      return (staging_entry_update (host, name,
            map->type, map->type_instance,
            map->ds_index, map->ds_type,
 -          (map->ds_type == DS_TYPE_COUNTER) ? value_counter : value_gauge));
 +          val_copy));
 +  }
  
    DEBUG ("gmond plugin: Cannot find a translation for %s.", name);
    return (-1);
diff --combined src/java.c
@@@ -227,7 -227,7 +227,7 @@@ static jobject ctoj_jlong_to_number (JN
    jmethodID m_long_constructor;
  
    /* Look up the java.lang.Long class */
-   c_long = (*jvm_env)->FindClass (jvm_env, "java.lang.Long");
+   c_long = (*jvm_env)->FindClass (jvm_env, "java/lang/Long");
    if (c_long == NULL)
    {
      ERROR ("java plugin: ctoj_jlong_to_number: Looking up the "
@@@ -255,7 -255,7 +255,7 @@@ static jobject ctoj_jdouble_to_number (
    jmethodID m_double_constructor;
  
    /* Look up the java.lang.Long class */
-   c_double = (*jvm_env)->FindClass (jvm_env, "java.lang.Double");
+   c_double = (*jvm_env)->FindClass (jvm_env, "java/lang/Double");
    if (c_double == NULL)
    {
      ERROR ("java plugin: ctoj_jdouble_to_number: Looking up the "
@@@ -284,10 -284,6 +284,10 @@@ static jobject ctoj_value_to_number (JN
      return (ctoj_jlong_to_number (jvm_env, (jlong) value.counter));
    else if (ds_type == DS_TYPE_GAUGE)
      return (ctoj_jdouble_to_number (jvm_env, (jdouble) value.gauge));
 +  if (ds_type == DS_TYPE_DERIVE)
 +    return (ctoj_jlong_to_number (jvm_env, (jlong) value.derive));
 +  if (ds_type == DS_TYPE_ABSOLUTE)
 +    return (ctoj_jlong_to_number (jvm_env, (jlong) value.absolute));
    else
      return (NULL);
  } /* }}} jobject ctoj_value_to_number */
@@@ -612,7 -608,7 +612,7 @@@ static jobject ctoj_data_set (JNIEnv *j
  
    /* Search for the `DataSet (String type)' constructor. */
    m_constructor = (*jvm_env)->GetMethodID (jvm_env,
-       c_dataset, "<init>", "(Ljava.lang.String;)V");
+       c_dataset, "<init>", "(Ljava/lang/String;)V");
    if (m_constructor == NULL)
    {
      ERROR ("java plugin: ctoj_data_set: Looking up the "
@@@ -1046,39 -1042,33 +1046,39 @@@ static int jtoc_value (JNIEnv *jvm_env
  
    class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
  
 -  if (ds_type == DS_TYPE_COUNTER)
 +  if (ds_type == DS_TYPE_GAUGE)
    {
 -    jlong tmp_long;
 +    jdouble tmp_double;
  
 -    status = jtoc_long (jvm_env, &tmp_long,
 -        class_ptr, object_ptr, "longValue");
 +    status = jtoc_double (jvm_env, &tmp_double,
 +        class_ptr, object_ptr, "doubleValue");
      if (status != 0)
      {
        ERROR ("java plugin: jtoc_value: "
 -          "jtoc_long failed.");
 +          "jtoc_double failed.");
        return (-1);
      }
 -    (*ret_value).counter = (counter_t) tmp_long;
 +    (*ret_value).gauge = (gauge_t) tmp_double;
    }
    else
    {
 -    jdouble tmp_double;
 +    jlong tmp_long;
  
 -    status = jtoc_double (jvm_env, &tmp_double,
 -        class_ptr, object_ptr, "doubleValue");
 +    status = jtoc_long (jvm_env, &tmp_long,
 +        class_ptr, object_ptr, "longValue");
      if (status != 0)
      {
        ERROR ("java plugin: jtoc_value: "
 -          "jtoc_double failed.");
 +          "jtoc_long failed.");
        return (-1);
      }
 -    (*ret_value).gauge = (gauge_t) tmp_double;
 +
 +    if (ds_type == DS_TYPE_DERIVE)
 +      (*ret_value).derive = (derive_t) tmp_long;
 +    else if (ds_type == DS_TYPE_ABSOLUTE)
 +      (*ret_value).absolute = (absolute_t) tmp_long;
 +    else
 +      (*ret_value).counter = (counter_t) tmp_long;
    }
  
    return (0);
@@@ -2189,6 -2179,15 +2189,15 @@@ static int cjni_config_load_plugin (oco
    class->class = NULL;
    class->object = NULL;
  
+   { /* Replace all dots ('.') with slashes ('/'). Dots are usually used
+        thorough the Java community, but (Sun's) `FindClass' and friends need
+        slashes. */
+     size_t i;
+     for (i = 0; class->name[i] != 0; i++)
+       if (class->name[i] == '.')
+         class->name[i] = '/';
+   }
    DEBUG ("java plugin: Loading class %s", class->name);
  
    class->class = (*jvm_env)->FindClass (jvm_env, class->name);
@@@ -116,7 -116,7 +116,7 @@@ typedef struct lcc_response_s lcc_respo
  /* Even though Posix requires "strerror_r" to return an "int",
   * some systems (e.g. the GNU libc) return a "char *" _and_
   * ignore the second argument ... -tokkee */
- char *sstrerror (int errnum, char *buf, size_t buflen)
static char *sstrerror (int errnum, char *buf, size_t buflen)
  {
    buf[0] = 0;
  
@@@ -792,11 -792,6 +792,11 @@@ int lcc_putval (lcc_connection_t *c, co
        else
          SSTRCATF (command, ":%g", vl->values[i].gauge);
      }
 +    else if (vl->values_types[i] == LCC_TYPE_DERIVE)
 +      SSTRCATF (command, ":%"PRIu64, vl->values[i].derive);
 +    else if (vl->values_types[i] == LCC_TYPE_ABSOLUTE)
 +      SSTRCATF (command, ":%"PRIu64, vl->values[i].absolute);
 +
    } /* for (i = 0; i < vl->values_len; i++) */
  
    status = lcc_sendreceive (c, command, &res);
diff --combined src/utils_cache.c
@@@ -34,7 -34,7 +34,7 @@@ typedef struct cache_entry_
        char name[6 * DATA_MAX_NAME_LEN];
        int        values_num;
        gauge_t   *values_gauge;
 -      counter_t *values_counter;
 +      value_t   *values_raw;
        /* Time contained in the package
         * (for calculating rates) */
        time_t last_time;
@@@ -69,12 -69,12 +69,12 @@@ static cache_entry_t *cache_alloc (int 
    memset (ce, '\0', sizeof (cache_entry_t));
    ce->values_num = values_num;
  
 -  ce->values_gauge = (gauge_t *) calloc (values_num, sizeof (gauge_t));
 -  ce->values_counter = (counter_t *) calloc (values_num, sizeof (counter_t));
 -  if ((ce->values_gauge == NULL) || (ce->values_counter == NULL))
 +  ce->values_gauge = calloc (values_num, sizeof (*ce->values_gauge));
 +  ce->values_raw   = calloc (values_num, sizeof (*ce->values_raw));
 +  if ((ce->values_gauge == NULL) || (ce->values_raw == NULL))
    {
      sfree (ce->values_gauge);
 -    sfree (ce->values_counter);
 +    sfree (ce->values_raw);
      sfree (ce);
      ERROR ("utils_cache: cache_alloc: calloc failed.");
      return (NULL);
@@@ -89,7 -89,7 +89,7 @@@ static void cache_free (cache_entry_t *
      return;
  
    sfree (ce->values_gauge);
 -  sfree (ce->values_counter);
 +  sfree (ce->values_raw);
    sfree (ce);
  } /* void cache_free */
  
@@@ -167,21 -167,6 +167,21 @@@ static int uc_send_notification (const 
    return (0);
  } /* int uc_send_notification */
  
 +static void uc_check_range (const data_set_t *ds, cache_entry_t *ce)
 +{
 +  int i;
 +
 +  for (i = 0; i < ds->ds_num; i++)
 +  {
 +    if (isnan (ce->values_gauge[i]))
 +      continue;
 +    else if (ce->values_gauge[i] < ds->ds[i].min)
 +      ce->values_gauge[i] = NAN;
 +    else if (ce->values_gauge[i] > ds->ds[i].max)
 +      ce->values_gauge[i] = NAN;
 +  }
 +} /* void uc_check_range */
 +
  static int uc_insert (const data_set_t *ds, const value_list_t *vl,
      const char *key)
  {
  
    for (i = 0; i < ds->ds_num; i++)
    {
 -    if (ds->ds[i].type == DS_TYPE_COUNTER)
 +    switch (ds->ds[i].type)
      {
 -      ce->values_gauge[i] = NAN;
 -      ce->values_counter[i] = vl->values[i].counter;
 -    }
 -    else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
 -    {
 -      ce->values_gauge[i] = vl->values[i].gauge;
 -    }
 +      case DS_TYPE_COUNTER:
 +      ce->values_gauge[i] = NAN;
 +      ce->values_raw[i].counter = vl->values[i].counter;
 +      break;
 +
 +      case DS_TYPE_GAUGE:
 +      ce->values_gauge[i] = vl->values[i].gauge;
 +      ce->values_raw[i].gauge = vl->values[i].gauge;
 +      break;
 +
 +      case DS_TYPE_DERIVE:
 +      ce->values_gauge[i] = NAN;
 +      ce->values_raw[i].derive = vl->values[i].derive;
 +      break;
 +
 +      case DS_TYPE_ABSOLUTE:
 +      ce->values_gauge[i] = NAN;
 +      if (vl->interval > 0)
 +        ce->values_gauge[i] = ((double) vl->values[i].absolute)
 +          / ((double) vl->interval);
 +      ce->values_raw[i].absolute = vl->values[i].absolute;
 +      break;
 +      
 +      default:
 +      /* This shouldn't happen. */
 +      ERROR ("uc_insert: Don't know how to handle data source type %i.",
 +          ds->ds[i].type);
 +      return (-1);
 +    } /* switch (ds->ds[i].type) */
    } /* for (i) */
  
 +  /* Prune invalid gauge data */
 +  uc_check_range (ds, ce);
 +
    ce->last_time = vl->time;
    ce->last_update = time (NULL);
    ce->interval = vl->interval;
@@@ -300,8 -260,9 +300,9 @@@ int uc_check_timeout (void
          (keys_len + 1) * sizeof (char *));
        if (tmp == NULL)
        {
-       ERROR ("uc_purge: realloc failed.");
+       ERROR ("uc_check_timeout: realloc failed.");
        c_avl_iterator_destroy (iter);
+       sfree (keys);
        pthread_mutex_unlock (&cache_lock);
        return (-1);
        }
      }
    } /* while (c_avl_iterator_next) */
  
+   ce = NULL;
    for (i = 0; i < keys_len; i++)
    {
      int status;
      {
        ERROR ("uc_check_timeout: ut_check_interesting failed.");
        sfree (keys[i]);
+       continue;
      }
      else if (status == 0) /* ``service'' is uninteresting */
      {
-       ce = NULL;
        DEBUG ("uc_check_timeout: %s is missing but ``uninteresting''",
          keys[i]);
        status = c_avl_remove (cache_tree, keys[i],
        sfree (key);
        cache_free (ce);
      }
-     else if (status == 2) /* persist */
+     /* If we get here, the value is ``interesting''. Query the record from the
+      * cache and update the state field. */
+     if (c_avl_get (cache_tree, keys[i], (void *) &ce) != 0)
+     {
+       ERROR ("uc_check_timeout: cannot get data for %s from cache", keys[i]);
+       /* Do not free `keys[i]' so a notification is sent further down. */
+       continue;
+     }
+     assert (ce != NULL);
+     if (status == 2) /* persist */
      {
        DEBUG ("uc_check_timeout: %s is missing, sending notification.",
          keys[i]);
        ce->state = STATE_MISSING;
+       /* Do not free `keys[i]' so a notification is sent further down. */
      }
      else if (status == 1) /* do not persist */
      {
        DEBUG ("uc_check_timeout: %s is missing but "
            "notification has already been sent.",
            keys[i]);
+       /* Set `keys[i]' to NULL to no notification is sent. */
        sfree (keys[i]);
        }
        else /* (ce->state != STATE_MISSING) */
        DEBUG ("uc_check_timeout: %s is missing, sending one notification.",
            keys[i]);
        ce->state = STATE_MISSING;
+       /* Do not free `keys[i]' so a notification is sent further down. */
        }
      }
      else
        WARNING ("uc_check_timeout: ut_check_interesting (%s) returned "
          "invalid status %i.",
          keys[i], status);
+       sfree (keys[i]);
      }
    } /* for (keys[i]) */
  
@@@ -440,70 -418,36 +458,70 @@@ int uc_update (const data_set_t *ds, co
  
    for (i = 0; i < ds->ds_num; i++)
    {
 -    if (ds->ds[i].type == DS_TYPE_COUNTER)
 +    switch (ds->ds[i].type)
      {
 -      counter_t diff;
 -
 -      /* check if the counter has wrapped around */
 -      if (vl->values[i].counter < ce->values_counter[i])
 -      {
 -      if (ce->values_counter[i] <= 4294967295U)
 -        diff = (4294967295U - ce->values_counter[i])
 -          + vl->values[i].counter;
 -      else
 -        diff = (18446744073709551615ULL - ce->values_counter[i])
 -          + vl->values[i].counter;
 -      }
 -      else /* counter has NOT wrapped around */
 -      {
 -      diff = vl->values[i].counter - ce->values_counter[i];
 -      }
 +      case DS_TYPE_COUNTER:
 +      {
 +        counter_t diff;
 +
 +        /* check if the counter has wrapped around */
 +        if (vl->values[i].counter < ce->values_raw[i].counter)
 +        {
 +          if (ce->values_raw[i].counter <= 4294967295U)
 +            diff = (4294967295U - ce->values_raw[i].counter)
 +              + vl->values[i].counter;
 +          else
 +            diff = (18446744073709551615ULL - ce->values_raw[i].counter)
 +              + vl->values[i].counter;
 +        }
 +        else /* counter has NOT wrapped around */
 +        {
 +          diff = vl->values[i].counter - ce->values_raw[i].counter;
 +        }
 +
 +        ce->values_gauge[i] = ((double) diff)
 +          / ((double) (vl->time - ce->last_time));
 +        ce->values_raw[i].counter = vl->values[i].counter;
 +      }
 +      break;
 +
 +      case DS_TYPE_GAUGE:
 +      ce->values_raw[i].gauge = vl->values[i].gauge;
 +      ce->values_gauge[i] = vl->values[i].gauge;
 +      break;
 +
 +      case DS_TYPE_DERIVE:
 +      {
 +        derive_t diff;
 +
 +        diff = vl->values[i].derive - ce->values_raw[i].derive;
 +
 +        ce->values_gauge[i] = ((double) diff)
 +          / ((double) (vl->time - ce->last_time));
 +        ce->values_raw[i].derive = vl->values[i].derive;
 +      }
 +      break;
 +
 +      case DS_TYPE_ABSOLUTE:
 +      ce->values_gauge[i] = ((double) vl->values[i].absolute)
 +        / ((double) (vl->time - ce->last_time));
 +      ce->values_raw[i].absolute = vl->values[i].absolute;
 +      break;
 +
 +      default:
 +      /* This shouldn't happen. */
 +      pthread_mutex_unlock (&cache_lock);
 +      ERROR ("uc_update: Don't know how to handle data source type %i.",
 +          ds->ds[i].type);
 +      return (-1);
 +    } /* switch (ds->ds[i].type) */
  
 -      ce->values_gauge[i] = ((double) diff)
 -      / ((double) (vl->time - ce->last_time));
 -      ce->values_counter[i] = vl->values[i].counter;
 -    }
 -    else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
 -    {
 -      ce->values_gauge[i] = vl->values[i].gauge;
 -    }
      DEBUG ("uc_update: %s: ds[%i] = %lf", name, i, ce->values_gauge[i]);
    } /* for (i) */
  
 +  /* Prune invalid gauge data */
 +  uc_check_range (ds, ce);
 +
    ce->last_time = vl->time;
    ce->last_update = time (NULL);
    ce->interval = vl->interval;