-# svn stuff:
-.svn
-contrib/.svn
-debian/.svn
-src/.svn
-src/libconfig/.svn
-src/liboping/.svn
-
# build.sh stuff:
-INSTALL
Makefile.in
-aclocal.m4
-autom4te.cache
-compile
-config.guess
-config.sub
-configure
-depcomp
-install-sh
-libltdl
-ltmain.sh
-missing
-src/Makefile.in
+/INSTALL
+/aclocal.m4
+/autom4te.cache
+/autom4te.cache
+/compile
+/config.guess
+/config.sub
+/configure
+/depcomp
+/install-sh
+/libltdl/
+/ltmain.sh
+/missing
src/config.h.in
-src/libconfig/Makefile.in
-src/liboping/Makefile.in
# configure stuff:
Makefile
src/stamp-h1
# make stuff:
-src/.libs
-src/*.la
-src/*.lo
-src/*.o
+*.la
+*.lo
+*.o
+.libs/
src/collectd
src/collectd-nagios
src/collectdmon
-src/collectd*.1
-src/collectd*.5
-src/types.db.5
-src/config.h.in~
-src/libcollectdclient/.libs
-src/libcollectdclient/*.la
-src/libcollectdclient/*.lo
+src/*.1
+src/*.5
src/libcollectdclient/lcc_features.h
-src/libiptc/.libs
-src/libiptc/*.la
-src/libiptc/*.lo
-src/liboconfig/.libs
-src/liboconfig/*.la
-src/liboconfig/*.lo
-src/liboping/.libs
-src/liboping/*.la
-src/liboping/*.lo
+
+# patch stuff
+*.rej
+*.orig
# lex / yacc stuff:
ylwrap
src/liboconfig/parser.h
src/liboconfig/scanner.c
+# make dist stuff:
+/collectd-*.tar.gz
+/collectd-*.tar.bz2
+
# perl stuff:
bindings/.perl-directory-stamp
bindings/perl/Collectd/pm_to_blib
bindings/perl/blib/
bindings/perl/pm_to_blib
-# make dist stuff:
-collectd-*.tar.gz
-collectd-*.tar.bz2
+# java stuff
+bindings/java/java-build-stamp
+bindings/java/org/collectd/api/*.class
+ the disk plugin, and
+ the users plugin.
+Paul Sadauskas <psadauskas at gmail.com>
+ - tokyotyrant plugin.
+
Peter Holik <peter at holik.at>
- cpufreq plugin.
- multimeter plugin.
- conntrack
Number of nf_conntrack entries.
+ - couchdb
+ Parse statistics from CouchDB JSON documents.
+
- cpu
CPU utilization: Time spent in the system, user, nice, idle, and related
states.
- thermal
Linux ACPI thermal zone information.
+ - tokyotyrant
+ Record in and file size of a Tokyo Cabinet database file.
+
- uptime
System uptime statistics.
* libxmms (optional)
<http://www.xmms.org/>
+ * libyajl (optional)
+ Parse JSON data. This is needed for the `couchdb' plugin.
+ <http://www.lloydforge.org/projects/yajl/>
Configuring / Compiling / Installing
------------------------------------
fi
# }}}
+# --with-libtokyotyrant {{{
+with_libtokyotyrant_cppflags=""
+with_libtokyotyrant_ldflags=""
+with_libtokyotyrant_libs=""
+AC_ARG_WITH(libtokyotyrant, [AS_HELP_STRING([--with-libtokyotyrant@<:@=PREFIX@:>@], [Path to libtokyotyrant.])],
+[
+ if test "x$withval" = "xno"
+ then
+ with_libtokyotyrant="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_libtokyotyrant="yes"
+ else
+ with_libtokyotyrant_cppflags="-I$withval/include"
+ with_libtokyotyrant_ldflags="-L$withval/include"
+ with_libtokyotyrant_libs="-ltokyotyrant"
+ with_libtokyotyrant="yes"
+ fi; fi
+],
+[
+ with_libtokyotyrant="yes"
+])
+
+if test "x$with_libtokyotyrant" = "xyes"
+then
+ if $PKG_CONFIG --exists tokyotyrant
+ then
+ with_libtokyotyrant_cppflags="$with_libtokyotyrant_cppflags `$PKG_CONFIG --cflags tokyotyrant`"
+ with_libtokyotyrant_ldflags="$with_libtokyotyrant_ldflags `pkg-config --libs-only-L tokyotyrant`"
+ with_libtokyotyrant_libs="$with_libtokyotyrant_libs `pkg-config --libs-only-l tokyotyrant`"
+ fi
+fi
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+CPPFLAGS="$CPPFLAGS $with_libtokyotyrant_cppflags"
+LDFLAGS="$LDFLAGS $with_libtokyotyrant_ldflags"
+
+if test "x$with_libtokyotyrant" = "xyes"
+then
+ AC_CHECK_HEADERS(tcrdb.h,
+ [
+ AC_DEFINE(HAVE_TCRDB_H, 1,
+ [Define to 1 if you have the <tcrdb.h> header file.])
+ ], [with_libtokyotyrant="no (tcrdb.h not found)"])
+fi
+
+if test "x$with_libtokyotyrant" = "xyes"
+then
+ AC_CHECK_LIB(tokyotyrant, tcrdbrnum,
+ [
+ AC_DEFINE(HAVE_LIBTOKYOTYRANT, 1,
+ [Define to 1 if you have the tokyotyrant library (-ltokyotyrant).])
+ ],
+ [with_libtokyotyrant="no (symbol tcrdbrnum not found)"],
+ [$with_libtokyotyrant_libs])
+fi
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+
+if test "x$with_libtokyotyrant" = "xyes"
+then
+ BUILD_WITH_LIBTOKYOTYRANT_CPPFLAGS="$with_libtokyotyrant_cppflags"
+ BUILD_WITH_LIBTOKYOTYRANT_LDFLAGS="$with_libtokyotyrant_ldflags"
+ BUILD_WITH_LIBTOKYOTYRANT_LIBS="$with_libtokyotyrant_libs"
+ AC_SUBST(BUILD_WITH_LIBTOKYOTYRANT_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBTOKYOTYRANT_LDFLAGS)
+ AC_SUBST(BUILD_WITH_LIBTOKYOTYRANT_LIBS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBTOKYOTYRANT, test "x$with_libtokyotyrant" = "xyes")
+# }}}
+
# --with-libupsclient {{{
with_libupsclient_config=""
with_libupsclient_cflags=""
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=""
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"
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])
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])
AC_PLUGIN([teamspeak2], [yes], [TeamSpeak2 server statistics])
AC_PLUGIN([ted], [$plugin_ted], [Read The Energy Detective values])
AC_PLUGIN([thermal], [$plugin_thermal], [Linux ACPI thermal zone statistics])
+AC_PLUGIN([tokyotyrant], [$with_libtokyotyrant], [TokyoTyrant database statistics])
AC_PLUGIN([unixsock], [yes], [Unixsock communication plugin])
AC_PLUGIN([uptime], [$plugin_uptime], [Uptime statistics])
AC_PLUGIN([users], [$plugin_users], [User statistics])
librrd . . . . . . . $with_librrd
libsensors . . . . . $with_libsensors
libstatgrab . . . . . $with_libstatgrab
+ libtokyotyrant . . . $with_libtokyotyrant
libupsclient . . . . $with_libupsclient
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
tcpconns . . . . . . $enable_tcpconns
teamspeak2 . . . . . $enable_teamspeak2
ted . . . . . . . . . $enable_ted
+ tokyotyrant . . . . . $enable_tokyotyrant
thermal . . . . . . . $enable_thermal
unixsock . . . . . . $enable_unixsock
uptime . . . . . . . $enable_uptime
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
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
collectd_DEPENDENCIES += thermal.la
endif
+if BUILD_PLUGIN_TOKYOTYRANT
+pkglib_LTLIBRARIES += tokyotyrant.la
+tokyotyrant_la_SOURCES = tokyotyrant.c
+tokyotyrant_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBTOKYOTYRANT_CPPFLAGS)
+tokyotyrant_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBTOKYOTYRANT_LDFLAGS)
+tokyotyrant_la_LIBADD = $(BUILD_WITH_LIBTOKYOTYRANT_LIBS)
+if BUILD_WITH_LIBSOCKET
+tokyotyrant_la_LIBADD += -lsocket
+endif
+collectd_LDADD += "-dlopen" tokyotyrant.la
+collectd_DEPENDENCIES += tokyotyrant.la
+endif
+
if BUILD_PLUGIN_UNIXSOCK
pkglib_LTLIBRARIES += unixsock.la
unixsock_la_SOURCES = unixsock.c \
[{
name => 'data_source_name',
- type => DS_TYPE_COUNTER || DS_TYPE_GAUGE,
+ type => DS_TYPE_COUNTER || DS_TYPE_GAUGE || DS_TYPE_DERIVE || DS_TYPE_ABSOLUTE,
min => value || undef,
max => value || undef
}, ...]
=item B<DS_TYPE_GAUGE>
+=item B<DS_TYPE_DERIVE>
+
+=item B<DS_TYPE_ABSOLUTE>
+
=back
=item B<:log>
#@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
#@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
#@BUILD_PLUGIN_TEAMSPEAK2_TRUE@LoadPlugin teamspeak2
#@BUILD_PLUGIN_TED_TRUE@LoadPlugin ted
#@BUILD_PLUGIN_THERMAL_TRUE@LoadPlugin thermal
+#@BUILD_PLUGIN_TOKYOTYRANT_TRUE@LoadPlugin tokyotyrant
#@BUILD_PLUGIN_UNIXSOCK_TRUE@LoadPlugin unixsock
#@BUILD_PLUGIN_UPTIME_TRUE@LoadPlugin uptime
#@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
# </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
# 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"
# Version 1
# Community "community_string"
# Collect "std_traffic"
-# Inverval 120
+# Interval 120
# </Host>
# <Host "some.server.mydomain.org">
# Address "192.168.0.42"
# IgnoreSelected false
#</Plugin>
+#<Plugin tokyotyrant>
+# Host "localhost"
+# Port "1978"
+#</Plugin>
+
#<Plugin unixsock>
# SocketFile "@prefix@/var/run/@PACKAGE_NAME@-unixsock"
# SocketGroup "collectd"
=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
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>
=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.
=back
+=head2 Plugin C<tokyotyrant>
+
+The C<tokyotyrant plugin> connects to a TokyoTyrant server and collects a
+couple metrics: number of records, and database size on disk.
+
+=over 4
+
+=item B<Host> I<Hostname/IP>
+
+The hostname or ip which identifies the server.
+Default: B<127.0.0.1>
+
+=item B<Port> I<Service/Port>
+
+The query port of the server. This needs to be a string, even if the port is
+given in its numeric form.
+Default: B<1978>
+
+=back
+
=head2 Plugin C<unixsock>
=over 4
missing value is generated once every B<Interval> seconds. If set to B<false>
only one such notification is generated until the value appears again.
+=item B<Percentage> B<true>|B<false>
+
+If set to B<true>, the minimum and maximum values given are interpreted as
+percentage value, relative to the other data sources. This is helpful for
+example for the "df" type, where you may want to issue a warning when less than
+5E<nbsp>% of the total space is available. Defaults to B<false>.
+
=back
=head1 FILTER CONFIGURATION
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)
{
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;
}
int parse_identifier (char *str, char **ret_host,
char **ret_plugin, char **ret_plugin_instance,
char **ret_type, char **ret_type_instance);
-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);
int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
#if !HAVE_GETPWNAM_R
--- /dev/null
+/**
+ * collectd - src/couchdb.c
+ * Copyright (C) 2009 Doug MacEachern
+ * Copyright (C) 2006-2009 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Doug MacEachern <dougm at hyperic.com>
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_avltree.h"
+
+#include <curl/curl.h>
+#include <yajl/yajl_parse.h>
+
+#define COUCHDB_DEFAULT_HOST "localhost"
+#define COUCHDB_KEY_MAGIC 0x43484b59UL /* CHKY */
+#define COUCHDB_IS_KEY(key) (key)->magic == COUCHDB_KEY_MAGIC
+#define COUCHDB_ANY "*"
+#define COUCH_MIN(x,y) ((x) < (y) ? (x) : (y))
+
+struct couchdb_key_s;
+typedef struct couchdb_key_s couchdb_key_t;
+struct couchdb_key_s /* {{{ */
+{
+ char *path;
+ char *type;
+ char *instance;
+ unsigned long magic;
+};
+/* }}} */
+
+struct couchdb_s /* {{{ */
+{
+ char *instance;
+ char *host;
+
+ char *url;
+ char *user;
+ char *pass;
+ char *credentials;
+ int verify_peer;
+ int verify_host;
+ char *cacert;
+
+ CURL *curl;
+ char curl_errbuf[CURL_ERROR_SIZE];
+
+ yajl_handle yajl;
+ c_avl_tree_t *tree;
+ couchdb_key_t *key;
+ int depth;
+ struct {
+ union {
+ c_avl_tree_t *tree;
+ couchdb_key_t *key;
+ };
+ char name[DATA_MAX_NAME_LEN];
+ } state[YAJL_MAX_DEPTH];
+};
+typedef struct couchdb_s couchdb_t; /* }}} */
+
+static int couchdb_read (user_data_t *ud);
+static int couchdb_curl_perform (couchdb_t *db, CURL *curl);
+static void couchdb_submit (couchdb_t *db, couchdb_key_t *key, value_t *value);
+
+static size_t couchdb_curl_callback (void *buf, /* {{{ */
+ size_t size, size_t nmemb, void *user_data)
+{
+ couchdb_t *db;
+ size_t len;
+ yajl_status status;
+
+ len = size * nmemb;
+
+ if (len <= 0)
+ return (len);
+
+ db = user_data;
+ if (db == NULL)
+ return (0);
+
+ status = yajl_parse(db->yajl, (unsigned char *)buf, len);
+ if (status == yajl_status_ok)
+ {
+ status = yajl_parse_complete(db->yajl);
+ return (len);
+ }
+ else if (status == yajl_status_insufficient_data)
+ return (len);
+
+ if (status != yajl_status_ok)
+ {
+ unsigned char *msg =
+ yajl_get_error(db->yajl, 1, (unsigned char *)buf, len);
+ ERROR ("couchdb plugin: yajl_parse failed: %s", msg);
+ yajl_free_error(db->yajl, msg);
+ return (0); /* abort write callback */
+ }
+
+ return (len);
+} /* }}} size_t couchdb_curl_callback */
+
+static int couchdb_get_type (couchdb_key_t *key)
+{
+ const data_set_t *ds;
+
+ ds = plugin_get_ds (key->type);
+ if (ds == NULL)
+ return -1; /* let plugin_write do the complaining */
+ else
+ return ds->ds[0].type; /* XXX support ds->ds_len > 1 */
+}
+
+/* yajl callbacks */
+static int couchcb_integer (void *ctx, long val)
+{
+ couchdb_t *db = (couchdb_t *)ctx;
+ couchdb_key_t *key = db->state[db->depth].key;
+
+ if (key != NULL)
+ {
+ value_t vt;
+ int type;
+
+ type = couchdb_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;
+
+ couchdb_submit (db, key, &vt);
+ }
+ return 1;
+}
+
+static int couchcb_double (void *ctx, double val)
+{
+ couchdb_t *db = (couchdb_t *)ctx;
+ couchdb_key_t *key = db->state[db->depth].key;
+
+ if (key != NULL)
+ {
+ value_t vt;
+ int type;
+
+ type = couchdb_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;
+
+ couchdb_submit (db, key, &vt);
+ }
+ return 1;
+}
+
+static int couchcb_map_key (void *ctx, const unsigned char *val,
+ unsigned int len)
+{
+ couchdb_t *db = (couchdb_t *)ctx;
+ c_avl_tree_t *tree;
+
+ tree = db->state[db->depth-1].tree;
+
+ if (tree != NULL)
+ {
+ couchdb_key_t *value;
+ char *name;
+
+ name = db->state[db->depth].name;
+ len = COUCH_MIN(len, sizeof (db->state[db->depth].name)-1);
+ sstrncpy (name, (char *)val, len+1);
+
+ if (c_avl_get (tree, name, (void *) &value) == 0)
+ db->state[db->depth].key = value;
+ else if (c_avl_get (tree, COUCHDB_ANY, (void *) &value) == 0)
+ db->state[db->depth].key = value;
+ else
+ db->state[db->depth].key = NULL;
+ }
+
+ return 1;
+}
+
+static int couchcb_string (void *ctx, const unsigned char *val,
+ unsigned int len)
+{
+ couchdb_t *db = (couchdb_t *)ctx;
+ c_avl_tree_t *tree;
+ char *ptr;
+
+ if (db->depth != 1) /* e.g. _all_dbs */
+ return 1;
+
+ couchcb_map_key (ctx, val, len); /* same logic */
+
+ tree = db->state[db->depth].tree;
+
+ if ((tree != NULL) && (ptr = rindex (db->url, '/')))
+ {
+ char url[PATH_MAX];
+ CURL *curl;
+
+ /* url =~ s,[^/]+$,$name, */
+ len = (ptr - db->url) + 1;
+ ptr = url;
+ sstrncpy (ptr, db->url, sizeof (url));
+ sstrncpy (ptr + len, db->state[db->depth].name, sizeof (url) - len);
+
+ curl = curl_easy_duphandle (db->curl);
+ curl_easy_setopt (curl, CURLOPT_URL, url);
+ couchdb_curl_perform (db, curl);
+ curl_easy_cleanup (curl);
+ }
+ return 1;
+}
+
+static int couchcb_start (void *ctx)
+{
+ couchdb_t *db = (couchdb_t *)ctx;
+ if (++db->depth >= YAJL_MAX_DEPTH)
+ {
+ ERROR ("couchdb plugin: %s depth exceeds max, aborting.", db->url);
+ return 0;
+ }
+ return 1;
+}
+
+static int couchcb_end (void *ctx)
+{
+ couchdb_t *db = (couchdb_t *)ctx;
+ db->state[db->depth].tree = NULL;
+ --db->depth;
+ return 1;
+}
+
+static int couchcb_start_map (void *ctx)
+{
+ return couchcb_start (ctx);
+}
+
+static int couchcb_end_map (void *ctx)
+{
+ return couchcb_end (ctx);
+}
+
+static int couchcb_start_array (void * ctx)
+{
+ return couchcb_start (ctx);
+}
+
+static int couchcb_end_array (void * ctx)
+{
+ return couchcb_start (ctx);
+}
+
+static yajl_callbacks ycallbacks = {
+ NULL, /* null */
+ NULL, /* boolean */
+ couchcb_integer,
+ couchcb_double,
+ NULL, /* number */
+ couchcb_string,
+ couchcb_start_map,
+ couchcb_map_key,
+ couchcb_end_map,
+ couchcb_start_array,
+ couchcb_end_array
+};
+
+/* end yajl callbacks */
+
+static void couchdb_key_free (couchdb_key_t *key) /* {{{ */
+{
+ if (key == NULL)
+ return;
+
+ sfree (key->path);
+ sfree (key->type);
+ sfree (key->instance);
+
+ sfree (key);
+} /* }}} void couchdb_key_free */
+
+static void couchdb_tree_free (c_avl_tree_t *tree) /* {{{ */
+{
+ char *name;
+ void *value;
+
+ while (c_avl_pick (tree, (void *) &name, (void *) &value) == 0)
+ {
+ couchdb_key_t *key = (couchdb_key_t *)value;
+
+ if (COUCHDB_IS_KEY(key))
+ couchdb_key_free (key);
+ else
+ couchdb_tree_free ((c_avl_tree_t *)value);
+
+ sfree (name);
+ }
+
+ c_avl_destroy (tree);
+} /* }}} void couchdb_tree_free */
+
+static void couchdb_free (void *arg) /* {{{ */
+{
+ couchdb_t *db;
+
+ DEBUG ("couchdb plugin: couchdb_free (arg = %p);", arg);
+
+ db = (couchdb_t *) arg;
+
+ if (db == NULL)
+ return;
+
+ if (db->curl != NULL)
+ curl_easy_cleanup (db->curl);
+ db->curl = NULL;
+
+ if (db->tree != NULL)
+ couchdb_tree_free (db->tree);
+ db->tree = NULL;
+
+ sfree (db->instance);
+ sfree (db->host);
+
+ sfree (db->url);
+ sfree (db->user);
+ sfree (db->pass);
+ sfree (db->credentials);
+ sfree (db->cacert);
+
+ sfree (db);
+} /* }}} void couchdb_free */
+
+/* Configuration handling functions {{{ */
+
+static int couchdb_config_add_string (const char *name, char **dest, /* {{{ */
+ oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("couchdb plugin: `%s' needs exactly one string argument.", name);
+ return (-1);
+ }
+
+ sfree (*dest);
+ *dest = strdup (ci->values[0].value.string);
+ if (*dest == NULL)
+ return (-1);
+
+ return (0);
+} /* }}} int couchdb_config_add_string */
+
+static int couchdb_config_set_boolean (const char *name, int *dest, /* {{{ */
+ oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ {
+ WARNING ("couchdb plugin: `%s' needs exactly one boolean argument.", name);
+ return (-1);
+ }
+
+ *dest = ci->values[0].value.boolean ? 1 : 0;
+
+ return (0);
+} /* }}} int couchdb_config_set_boolean */
+
+static c_avl_tree_t *couchdb_avl_create(void)
+{
+ return c_avl_create ((int (*) (const void *, const void *)) strcmp);
+}
+
+static int couchdb_config_add_key (couchdb_t *db, /* {{{ */
+ oconfig_item_t *ci)
+{
+ couchdb_key_t *key;
+ int status;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("couchdb plugin: The `Key' block "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ key = (couchdb_key_t *) malloc (sizeof (*key));
+ if (key == NULL)
+ {
+ ERROR ("couchdb plugin: malloc failed.");
+ return (-1);
+ }
+ memset (key, 0, sizeof (*key));
+ key->magic = COUCHDB_KEY_MAGIC;
+
+ if (strcasecmp ("Key", ci->key) == 0)
+ {
+ status = couchdb_config_add_string ("Key", &key->path, ci);
+ if (status != 0)
+ {
+ sfree (key);
+ return (status);
+ }
+ }
+ else
+ {
+ ERROR ("couchdb plugin: couchdb_config: "
+ "Invalid key: %s", ci->key);
+ return (-1);
+ }
+
+ status = 0;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Type", child->key) == 0)
+ status = couchdb_config_add_string ("Type", &key->type, child);
+ else if (strcasecmp ("Instance", child->key) == 0)
+ status = couchdb_config_add_string ("Instance", &key->instance, child);
+ else
+ {
+ WARNING ("couchdb plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (i = 0; i < ci->children_num; i++) */
+
+ while (status == 0)
+ {
+ if (key->type == NULL)
+ {
+ WARNING ("couchdb plugin: `Type' missing in `Key' block.");
+ status = -1;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ /* store path in a tree that will match the json map structure, example:
+ * "httpd/requests/count",
+ * "httpd/requests/current" ->
+ * { "httpd": { "requests": { "count": $key, "current": $key } } }
+ */
+ if (status == 0)
+ {
+ char *ptr;
+ char *name;
+ char ent[PATH_MAX];
+ c_avl_tree_t *tree;
+
+ if (db->tree == NULL)
+ db->tree = couchdb_avl_create();
+
+ tree = db->tree;
+ name = key->path;
+ ptr = key->path;
+ if (*ptr == '/')
+ ++ptr;
+
+ name = ptr;
+ while (*ptr)
+ {
+ if (*ptr == '/')
+ {
+ c_avl_tree_t *value;
+ int len;
+
+ len = ptr-name;
+ if (len == 0)
+ break;
+ sstrncpy (ent, name, len+1);
+
+ if (c_avl_get (tree, ent, (void *) &value) != 0)
+ {
+ value = couchdb_avl_create ();
+ c_avl_insert (tree, strdup (ent), value);
+ }
+
+ tree = value;
+ name = ptr+1;
+ }
+ ++ptr;
+ }
+ if (*name)
+ c_avl_insert (tree, strdup(name), key);
+ else
+ {
+ ERROR ("couchdb plugin: invalid key: %s", key->path);
+ status = -1;
+ }
+ }
+
+ return (status);
+} /* }}} int couchdb_config_add_key */
+
+static int couchdb_init_curl (couchdb_t *db) /* {{{ */
+{
+ db->curl = curl_easy_init ();
+ if (db->curl == NULL)
+ {
+ ERROR ("couchdb plugin: curl_easy_init failed.");
+ return (-1);
+ }
+
+ curl_easy_setopt (db->curl, CURLOPT_WRITEFUNCTION, couchdb_curl_callback);
+ curl_easy_setopt (db->curl, CURLOPT_WRITEDATA, db);
+ curl_easy_setopt (db->curl, CURLOPT_USERAGENT,
+ PACKAGE_NAME"/"PACKAGE_VERSION);
+ curl_easy_setopt (db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf);
+ curl_easy_setopt (db->curl, CURLOPT_URL, db->url);
+
+ if (db->user != NULL)
+ {
+ size_t credentials_size;
+
+ credentials_size = strlen (db->user) + 2;
+ if (db->pass != NULL)
+ credentials_size += strlen (db->pass);
+
+ db->credentials = (char *) malloc (credentials_size);
+ if (db->credentials == NULL)
+ {
+ ERROR ("couchdb plugin: malloc failed.");
+ return (-1);
+ }
+
+ ssnprintf (db->credentials, credentials_size, "%s:%s",
+ db->user, (db->pass == NULL) ? "" : db->pass);
+ curl_easy_setopt (db->curl, CURLOPT_USERPWD, db->credentials);
+ }
+
+ curl_easy_setopt (db->curl, CURLOPT_SSL_VERIFYPEER, db->verify_peer);
+ curl_easy_setopt (db->curl, CURLOPT_SSL_VERIFYHOST,
+ db->verify_host ? 2 : 0);
+ if (db->cacert != NULL)
+ curl_easy_setopt (db->curl, CURLOPT_CAINFO, db->cacert);
+
+ return (0);
+} /* }}} int couchdb_init_curl */
+
+static int couchdb_config_add_url (oconfig_item_t *ci) /* {{{ */
+{
+ couchdb_t *db;
+ int status = 0;
+ int i;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("couchdb plugin: The `URL' block "
+ "needs exactly one string argument.");
+ return (-1);
+ }
+
+ db = (couchdb_t *) malloc (sizeof (*db));
+ if (db == NULL)
+ {
+ ERROR ("couchdb plugin: malloc failed.");
+ return (-1);
+ }
+ memset (db, 0, sizeof (*db));
+
+ if (strcasecmp ("URL", ci->key) == 0)
+ {
+ status = couchdb_config_add_string ("URL", &db->url, ci);
+ if (status != 0)
+ {
+ sfree (db);
+ return (status);
+ }
+ }
+ else
+ {
+ ERROR ("couchdb plugin: couchdb_config: "
+ "Invalid key: %s", ci->key);
+ return (-1);
+ }
+
+ /* Fill the `couchdb_t' structure.. */
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Instance", child->key) == 0)
+ status = couchdb_config_add_string ("Instance", &db->instance, child);
+ else if (strcasecmp ("Host", child->key) == 0)
+ status = couchdb_config_add_string ("Host", &db->host, child);
+ else if (strcasecmp ("User", child->key) == 0)
+ status = couchdb_config_add_string ("User", &db->user, child);
+ else if (strcasecmp ("Password", child->key) == 0)
+ status = couchdb_config_add_string ("Password", &db->pass, child);
+ else if (strcasecmp ("VerifyPeer", child->key) == 0)
+ status = couchdb_config_set_boolean ("VerifyPeer", &db->verify_peer, child);
+ else if (strcasecmp ("VerifyHost", child->key) == 0)
+ status = couchdb_config_set_boolean ("VerifyHost", &db->verify_host, child);
+ else if (strcasecmp ("CACert", child->key) == 0)
+ status = couchdb_config_add_string ("CACert", &db->cacert, child);
+ else if (strcasecmp ("Key", child->key) == 0)
+ status = couchdb_config_add_key (db, child);
+ else
+ {
+ WARNING ("couchdb plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ if (status == 0)
+ {
+ if (db->tree == NULL)
+ {
+ WARNING ("couchdb plugin: No (valid) `Key' block "
+ "within `URL' block `%s'.", db->url);
+ status = -1;
+ }
+ if (status == 0)
+ status = couchdb_init_curl (db);
+ }
+
+ /* If all went well, register this database for reading */
+ if (status == 0)
+ {
+ user_data_t ud;
+ char cb_name[DATA_MAX_NAME_LEN];
+
+ if (db->instance == NULL)
+ db->instance = strdup("default");
+
+ DEBUG ("couchdb plugin: Registering new read callback: %s",
+ db->instance);
+
+ memset (&ud, 0, sizeof (ud));
+ ud.data = (void *) db;
+ ud.free_func = couchdb_free;
+
+ ssnprintf (cb_name, sizeof (cb_name), "couchdb-%s-%s",
+ db->instance, db->url);
+
+ plugin_register_complex_read (cb_name, couchdb_read,
+ /* interval = */ NULL, &ud);
+ }
+ else
+ {
+ couchdb_free (db);
+ return (-1);
+ }
+
+ return (0);
+}
+ /* }}} int couchdb_config_add_database */
+
+static int couchdb_config (oconfig_item_t *ci) /* {{{ */
+{
+ int success;
+ int errors;
+ int status;
+ int i;
+
+ success = 0;
+ errors = 0;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("URL", child->key) == 0)
+ {
+ status = couchdb_config_add_url (child);
+ if (status == 0)
+ success++;
+ else
+ errors++;
+ }
+ else
+ {
+ WARNING ("couchdb plugin: Option `%s' not allowed here.", child->key);
+ errors++;
+ }
+ }
+
+ if ((success == 0) && (errors > 0))
+ {
+ ERROR ("couchdb plugin: All statements failed.");
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int couchdb_config */
+
+/* }}} End of configuration handling functions */
+
+static void couchdb_submit (couchdb_t *db, couchdb_key_t *key, value_t *value) /* {{{ */
+{
+ value_list_t vl = VALUE_LIST_INIT;
+ char *host;
+
+ vl.values = value;
+ vl.values_len = 1;
+
+ if ((db->host == NULL)
+ || (strcmp ("", db->host) == 0)
+ || (strcmp (COUCHDB_DEFAULT_HOST, db->host) == 0))
+ host = hostname_g;
+ else
+ host = db->host;
+
+ if (key->instance == NULL)
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s",
+ db->state[db->depth-1].name, db->state[db->depth].name);
+ else
+ sstrncpy (vl.type_instance, key->instance, sizeof (vl.type_instance));
+
+ sstrncpy (vl.host, host, sizeof (vl.host));
+ sstrncpy (vl.plugin, "couchdb", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, db->instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, key->type, sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+} /* }}} int couchdb_submit */
+
+static int couchdb_curl_perform (couchdb_t *db, CURL *curl) /* {{{ */
+{
+ int status;
+ long rc;
+ char *url;
+ yajl_handle yprev = db->yajl;
+
+ db->yajl = yajl_alloc (&ycallbacks, NULL, NULL, (void *)db);
+ if (db->yajl == NULL)
+ {
+ ERROR ("couchdb plugin: yajl_alloc failed.");
+ return (-1);
+ }
+
+ status = curl_easy_perform (curl);
+
+ yajl_free (db->yajl);
+ db->yajl = yprev;
+
+ curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
+
+ if (rc != 200)
+ {
+ ERROR ("couchdb plugin: curl_easy_perform failed with response code %ld (%s)",
+ rc, url);
+ return (-1);
+ }
+
+ if (status != 0)
+ {
+ ERROR ("couchdb plugin: curl_easy_perform failed with status %i: %s (%s)",
+ status, db->curl_errbuf, url);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int couchdb_curl_perform */
+
+static int couchdb_read (user_data_t *ud) /* {{{ */
+{
+ couchdb_t *db;
+
+ if ((ud == NULL) || (ud->data == NULL))
+ {
+ ERROR ("couchdb plugin: couchdb_read: Invalid user data.");
+ return (-1);
+ }
+
+ db = (couchdb_t *) ud->data;
+
+ db->depth = 0;
+ memset (&db->state, 0, sizeof(db->state));
+ db->state[db->depth].tree = db->tree;
+ db->key = NULL;
+
+ return couchdb_curl_perform (db, db->curl);
+} /* }}} int couchdb_read */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("couchdb", couchdb_config);
+} /* void module_register */
for (i = 0; i < ds->ds_num; i++)
{
if ((ds->ds[i].type != DS_TYPE_COUNTER)
- && (ds->ds[i].type != DS_TYPE_GAUGE))
+ && (ds->ds[i].type != DS_TYPE_GAUGE)
+ && (ds->ds[i].type != DS_TYPE_DERIVE)
+ && (ds->ds[i].type != DS_TYPE_ABSOLUTE))
return (-1);
- if (ds->ds[i].type == DS_TYPE_COUNTER)
+ if (ds->ds[i].type == DS_TYPE_GAUGE)
{
- if (store_rates == 0)
- {
- status = ssnprintf (buffer + offset,
- buffer_len - offset,
- ",%llu",
- vl->values[i].counter);
- }
- else /* if (store_rates == 1) */
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ",%lf", vl->values[i].gauge);
+ }
+ else if (store_rates != 0)
+ {
+ if (rates == NULL)
+ rates = uc_get_rate (ds, vl);
+ if (rates == NULL)
{
- if (rates == NULL)
- rates = uc_get_rate (ds, vl);
- if (rates == NULL)
- {
- WARNING ("csv plugin: "
- "uc_get_rate failed.");
- return (-1);
- }
- status = ssnprintf (buffer + offset,
- buffer_len - offset,
- ",%lf", rates[i]);
+ WARNING ("csv plugin: "
+ "uc_get_rate failed.");
+ return (-1);
}
+ status = ssnprintf (buffer + offset,
+ buffer_len - offset,
+ ",%lf", rates[i]);
}
- else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
+ else if (ds->ds[i].type == DS_TYPE_COUNTER)
{
- status = ssnprintf (buffer + offset, buffer_len - offset,
- ",%lf", vl->values[i].gauge);
+ status = ssnprintf (buffer + offset,
+ buffer_len - offset,
+ ",%llu",
+ vl->values[i].counter);
+ }
+ else if (ds->ds[i].type == DS_TYPE_DERIVE)
+ {
+ status = ssnprintf (buffer + offset,
+ buffer_len - offset,
+ ",%"PRIi64,
+ vl->values[i].derive);
+ }
+ else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+ {
+ status = ssnprintf (buffer + offset,
+ buffer_len - offset,
+ ",%"PRIu64,
+ vl->values[i].absolute);
}
if ((status < 1) || (status >= (buffer_len - offset)))
else
dstype = 0;
}
+else if (strncasecmp ("Derive", ci->values[0].value.string,
+ strlen ("Derive")) == 0)
+ {
+ dstype = UTILS_MATCH_DS_TYPE_DERIVE;
+ if (strcasecmp ("DeriveSet", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_DERIVE_SET;
+ else if (strcasecmp ("DeriveAdd", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_DERIVE_ADD;
+ else if (strcasecmp ("DeriveInc", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_DERIVE_INC;
+ else
+ dstype = 0;
+ }
+else if (strncasecmp ("Absolute", ci->values[0].value.string,
+ strlen ("Absolute")) == 0)
+ {
+ dstype = UTILS_MATCH_DS_TYPE_ABSOLUTE;
+ if (strcasecmp ("AbsoluteSet", ci->values[0].value.string) == 0) /* Absolute DS is reset-on-read so no sense doin anything else but set */
+ dstype |= UTILS_MATCH_CF_ABSOLUTE_SET;
+ else
+ dstype = 0;
+ }
+
else
{
dstype = 0;
{
"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;
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);
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
{
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. */
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;
}
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);
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 */
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);
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);
*/
#define LCC_TYPE_COUNTER 0
#define LCC_TYPE_GAUGE 1
+#define LCC_TYPE_DERIVE 2
+#define LCC_TYPE_ABSOLUTE 3
LCC_BEGIN_DECLS
typedef uint64_t counter_t;
typedef double gauge_t;
+typedef uint64_t derive_t;
+typedef uint64_t absolute_t;
union value_u
{
counter_t counter;
gauge_t gauge;
+ derive_t derive;
+ absolute_t absolute;
};
typedef union value_u value_t;
/**
* collectd - src/meta_data.c
- * Copyright (C) 2008 Florian octo Forster
+ * Copyright (C) 2008,2009 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
#define MD_TYPE_SIGNED_INT 2
#define MD_TYPE_UNSIGNED_INT 3
#define MD_TYPE_DOUBLE 4
+#define MD_TYPE_BOOLEAN 5
/*
* Data types
int64_t mv_signed_int;
uint64_t mv_unsigned_int;
double mv_double;
+ _Bool mv_boolean;
};
typedef union meta_value_u meta_value_t;
return (0);
} /* }}} int meta_data_delete */
+/*
+ * Add functions
+ */
int meta_data_add_string (meta_data_t *md, /* {{{ */
const char *key, const char *value)
{
return (md_entry_insert (md, e));
} /* }}} int meta_data_add_double */
+int meta_data_add_boolean (meta_data_t *md, /* {{{ */
+ const char *key, _Bool value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL))
+ return (-EINVAL);
+
+ e = md_entry_alloc (key);
+ if (e == NULL)
+ return (-ENOMEM);
+
+ e->value.mv_boolean = value;
+ e->type = MD_TYPE_BOOLEAN;
+
+ return (md_entry_insert (md, e));
+} /* }}} int meta_data_add_boolean */
+
+/*
+ * Get functions
+ */
int meta_data_get_string (meta_data_t *md, /* {{{ */
const char *key, char **value)
{
return (0);
} /* }}} int meta_data_get_double */
+int meta_data_get_boolean (meta_data_t *md, /* {{{ */
+ const char *key, _Bool *value)
+{
+ meta_entry_t *e;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ if (e->type != MD_TYPE_BOOLEAN)
+ {
+ ERROR ("meta_data_get_boolean: Type mismatch for key `%s'", e->key);
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ *value = e->value.mv_boolean;
+
+ pthread_mutex_unlock (&md->lock);
+ return (0);
+} /* }}} int meta_data_get_boolean */
+
/* vim: set sw=2 sts=2 et fdm=marker : */
/**
* collectd - src/meta_data.h
- * Copyright (C) 2008 Florian octo Forster
+ * Copyright (C) 2008,2009 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
int meta_data_add_double (meta_data_t *md,
const char *key,
double value);
+int meta_data_add_boolean (meta_data_t *md,
+ const char *key,
+ _Bool value);
int meta_data_get_string (meta_data_t *md,
const char *key,
int meta_data_get_double (meta_data_t *md,
const char *key,
double *value);
+int meta_data_get_boolean (meta_data_t *md,
+ const char *key,
+ _Bool *value);
#endif /* META_DATA_H */
/* vim: set sw=2 sts=2 et : */
for (i = 0; i < num_values; i++)
{
- if (ds->ds[i].type == DS_TYPE_COUNTER)
+ pkg_values_types[i] = (uint8_t) ds->ds[i].type;
+ switch (ds->ds[i].type)
{
- pkg_values_types[i] = DS_TYPE_COUNTER;
- pkg_values[i].counter = htonll (vl->values[i].counter);
- }
- else
- {
- pkg_values_types[i] = DS_TYPE_GAUGE;
- pkg_values[i].gauge = htond (vl->values[i].gauge);
- }
- }
+ case DS_TYPE_COUNTER:
+ pkg_values[i].counter = htonll (vl->values[i].counter);
+ break;
+
+ case DS_TYPE_GAUGE:
+ pkg_values[i].gauge = htond (vl->values[i].gauge);
+ break;
+
+ case DS_TYPE_DERIVE:
+ pkg_values[i].derive = htonll (vl->values[i].derive);
+ break;
+
+ case DS_TYPE_ABSOLUTE:
+ pkg_values[i].absolute = htonll (vl->values[i].absolute);
+ break;
+
+ default:
+ free (pkg_values_types);
+ free (pkg_values);
+ ERROR ("network plugin: write_part_values: "
+ "Unknown data source type: %i",
+ ds->ds[i].type);
+ return (-1);
+ } /* switch (ds->ds[i].type) */
+ } /* for (num_values) */
/*
* Use `memcpy' to write everything to the buffer, because the pointer
for (i = 0; i < pkg_numval; i++)
{
- if (pkg_types[i] == DS_TYPE_COUNTER)
- pkg_values[i].counter = ntohll (pkg_values[i].counter);
- else if (pkg_types[i] == DS_TYPE_GAUGE)
- pkg_values[i].gauge = ntohd (pkg_values[i].gauge);
+ switch (pkg_types[i])
+ {
+ case DS_TYPE_COUNTER:
+ pkg_values[i].counter = (counter_t) ntohll (pkg_values[i].counter);
+ break;
+
+ case DS_TYPE_GAUGE:
+ pkg_values[i].gauge = (gauge_t) ntohd (pkg_values[i].gauge);
+ break;
+
+ case DS_TYPE_DERIVE:
+ pkg_values[i].derive = (derive_t) ntohll (pkg_values[i].derive);
+ break;
+
+ case DS_TYPE_ABSOLUTE:
+ pkg_values[i].absolute = (absolute_t) ntohll (pkg_values[i].absolute);
+ break;
+
+ default:
+ sfree (pkg_types);
+ sfree (pkg_values);
+ NOTICE ("network plugin: parse_part_values: "
+ "Don't know how to handle data source type %"PRIu8,
+ pkg_types[i]);
+ return (-1);
+ } /* switch (pkg_types[i]) */
}
*ret_buffer = buffer;
--- /dev/null
+/**
+ * collectd - src/olsrd.c
+ * Copyright (C) 2009 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#define OLSRD_DEFAULT_NODE "localhost"
+#define OLSRD_DEFAULT_SERVICE "2006"
+
+static const char *config_keys[] =
+{
+ "Host",
+ "Port",
+ "CollectLinks",
+ "CollectRoutes",
+ "CollectTopology"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char *config_node = NULL;
+static char *config_service = NULL;
+
+#define OLSRD_WANT_NOT 0
+#define OLSRD_WANT_SUMMARY 1
+#define OLSRD_WANT_DETAIL 2
+static int config_want_links = OLSRD_WANT_DETAIL;
+static int config_want_routes = OLSRD_WANT_SUMMARY;
+static int config_want_topology = OLSRD_WANT_SUMMARY;
+
+static const char *olsrd_get_node (void) /* {{{ */
+{
+ if (config_node != NULL)
+ return (config_node);
+ return (OLSRD_DEFAULT_NODE);
+} /* }}} const char *olsrd_get_node */
+
+static const char *olsrd_get_service (void) /* {{{ */
+{
+ if (config_service != NULL)
+ return (config_service);
+ return (OLSRD_DEFAULT_SERVICE);
+} /* }}} const char *olsrd_get_service */
+
+static void olsrd_set_node (const char *node) /* {{{ */
+{
+ char *tmp;
+ if (node == NULL)
+ return;
+ tmp = strdup (node);
+ if (tmp == NULL)
+ return;
+ config_node = tmp;
+} /* }}} void olsrd_set_node */
+
+static void olsrd_set_service (const char *service) /* {{{ */
+{
+ char *tmp;
+ if (service == NULL)
+ return;
+ tmp = strdup (service);
+ if (tmp == NULL)
+ return;
+ config_service = tmp;
+} /* }}} void olsrd_set_service */
+
+static void olsrd_set_detail (int *varptr, const char *detail, /* {{{ */
+ const char *key)
+{
+ if (strcasecmp ("No", detail) == 0)
+ *varptr = OLSRD_WANT_NOT;
+ else if (strcasecmp ("Summary", detail) == 0)
+ *varptr = OLSRD_WANT_SUMMARY;
+ else if (strcasecmp ("Detail", detail) == 0)
+ *varptr = OLSRD_WANT_DETAIL;
+ else
+ {
+ ERROR ("olsrd plugin: Invalid argument given to the `%s' configuration "
+ "option: `%s'. Expected: `No', `Summary', or `Detail'.",
+ key, detail);
+ }
+} /* }}} void olsrd_set_detail */
+
+/* Strip trailing newline characters. Returns length of string. */
+static size_t strchomp (char *buffer) /* {{{ */
+{
+ size_t buffer_len;
+
+ buffer_len = strlen (buffer);
+ while ((buffer_len > 0)
+ && ((buffer[buffer_len - 1] == '\r')
+ || (buffer[buffer_len - 1] == '\n')))
+ {
+ buffer_len--;
+ buffer[buffer_len] = 0;
+ }
+
+ return (buffer_len);
+} /* }}} size_t strchomp */
+
+static size_t strtabsplit (char *string, char **fields, size_t size) /* {{{ */
+{
+ size_t i;
+ char *ptr;
+ char *saveptr;
+
+ i = 0;
+ ptr = string;
+ saveptr = NULL;
+ while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL)
+ {
+ ptr = NULL;
+ i++;
+
+ if (i >= size)
+ break;
+ }
+
+ return (i);
+} /* }}} size_t strtabsplit */
+
+static FILE *olsrd_connect (void) /* {{{ */
+{
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_list, *ai_ptr;
+ int ai_return;
+
+ FILE *fh;
+
+ memset (&ai_hints, 0, sizeof (ai_hints));
+ ai_hints.ai_flags = 0;
+#ifdef AI_ADDRCONFIG
+ ai_hints.ai_flags |= AI_ADDRCONFIG;
+#endif
+ ai_hints.ai_family = PF_UNSPEC;
+ ai_hints.ai_socktype = SOCK_STREAM;
+ ai_hints.ai_protocol = IPPROTO_TCP;
+
+ ai_list = NULL;
+ ai_return = getaddrinfo (olsrd_get_node (), olsrd_get_service (),
+ &ai_hints, &ai_list);
+ if (ai_return != 0)
+ {
+ ERROR ("olsrd plugin: getaddrinfo (%s, %s) failed: %s",
+ olsrd_get_node (), olsrd_get_service (),
+ gai_strerror (ai_return));
+ return (NULL);
+ }
+
+ fh = NULL;
+ for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+ {
+ int fd;
+ int status;
+ char errbuf[1024];
+
+ fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+ if (fd < 0)
+ {
+ ERROR ("olsrd plugin: socket failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ continue;
+ }
+
+ status = connect (fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ if (status != 0)
+ {
+ ERROR ("olsrd plugin: connect failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ close (fd);
+ continue;
+ }
+
+ fh = fdopen (fd, "r+");
+ if (fh == NULL)
+ {
+ ERROR ("olsrd plugin: fdopen failed.");
+ close (fd);
+ continue;
+ }
+
+ break;
+ } /* for (ai_ptr) */
+
+ freeaddrinfo (ai_list);
+
+ return (fh);
+} /* }}} FILE *olsrd_connect */
+
+__attribute__ ((nonnull(2)))
+static void olsrd_submit (const char *plugin_instance, /* {{{ */
+ const char *type, const char *type_instance, gauge_t value)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "olsrd", sizeof (vl.plugin));
+ if (plugin_instance != NULL)
+ sstrncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_instance != NULL)
+ sstrncpy (vl.type_instance, type_instance,
+ sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* }}} void olsrd_submit */
+
+static int olsrd_cb_ignore (int lineno, /* {{{ */
+ size_t fields_num, char **fields)
+{
+ return (0);
+} /* }}} int olsrd_cb_ignore */
+
+static int olsrd_cb_links (int lineno, /* {{{ */
+ size_t fields_num, char **fields)
+{
+ /* Fields:
+ * 0 = Local IP
+ * 1 = Remote IP
+ * 2 = Hyst.
+ * 3 = LQ
+ * 4 = NLQ
+ * 5 = Cost */
+
+ static uint32_t links_num;
+ static double lq_sum;
+ static uint32_t lq_num;
+ static double nlq_sum;
+ static uint32_t nlq_num;
+
+ double lq;
+ double nlq;
+
+ char *endptr;
+
+ if (config_want_links == OLSRD_WANT_NOT)
+ return (0);
+
+ /* Special handling of the first line. */
+ if (lineno <= 0)
+ {
+ links_num = 0;
+ lq_sum = 0.0;
+ lq_num = 0;
+ nlq_sum = 0.0;
+ nlq_num = 0;
+
+ return (0);
+ }
+
+ /* Special handling of the last line. */
+ if (fields_num == 0)
+ {
+ DEBUG ("olsrd plugin: Number of links: %"PRIu32, links_num);
+ olsrd_submit (/* p.-inst = */ "links", /* type = */ "links",
+ /* t.-inst = */ NULL, (gauge_t) links_num);
+
+ lq = NAN;
+ if (lq_num > 0)
+ lq = lq_sum / ((double) lq_num);
+ DEBUG ("olsrd plugin: Average LQ: %g", lq);
+ olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
+ "average-lq", lq);
+
+ nlq = NAN;
+ if (nlq_num > 0)
+ nlq = nlq_sum / ((double) nlq_num);
+ DEBUG ("olsrd plugin: Average NLQ: %g", nlq);
+ olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
+ "average-nlq", nlq);
+
+ return (0);
+ }
+
+ if (fields_num != 6)
+ return (-1);
+
+ links_num++;
+
+ errno = 0;
+ endptr = NULL;
+ lq = strtod (fields[3], &endptr);
+ if ((errno != 0) || (endptr == fields[3]))
+ {
+ ERROR ("olsrd plugin: Cannot parse link quality: %s", fields[3]);
+ }
+ else
+ {
+ if (!isnan (lq))
+ {
+ lq_sum += lq;
+ lq_num++;
+ }
+
+ if (config_want_links == OLSRD_WANT_DETAIL)
+ {
+ char type_instance[DATA_MAX_NAME_LEN];
+
+ ssnprintf (type_instance, sizeof (type_instance), "%s-%s-lq",
+ fields[0], fields[1]);
+
+ DEBUG ("olsrd plugin: links: type_instance = %s; lq = %g;",
+ type_instance, lq);
+ olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
+ type_instance, lq);
+ }
+ }
+
+ errno = 0;
+ endptr = NULL;
+ nlq = strtod (fields[4], &endptr);
+ if ((errno != 0) || (endptr == fields[4]))
+ {
+ ERROR ("olsrd plugin: Cannot parse neighbor link quality: %s", fields[4]);
+ }
+ else
+ {
+ if (!isnan (nlq))
+ {
+ nlq_sum += nlq;
+ nlq_num++;
+ }
+
+ if (config_want_links == OLSRD_WANT_DETAIL)
+ {
+ char type_instance[DATA_MAX_NAME_LEN];
+
+ ssnprintf (type_instance, sizeof (type_instance), "%s-%s-rx",
+ fields[0], fields[1]);
+
+ DEBUG ("olsrd plugin: links: type_instance = %s; nlq = %g;",
+ type_instance, lq);
+ olsrd_submit (/* p.-inst = */ "links", /* type = */ "signal_quality",
+ type_instance, nlq);
+ }
+ }
+
+ return (0);
+} /* }}} int olsrd_cb_links */
+
+static int olsrd_cb_routes (int lineno, /* {{{ */
+ size_t fields_num, char **fields)
+{
+ /* Fields:
+ * 0 = Destination
+ * 1 = Gateway IP
+ * 2 = Metric
+ * 3 = ETX
+ * 4 = Interface */
+
+ static uint32_t routes_num;
+ static uint32_t metric_sum;
+ static uint32_t metric_num;
+ static double etx_sum;
+ static uint32_t etx_num;
+
+ uint32_t metric;
+ double etx;
+ char *endptr;
+
+ if (config_want_routes == OLSRD_WANT_NOT)
+ return (0);
+
+ /* Special handling of the first line */
+ if (lineno <= 0)
+ {
+ routes_num = 0;
+ metric_num = 0;
+ metric_sum = 0;
+ etx_sum = 0.0;
+ etx_num = 0;
+
+ return (0);
+ }
+
+ /* Special handling after the last line */
+ if (fields_num == 0)
+ {
+ double metric_avg;
+
+ DEBUG ("olsrd plugin: Number of routes: %"PRIu32, routes_num);
+ olsrd_submit (/* p.-inst = */ "routes", /* type = */ "routes",
+ /* t.-inst = */ NULL, (gauge_t) routes_num);
+
+ metric_avg = NAN;
+ if (metric_num > 0)
+ metric_avg = ((double) metric_sum) / ((double) metric_num);
+ DEBUG ("olsrd plugin: Average metric: %g", metric_avg);
+ olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_metric",
+ "average", metric_avg);
+
+ etx = NAN;
+ if (etx_num > 0)
+ etx = etx_sum / ((double) etx_sum);
+ DEBUG ("olsrd plugin: Average ETX: %g", etx);
+ olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_etx",
+ "average", etx);
+
+ return (0);
+ }
+
+ if (fields_num != 5)
+ return (-1);
+
+ routes_num++;
+
+ errno = 0;
+ endptr = NULL;
+ metric = (uint32_t) strtoul (fields[2], &endptr, 0);
+ if ((errno != 0) || (endptr == fields[2]))
+ {
+ ERROR ("olsrd plugin: Unable to parse metric: %s", fields[2]);
+ }
+ else
+ {
+ metric_num++;
+ metric_sum += metric;
+
+ if (config_want_routes == OLSRD_WANT_DETAIL)
+ {
+ DEBUG ("olsrd plugin: destination = %s; metric = %"PRIu32";",
+ fields[0], metric);
+ olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_metric",
+ /* t.-inst = */ fields[0], (gauge_t) metric);
+ }
+ }
+
+ errno = 0;
+ endptr = NULL;
+ etx = strtod (fields[3], &endptr);
+ if ((errno != 0) || (endptr == fields[3]))
+ {
+ ERROR ("olsrd plugin: Unable to parse ETX: %s", fields[3]);
+ }
+ else
+ {
+ if (!isnan (etx))
+ {
+ etx_sum += etx;
+ etx_num++;
+ }
+
+ if (config_want_routes == OLSRD_WANT_DETAIL)
+ {
+ DEBUG ("olsrd plugin: destination = %s; etx = %g;",
+ fields[0], etx);
+ olsrd_submit (/* p.-inst = */ "routes", /* type = */ "route_etx",
+ /* t.-inst = */ fields[0], etx);
+ }
+ }
+
+ return (0);
+} /* }}} int olsrd_cb_routes */
+
+static int olsrd_cb_topology (int lineno, /* {{{ */
+ size_t fields_num, char **fields)
+{
+ /* Fields:
+ * 0 = Dest. IP
+ * 1 = Last hop IP
+ * 2 = LQ
+ * 3 = NLQ
+ * 4 = Cost */
+
+ static double lq_sum;
+ static uint32_t lq_num;
+
+ static uint32_t links_num;
+
+ double lq;
+ char *endptr;
+
+ if (config_want_topology == OLSRD_WANT_NOT)
+ return (0);
+
+ /* Special handling of the first line */
+ if (lineno <= 0)
+ {
+ lq_sum = 0.0;
+ lq_num = 0;
+ links_num = 0;
+
+ return (0);
+ }
+
+ /* Special handling after the last line */
+ if (fields_num == 0)
+ {
+ DEBUG ("olsrd plugin: topology: Number of links: %"PRIu32, links_num);
+ olsrd_submit (/* p.-inst = */ "topology", /* type = */ "links",
+ /* t.-inst = */ NULL, (gauge_t) links_num);
+
+ lq = NAN;
+ if (lq_num > 0)
+ lq = lq_sum / ((double) lq_sum);
+ DEBUG ("olsrd plugin: topology: Average link quality: %g", lq);
+ olsrd_submit (/* p.-inst = */ "topology", /* type = */ "signal_quality",
+ /* t.-inst = */ "average", lq);
+
+ return (0);
+ }
+
+ if (fields_num != 5)
+ return (-1);
+
+ links_num++;
+
+ errno = 0;
+ endptr = NULL;
+ lq = strtod (fields[2], &endptr);
+ if ((errno != 0) || (endptr == fields[2]))
+ {
+ ERROR ("olsrd plugin: Unable to parse LQ: %s", fields[2]);
+ }
+ else
+ {
+ if (!isnan (lq))
+ {
+ lq_sum += lq;
+ lq_num++;
+ }
+
+ if (config_want_topology == OLSRD_WANT_DETAIL)
+ {
+ char type_instance[DATA_MAX_NAME_LEN];
+
+ memset (type_instance, 0, sizeof (type_instance));
+ ssnprintf (type_instance, sizeof (type_instance), "%s-%s-lq",
+ fields[0], fields[1]);
+ DEBUG ("olsrd plugin: type_instance = %s; lq = %g;", type_instance, lq);
+ olsrd_submit (/* p.-inst = */ "topology", /* type = */ "signal_quality",
+ type_instance, lq);
+ }
+ }
+
+ if (config_want_topology == OLSRD_WANT_DETAIL)
+ {
+ double nlq;
+
+ errno = 0;
+ endptr = NULL;
+ nlq = strtod (fields[3], &endptr);
+ if ((errno != 0) || (endptr == fields[3]))
+ {
+ ERROR ("olsrd plugin: Unable to parse NLQ: %s", fields[3]);
+ }
+ else
+ {
+ char type_instance[DATA_MAX_NAME_LEN];
+
+ memset (type_instance, 0, sizeof (type_instance));
+ ssnprintf (type_instance, sizeof (type_instance), "%s-%s-nlq",
+ fields[0], fields[1]);
+ DEBUG ("olsrd plugin: type_instance = %s; nlq = %g;", type_instance, nlq);
+ olsrd_submit (/* p.-inst = */ "topology", /* type = */ "signal_quality",
+ type_instance, nlq);
+ }
+ }
+
+ return (0);
+} /* }}} int olsrd_cb_topology */
+
+static int olsrd_read_table (FILE *fh, /* {{{ */
+ int (*callback) (int lineno, size_t fields_num, char **fields))
+{
+ char buffer[1024];
+ size_t buffer_len;
+
+ char *fields[32];
+ size_t fields_num;
+
+ int lineno;
+
+ lineno = 0;
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
+ {
+ /* An empty line ends the table. */
+ buffer_len = strchomp (buffer);
+ if (buffer_len <= 0)
+ {
+ (*callback) (lineno, /* fields_num = */ 0, /* fields = */ NULL);
+ break;
+ }
+
+ fields_num = strtabsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
+
+ (*callback) (lineno, fields_num, fields);
+ lineno++;
+ } /* while (fgets) */
+
+ return (0);
+} /* }}} int olsrd_read_table */
+
+static int olsrd_config (const char *key, const char *value) /* {{{ */
+{
+ if (strcasecmp ("Host", key) == 0)
+ olsrd_set_node (value);
+ else if (strcasecmp ("Port", key) == 0)
+ olsrd_set_service (value);
+ else if (strcasecmp ("CollectLinks", key) == 0)
+ olsrd_set_detail (&config_want_links, value, key);
+ else if (strcasecmp ("CollectRoutes", key) == 0)
+ olsrd_set_detail (&config_want_routes, value, key);
+ else if (strcasecmp ("CollectTopology", key) == 0)
+ olsrd_set_detail (&config_want_topology, value, key);
+ else
+ {
+ ERROR ("olsrd plugin: Unknown configuration option given: %s", key);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int olsrd_config */
+
+static int olsrd_read (void) /* {{{ */
+{
+ FILE *fh;
+ char buffer[1024];
+ size_t buffer_len;
+
+ fh = olsrd_connect ();
+ if (fh == NULL)
+ return (-1);
+
+ fputs ("\r\n", fh);
+ fflush (fh);
+
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
+ {
+ buffer_len = strchomp (buffer);
+ if (buffer_len <= 0)
+ continue;
+
+ if (strcmp ("Table: Links", buffer) == 0)
+ olsrd_read_table (fh, olsrd_cb_links);
+ else if (strcmp ("Table: Neighbors", buffer) == 0)
+ olsrd_read_table (fh, olsrd_cb_ignore);
+ else if (strcmp ("Table: Topology", buffer) == 0)
+ olsrd_read_table (fh, olsrd_cb_topology);
+ else if (strcmp ("Table: HNA", buffer) == 0)
+ olsrd_read_table (fh, olsrd_cb_ignore);
+ else if (strcmp ("Table: MID", buffer) == 0)
+ olsrd_read_table (fh, olsrd_cb_ignore);
+ else if (strcmp ("Table: Routes", buffer) == 0)
+ olsrd_read_table (fh, olsrd_cb_routes);
+ else if ((strcmp ("HTTP/1.0 200 OK", buffer) == 0)
+ || (strcmp ("Content-type: text/plain", buffer) == 0))
+ {
+ /* ignore */
+ }
+ else
+ {
+ DEBUG ("olsrd plugin: Unable to handle line: %s", buffer);
+ }
+ } /* while (fgets) */
+
+ fclose (fh);
+
+ return (0);
+} /* }}} int olsrd_read */
+
+static int olsrd_shutdown (void) /* {{{ */
+{
+ sfree (config_node);
+ sfree (config_service);
+
+ return (0);
+} /* }}} int olsrd_shutdown */
+
+void module_register (void)
+{
+ plugin_register_config ("olsrd", olsrd_config,
+ config_keys, config_keys_num);
+ plugin_register_read ("olsrd", olsrd_read);
+ plugin_register_shutdown ("olsrd", olsrd_shutdown);
+} /* void module_register */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
{ "Collectd::TYPE_DATASET", PLUGIN_DATASET },
{ "Collectd::DS_TYPE_COUNTER", DS_TYPE_COUNTER },
{ "Collectd::DS_TYPE_GAUGE", DS_TYPE_GAUGE },
+ { "Collectd::DS_TYPE_DERIVE", DS_TYPE_DERIVE },
+ { "Collectd::DS_TYPE_ABSOLUTE", DS_TYPE_ABSOLUTE },
{ "Collectd::LOG_ERR", LOG_ERR },
{ "Collectd::LOG_WARNING", LOG_WARNING },
{ "Collectd::LOG_NOTICE", LOG_NOTICE },
if (NULL != (tmp = hv_fetch (hash, "type", 4, 0))) {
ds->type = SvIV (*tmp);
- if ((DS_TYPE_COUNTER != ds->type) && (DS_TYPE_GAUGE != ds->type)) {
+ if ((DS_TYPE_COUNTER != ds->type)
+ && (DS_TYPE_GAUGE != ds->type)
+ && (DS_TYPE_DERIVE != ds->type)
+ && (DS_TYPE_ABSOLUTE != ds->type)) {
log_err ("hv2data_source: Invalid DS type.");
return -1;
}
if (NULL != tmp) {
if (DS_TYPE_COUNTER == ds->ds[i].type)
value[i].counter = SvIV (*tmp);
- else
+ else if (DS_TYPE_GAUGE == ds->ds[i].type)
value[i].gauge = SvNV (*tmp);
+ else if (DS_TYPE_DERIVE == ds->ds[i].type)
+ value[i].derive = SvIV (*tmp);
+ else if (DS_TYPE_ABSOLUTE == ds->ds[i].type)
+ value[i].absolute = SvIV (*tmp);
}
else {
return -1;
if (DS_TYPE_COUNTER == ds->ds[i].type)
val = newSViv (vl->values[i].counter);
- else
+ else if (DS_TYPE_GAUGE == ds->ds[i].type)
val = newSVnv (vl->values[i].gauge);
+ else if (DS_TYPE_DERIVE == ds->ds[i].type)
+ val = newSViv (vl->values[i].derive);
+ else if (DS_TYPE_ABSOLUTE == ds->ds[i].type)
+ val = newSViv (vl->values[i].absolute);
if (NULL == av_store (values, i, val)) {
av_undef (values);
data_set_t *ds;
+ int free_meta_data = 0;
+
if ((vl == NULL) || (vl->type[0] == 0)
|| (vl->values == NULL) || (vl->values_len < 1))
{
return (-1);
}
+ /* Free meta data only if the calling function didn't specify any. In
+ * this case matches and targets may add some and the calling function
+ * may not expect (and therefore free) that data. */
+ if (vl->meta == NULL)
+ free_meta_data = 1;
+
if (list_write == NULL)
c_complain_once (LOG_WARNING, &no_write_complaint,
"plugin_dispatch_values: No write callback has been "
vl->values_len = saved_values_len;
}
+ if ((free_meta_data != 0) && (vl->meta != NULL))
+ {
+ meta_data_destroy (vl->meta);
+ vl->meta = NULL;
+ }
+
return (0);
} /* int plugin_dispatch_values */
#include "collectd.h"
#include "configfile.h"
+#include "meta_data.h"
#define DATA_MAX_NAME_LEN 64
-#define DS_TYPE_COUNTER 0
-#define DS_TYPE_GAUGE 1
+#define DS_TYPE_COUNTER 0
+#define DS_TYPE_GAUGE 1
+#define DS_TYPE_DERIVE 2
+#define DS_TYPE_ABSOLUTE 3
+
+#define DS_TYPE_TO_STRING(t) (t == DS_TYPE_COUNTER) ? "counter" : \
+ (t == DS_TYPE_GAUGE) ? "gauge" : \
+ (t == DS_TYPE_DERIVE) ? "derive" : \
+ (t == DS_TYPE_ABSOLUTE) ? "absolute" : \
+ "unknown"
+
#ifndef LOG_ERR
# define LOG_ERR 3
*/
typedef unsigned long long counter_t;
typedef double gauge_t;
+typedef int64_t derive_t;
+typedef uint64_t absolute_t;
union value_u
{
- counter_t counter;
- gauge_t gauge;
+ counter_t counter;
+ gauge_t gauge;
+ derive_t derive;
+ absolute_t absolute;
};
typedef union value_u value_t;
char plugin_instance[DATA_MAX_NAME_LEN];
char type[DATA_MAX_NAME_LEN];
char type_instance[DATA_MAX_NAME_LEN];
+ meta_data_t *meta;
};
typedef struct value_list_s value_list_t;
-#define VALUE_LIST_INIT { NULL, 0, 0, interval_g, "localhost", "", "", "", "" }
-#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "", "" }
+#define VALUE_LIST_INIT { NULL, 0, 0, interval_g, "localhost", "", "", "", "", NULL }
+#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "", "", NULL }
struct data_source_s
{
return;
}
- if (0 != parse_value (value, &values[0], ds->ds[0]))
+ if (0 != parse_value (value, &values[0], ds->ds[0].type))
{
ERROR ("powerdns plugin: Cannot convert `%s' "
"to a number.", value);
for (i = 0; i < ds->ds_num; i++)
{
if ((ds->ds[i].type != DS_TYPE_COUNTER)
- && (ds->ds[i].type != DS_TYPE_GAUGE))
+ && (ds->ds[i].type != DS_TYPE_GAUGE)
+ && (ds->ds[i].type != DS_TYPE_DERIVE)
+ && (ds->ds[i].type != DS_TYPE_ABSOLUTE))
return (-1);
if (ds->ds[i].type == DS_TYPE_COUNTER)
status = ssnprintf (buffer + offset, buffer_len - offset,
":%llu", vl->values[i].counter);
}
- else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
{
status = ssnprintf (buffer + offset, buffer_len - offset,
- ":%lf", vl->values[i].gauge);
+ ":%f", vl->values[i].gauge);
+ }
+ else if (ds->ds[i].type == DS_TYPE_DERIVE) {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%"PRIi64, vl->values[i].derive);
+ }
+ else /* if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ {
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%"PRIu64, vl->values[i].absolute);
+
}
if ((status < 1) || (status >= (buffer_len - offset)))
for (i = 0; i < ds->ds_num; i++)
{
if ((ds->ds[i].type != DS_TYPE_COUNTER)
- && (ds->ds[i].type != DS_TYPE_GAUGE))
+ && (ds->ds[i].type != DS_TYPE_GAUGE)
+ && (ds->ds[i].type != DS_TYPE_DERIVE)
+ && (ds->ds[i].type != DS_TYPE_ABSOLUTE))
return (-1);
if (ds->ds[i].type == DS_TYPE_COUNTER)
status = ssnprintf (buffer + offset, buffer_len - offset,
":%llu", vl->values[i].counter);
- else
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
status = ssnprintf (buffer + offset, buffer_len - offset,
":%lf", vl->values[i].gauge);
+ else if (ds->ds[i].type == DS_TYPE_DERIVE)
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%"PRIi64, vl->values[i].derive);
+ else /*if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ ":%"PRIu64, vl->values[i].absolute);
if ((status < 1) || (status >= (buffer_len - offset)))
return (-1);
if (vl->type == ASN_OCTET_STR)
{
- char *endptr;
+ int status = -1;
- endptr = NULL;
if (vl->val.string != NULL)
{
char string[64];
string_length = vl->val_len;
/* The strings we get from the Net-SNMP library may not be null
- * terminated. That is why we're using `membpy' here and not `strcpy'.
+ * terminated. That is why we're using `memcpy' here and not `strcpy'.
* `string_length' is set to `vl->val_len' which holds the length of the
* string. -octo */
memcpy (string, vl->val.string, string_length);
string[string_length] = 0;
- if (type == DS_TYPE_COUNTER)
+ status = parse_value (string, &ret, type);
+ if (status != 0)
{
- ret.counter = (counter_t) strtoll (string, &endptr, /* base = */ 0);
- DEBUG ("snmp plugin: csnmp_value_list_to_value: String to counter: %s -> %llu",
- string, (unsigned long long) ret.counter);
- }
- else if (type == DS_TYPE_GAUGE)
- {
- ret.gauge = (gauge_t) strtod (string, &endptr);
- DEBUG ("snmp plugin: csnmp_value_list_to_value: String to gauge: %s -> %g",
- string, (double) ret.gauge);
+ ERROR ("snmp plugin: csnmp_value_list_to_value: Parsing string as %s failed: %s",
+ DS_TYPE_TO_STRING (type), string);
}
}
- /* Check if an error occurred */
- if ((vl->val.string == NULL) || (endptr == (char *) vl->val.string))
+ if (status != 0)
{
- if (type == DS_TYPE_COUNTER)
- ret.counter = 0;
- else if (type == DS_TYPE_GAUGE)
- ret.gauge = NAN;
+ switch (type)
+ {
+ case DS_TYPE_COUNTER:
+ case DS_TYPE_DERIVE:
+ case DS_TYPE_ABSOLUTE:
+ memset (&ret, 0, sizeof (ret));
+ break;
+
+ case DS_TYPE_GAUGE:
+ ret.gauge = NAN;
+ break;
+
+ default:
+ ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown "
+ "data source type: %i.", type);
+ ret.gauge = NAN;
+ }
}
- }
+ } /* if (vl->type == ASN_OCTET_STR) */
else if (type == DS_TYPE_COUNTER)
- {
ret.counter = temp;
- }
else if (type == DS_TYPE_GAUGE)
{
ret.gauge = NAN;
if (defined != 0)
ret.gauge = (scale * temp) + shift;
}
+ else if (type == DS_TYPE_DERIVE)
+ ret.derive = (derive_t) temp;
+ else if (type == DS_TYPE_ABSOLUTE)
+ ret.absolute = (absolute_t) temp;
+ else
+ {
+ ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown data source "
+ "type: %i.", type);
+ ret.gauge = NAN;
+ }
return (ret);
} /* value_t csnmp_value_list_to_value */
assert (res->values[i] < fields_num);
value = fields[res->values[i]];
- if (0 != parse_value (value, &values[i], res->ds->ds[i]))
+ if (0 != parse_value (value, &values[i], res->ds->ds[i].type))
return -1;
}
else
cm->flags = 0;
}
+ else if (strncasecmp ("Derive", ci->values[0].value.string, strlen ("Derive")) == 0)
+ {
+ cm->flags = UTILS_MATCH_DS_TYPE_DERIVE;
+ if (strcasecmp ("DeriveSet", ci->values[0].value.string) == 0)
+ cm->flags |= UTILS_MATCH_CF_DERIVE_SET;
+ else if (strcasecmp ("DeriveAdd", ci->values[0].value.string) == 0)
+ cm->flags |= UTILS_MATCH_CF_DERIVE_ADD;
+ else if (strcasecmp ("DeriveInc", ci->values[0].value.string) == 0)
+ cm->flags |= UTILS_MATCH_CF_DERIVE_INC;
+ else
+ cm->flags = 0;
+ }
+ else if (strncasecmp ("Absolute", ci->values[0].value.string, strlen ("Absolute")) == 0)
+ {
+ cm->flags = UTILS_MATCH_DS_TYPE_ABSOLUTE;
+ if (strcasecmp ("AbsoluteSet", ci->values[0].value.string) == 0)
+ cm->flags |= UTILS_MATCH_CF_ABSOLUTE_SET;
+ else
+ cm->flags = 0;
+ }
else
{
cm->flags = 0;
--- /dev/null
+/**
+ * collectd - src/tokyotyrant.c
+ * Copyright (C) 2009 Paul Sadauskas
+ *
+ * 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Paul Sadauskas <psadauskas@gmail.com>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "utils_cache.h"
+#include "utils_parse_option.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <tcrdb.h>
+
+#define DEFAULT_HOST "127.0.0.1"
+#define DEFAULT_PORT 1978
+
+static const char *config_keys[] =
+{
+ "Host",
+ "Port"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char *config_host = NULL;
+static char *config_port = NULL;
+
+static TCRDB *rdb = NULL;
+
+static int parse_service_name (const char *service_name)
+{
+ struct addrinfo *ai_list;
+ struct addrinfo *ai_ptr;
+ struct addrinfo ai_hints;
+ int status;
+ int service_number;
+
+ ai_list = NULL;
+ memset (&ai_hints, 0, sizeof (ai_hints));
+ ai_hints.ai_family = AF_UNSPEC;
+
+ status = getaddrinfo (/* node = */ NULL, service_name,
+ &ai_hints, &ai_list);
+ if (status != 0)
+ {
+ ERROR ("tokyotyrant plugin: getaddrinfo failed: %s",
+ gai_strerror (status));
+ return (-1);
+ }
+
+ service_number = -1;
+ for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+ {
+ if (ai_ptr->ai_family == AF_INET)
+ {
+ struct sockaddr_in *sa;
+
+ sa = (void *) ai_ptr->ai_addr;
+ service_number = (int) ntohs (sa->sin_port);
+ }
+ else if (ai_ptr->ai_family == AF_INET6)
+ {
+ struct sockaddr_in6 *sa;
+
+ sa = (void *) ai_ptr->ai_addr;
+ service_number = (int) ntohs (sa->sin6_port);
+ }
+
+ if ((service_number > 0) && (service_number <= 65535))
+ break;
+ }
+
+ freeaddrinfo (ai_list);
+
+ if ((service_number > 0) && (service_number <= 65535))
+ return (service_number);
+ return (-1);
+} /* int parse_service_name */
+
+static int tt_config (const char *key, const char *value)
+{
+ if (strcasecmp ("Host", key) == 0)
+ {
+ char *temp;
+
+ temp = strdup (value);
+ if (temp == NULL)
+ {
+ ERROR("tokyotyrant plugin: Host strdup failed.");
+ return (1);
+ }
+ sfree (config_host);
+ config_host = temp;
+ }
+ else if (strcasecmp ("Port", key) == 0)
+ {
+ char *temp;
+
+ temp = strdup (value);
+ if (temp == NULL)
+ {
+ ERROR("tokyotyrant plugin: Port strdup failed.");
+ return (1);
+ }
+ sfree (config_port);
+ config_port = temp;
+ }
+ else
+ {
+ ERROR ("tokyotyrant plugin: error: unrecognized configuration key %s", key);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void printerr()
+{
+ int ecode = tcrdbecode(rdb);
+ ERROR ("tokyotyrant plugin: error: %d, %s",
+ ecode, tcrdberrmsg(ecode));
+}
+
+static void tt_submit (gauge_t val, const char* type)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = val;
+
+ vl.values = values;
+ vl.values_len = STATIC_ARRAY_SIZE (values);
+
+ sstrncpy (vl.host, config_host, sizeof (vl.host));
+ sstrncpy (vl.plugin, "tokyotyrant", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, config_port,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+}
+
+static void tt_open_db (void)
+{
+ char* host = NULL;
+ int port = DEFAULT_PORT;
+
+ if (rdb != NULL)
+ return;
+
+ host = ((config_host != NULL) ? config_host : DEFAULT_HOST);
+
+ if (config_port != NULL)
+ {
+ port = parse_service_name (config_port);
+ if (port <= 0)
+ return;
+ }
+
+ rdb = tcrdbnew ();
+ if (rdb == NULL)
+ return;
+ else if (!tcrdbopen(rdb, host, port))
+ {
+ printerr ();
+ tcrdbdel (rdb);
+ rdb = NULL;
+ }
+} /* void tt_open_db */
+
+static int tt_read (void) {
+ gauge_t rnum, size;
+
+ tt_open_db ();
+ if (rdb == NULL)
+ return (-1);
+
+ rnum = tcrdbrnum(rdb);
+ tt_submit (rnum, "records");
+
+ size = tcrdbsize(rdb);
+ tt_submit (size, "file_size");
+
+ return (0);
+}
+
+static int tt_shutdown(void)
+{
+ sfree(config_host);
+ sfree(config_port);
+
+ if (rdb != NULL)
+ {
+ if (!tcrdbclose(rdb))
+ {
+ printerr ();
+ tcrdbdel (rdb);
+ return (1);
+ }
+ tcrdbdel (rdb);
+ rdb = NULL;
+ }
+
+ return(0);
+}
+
+void module_register (void)
+{
+ plugin_register_config("tokyotyrant", tt_config,
+ config_keys, config_keys_num);
+ plugin_register_read("tokyotyrant", tt_read);
+ plugin_register_shutdown("tokyotyrant", tt_shutdown);
+}
+
+/* vim: set sw=8 ts=8 tw=78 : */
+absolute count:ABSOLUTE:0:U
apache_bytes count:COUNTER:0:134217728
apache_connections count:GAUGE:0:65535
apache_requests count:COUNTER:0:134217728
cpu value:COUNTER:0:4294967295
current value:GAUGE:U:U
delay seconds:GAUGE:-1000000:1000000
+derive value:DERIVE:0:U
df used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
disk_merged read:COUNTER:0:4294967295, write:COUNTER:0:4294967295
disk_octets read:COUNTER:0:17179869183, write:COUNTER:0:17179869183
dns_notify value:COUNTER:0:65535
dns_octets queries:COUNTER:0:125000000, responses:COUNTER:0:125000000
dns_opcode value:COUNTER:0:65535
-dns_qtype value:COUNTER:0:65535
dns_qtype_cached value:GAUGE:0:4294967295
+dns_qtype value:COUNTER:0:65535
dns_query value:COUNTER:0:65535
dns_question value:COUNTER:0:65535
dns_rcode value:COUNTER:0:65535
email_size value:GAUGE:0:U
entropy entropy:GAUGE:0:4294967295
fanspeed value:GAUGE:0:U
+file_size bytes:GAUGE:0:U
files value:GAUGE:0:U
frequency frequency:GAUGE:0:U
frequency_offset ppm:GAUGE:-1000000:1000000
+fscache_stat value:COUNTER:0:4294967295
gauge value:GAUGE:U:U
+http_request_methods count:COUNTER:0:134217728
+http_requests count:COUNTER:0:134217728
+http_response_codes count:COUNTER:0:134217728
humidity value:GAUGE:0:100
if_collisions value:COUNTER:0:4294967295
if_dropped rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
ipt_packets value:COUNTER:0:134217728
irq value:COUNTER:U:65535
latency value:GAUGE:0:65535
+links value:GAUGE:0:U
load shortterm:GAUGE:0:100, midterm:GAUGE:0:100, longterm:GAUGE:0:100
memcached_command value:COUNTER:0:U
memcached_connections value:GAUGE:0:U
mysql_qcache hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U
mysql_threads running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U
nfs_procedure value:COUNTER:0:4294967295
-fscache_stat value:COUNTER:0:4294967295
nginx_connections value:GAUGE:0:U
nginx_requests value:COUNTER:0:134217728
operations value:COUNTER:0:4294967295
pg_numbackends value:GAUGE:0:U
pg_scan value:COUNTER:0:U
pg_xact value:COUNTER:0:U
-ping ping:GAUGE:0:65535
ping_droprate value:GAUGE:0:100
+ping ping:GAUGE:0:65535
ping_stddev value:GAUGE:0:65535
players value:GAUGE:0:1000000
power value:GAUGE:0:U
ps_state value:GAUGE:0:65535
ps_vm value:GAUGE:0:9223372036854775807
queue_length value:GAUGE:0:U
+records count:GAUGE:0:U
+route_etx value:GAUGE:0:U
+route_metric value:GAUGE:0:U
+routes value:GAUGE:0:U
serial_octets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
signal_noise value:GAUGE:U:0
signal_power value:GAUGE:U:0
dsrc->type = DS_TYPE_GAUGE;
else if (strcasecmp (fields[1], "COUNTER") == 0)
dsrc->type = DS_TYPE_COUNTER;
+ else if (strcasecmp (fields[1], "DERIVE") == 0)
+ dsrc->type = DS_TYPE_DERIVE;
+ else if (strcasecmp (fields[1], "ABSOLUTE") == 0)
+ dsrc->type = DS_TYPE_ABSOLUTE;
else
{
- ERROR ("(fields[1] = %s) != (GAUGE || COUNTER)", fields[1]);
+ ERROR ("(fields[1] = %s) != (GAUGE || COUNTER || DERIVE || ABSOLUTE)", fields[1]);
return (-1);
}
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;
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);
return;
sfree (ce->values_gauge);
- sfree (ce->values_counter);
+ sfree (ce->values_raw);
sfree (ce);
} /* void cache_free */
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;
for (i = 0; i < ds->ds_num; i++)
{
- if (ds->ds[i].type == DS_TYPE_COUNTER)
+ switch (ds->ds[i].type)
{
- counter_t diff;
+ 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;
- /* 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_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;
static int dispatch_values (const data_set_t *ds, value_list_t *vl,
FILE *fh, char *buffer)
{
- char *dummy;
- char *ptr;
- char *saveptr;
- int i;
-
- char *time_str = buffer;
- char *value_str = strchr (time_str, ':');
- if (value_str == NULL)
- {
- print_to_socket (fh, "-1 No time found.\n");
- return (-1);
- }
- *value_str = '\0'; value_str++;
-
- vl->time = (time_t) atoi (time_str);
+ int status;
- i = 0;
- dummy = value_str;
- saveptr = NULL;
- while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
- {
- dummy = NULL;
-
- if (i >= vl->values_len)
- {
- i = vl->values_len + 1;
- break;
- }
-
- if ((strcmp (ptr, "U") == 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]))
- {
- print_to_socket (fh, "-1 Failed to parse value `%s'.\n", ptr);
- return (-1);
- }
-
- i++;
- } /* while (strtok_r) */
-
- if (i != vl->values_len)
+ status = parse_values (buffer, vl, ds);
+ if (status != 0)
{
- char identifier[128];
- FORMAT_VL (identifier, sizeof (identifier), vl, ds);
- ERROR ("cmd putval: dispatch_values: "
- "Number of values incorrect: "
- "Got %i, expected %i. Identifier is `%s'.",
- i, vl->values_len, identifier);
- print_to_socket (fh, "-1 Number of values incorrect: "
- "Got %i, expected %i.\n",
- i, vl->values_len);
+ print_to_socket (fh, "-1 Parsing the values string failed.\n");
return (-1);
}
vl.values_len = 1;
value_str = column_values[r->legacy_position];
- if (0 != parse_value (value_str, &vl.values[0], r->ds->ds[0]))
+ if (0 != parse_value (value_str, &vl.values[0], r->ds->ds[0].type))
{
ERROR ("db query utils: udb_legacy_result_handle_result: "
"Parsing `%s' as %s failed.", value_str,
- (r->ds->ds[0].type == DS_TYPE_COUNTER) ? "counter" : "gauge");
+ DS_TYPE_TO_STRING (r->ds->ds[0].type));
errno = EINVAL;
return (-1);
}
{
char *value_str = r->values_buffer[i];
- if (0 != parse_value (value_str, &vl.values[i], r->ds->ds[i]))
+ if (0 != parse_value (value_str, &vl.values[i], r->ds->ds[i].type))
{
ERROR ("db query utils: udb_result_submit: Parsing `%s' as %s failed.",
- value_str,
- (r->ds->ds[i].type == DS_TYPE_COUNTER) ? "counter" : "gauge");
+ value_str, DS_TYPE_TO_STRING (r->ds->ds[i].type));
errno = EINVAL;
return (-1);
}
data->values_num++;
}
+ else if (data->ds_type & UTILS_MATCH_DS_TYPE_DERIVE)
+ {
+ derive_t value;
+ char *endptr = NULL;
+
+ if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC)
+ {
+ data->value.counter++;
+ data->values_num++;
+ return (0);
+ }
+
+ if (matches_num < 2)
+ return (-1);
+
+ value = strtoll (matches[1], &endptr, 0);
+ if (matches[1] == endptr)
+ return (-1);
+
+ if (data->ds_type & UTILS_MATCH_CF_DERIVE_SET)
+ data->value.derive = value;
+ else if (data->ds_type & UTILS_MATCH_CF_DERIVE_ADD)
+ data->value.derive += value;
+ else
+ {
+ ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+ return (-1);
+ }
+
+ data->values_num++;
+ }
+ else if (data->ds_type & UTILS_MATCH_DS_TYPE_ABSOLUTE)
+ {
+ absolute_t value;
+ char *endptr = NULL;
+
+ if (matches_num < 2)
+ return (-1);
+
+ value = strtoll (matches[1], &endptr, 0);
+ if (matches[1] == endptr)
+ return (-1);
+
+ if (data->ds_type & UTILS_MATCH_CF_ABSOLUTE_SET)
+ data->value.absolute = value;
+ else
+ {
+ ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
+ return (-1);
+ }
+
+ data->values_num++;
+ }
else
{
ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
*/
#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_CF_GAUGE_AVERAGE 0x01
#define UTILS_MATCH_CF_GAUGE_MIN 0x02
#define UTILS_MATCH_CF_COUNTER_ADD 0x02
#define UTILS_MATCH_CF_COUNTER_INC 0x04
+#define UTILS_MATCH_CF_DERIVE_SET 0x01
+#define UTILS_MATCH_CF_DERIVE_ADD 0x02
+#define UTILS_MATCH_CF_DERIVE_INC 0x04
+
+#define UTILS_MATCH_CF_ABSOLUTE_SET 0x01
+#define UTILS_MATCH_CF_ABSOLUTE_ADD 0x02
+#define UTILS_MATCH_CF_ABSOLUTE_INC 0x04
+
/*
* Data types
*/
type = "COUNTER";
else if (d->type == DS_TYPE_GAUGE)
type = "GAUGE";
+ else if (d->type == DS_TYPE_DERIVE)
+ type = "DERIVE";
+ else if (d->type == DS_TYPE_ABSOLUTE)
+ type = "ABSOLUTE";
else
{
ERROR ("rrdtool plugin: Unknown DS type: %i",
sstrncpy (min, "U", sizeof (min));
}
else
- ssnprintf (min, sizeof (min), "%lf", d->min);
+ ssnprintf (min, sizeof (min), "%f", d->min);
if (isnan (d->max))
{
sstrncpy (max, "U", sizeof (max));
}
else
- ssnprintf (max, sizeof (max), "%lf", d->max);
+ ssnprintf (max, sizeof (max), "%f", d->max);
status = ssnprintf (buffer, sizeof (buffer),
"DS:%s:%s:%i:%s:%s",
* {{{ */
#define UT_FLAG_INVERT 0x01
#define UT_FLAG_PERSIST 0x02
+#define UT_FLAG_PERCENTAGE 0x04
typedef struct threshold_s
{
return (0);
} /* int ut_config_type_persist */
+static int ut_config_type_percentage(threshold_t *th, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
+ {
+ WARNING ("threshold values: The `Percentage' option needs exactly one "
+ "boolean argument.");
+ return (-1);
+ }
+
+ if (ci->values[0].value.boolean)
+ th->flags |= UT_FLAG_PERCENTAGE;
+ else
+ th->flags &= ~UT_FLAG_PERCENTAGE;
+
+ return (0);
+} /* int ut_config_type_percentage */
+
static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
{
int i;
status = ut_config_type_invert (&th, option);
else if (strcasecmp ("Persist", option->key) == 0)
status = ut_config_type_persist (&th, option);
+ else if (strcasecmp ("Percentage", option->key) == 0)
+ status = ut_config_type_percentage (&th, option);
else
{
WARNING ("threshold values: Option `%s' not allowed inside a `Type' "
th.warning_max = NAN;
th.failure_min = NAN;
th.failure_max = NAN;
-
+
for (i = 0; i < ci->children_num; i++)
{
oconfig_item_t *option = ci->children + i;
{
if (!isnan (min) && !isnan (max))
{
- status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
- "%f. That is within the %s region of %f and %f.",
- ds->ds[ds_index].name, values[ds_index],
- (state == STATE_ERROR) ? "failure" : "warning",
- min, max);
+ status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
+ "%f. That is within the %s region of %f%s and %f%s.",
+ ds->ds[ds_index].name, values[ds_index],
+ (state == STATE_ERROR) ? "failure" : "warning",
+ min, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "",
+ max, ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
}
else
{
status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
- "%f. That is %s the %s threshold of %f.",
+ "%f. That is %s the %s threshold of %f%s.",
ds->ds[ds_index].name, values[ds_index],
isnan (min) ? "below" : "above",
(state == STATE_ERROR) ? "failure" : "warning",
- isnan (min) ? max : min);
+ isnan (min) ? max : min,
+ ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
}
}
else /* is not inverted */
{
status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
- "%f. That is %s the %s threshold of %f.",
+ "%f. That is %s the %s threshold of %f%s.",
ds->ds[ds_index].name, values[ds_index],
(values[ds_index] < min) ? "below" : "above",
(state == STATE_ERROR) ? "failure" : "warning",
- (values[ds_index] < min) ? min : max);
+ (values[ds_index] < min) ? min : max,
+ ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
}
buf += status;
bufsize -= status;
int is_failure = 0;
/* check if this threshold applies to this data source */
- ds_name = ds->ds[ds_index].name;
- if ((th->data_source[0] != 0)
- && (strcmp (ds_name, th->data_source) != 0))
- return (STATE_OKAY);
+ if (ds != NULL)
+ {
+ ds_name = ds->ds[ds_index].name;
+ if ((th->data_source[0] != 0)
+ && (strcmp (ds_name, th->data_source) != 0))
+ return (STATE_OKAY);
+ }
if ((th->flags & UT_FLAG_INVERT) != 0)
{
int ret = -1;
int ds_index = -1;
int i;
+ gauge_t values_copy[ds->ds_num];
+
+ memcpy (values_copy, values, sizeof (values_copy));
+
+ if ((th->flags & UT_FLAG_PERCENTAGE) != 0)
+ {
+ int num = 0;
+ gauge_t sum=0.0;
+
+ if (ds->ds_num == 1)
+ {
+ WARNING ("ut_check_one_threshold: The %s type has only one data "
+ "source, but you have configured to check this as a percentage. "
+ "That doesn't make much sense, because the percentage will always "
+ "be 100%%!", ds->type);
+ }
+
+ /* Prepare `sum' and `num'. */
+ for (i = 0; i < ds->ds_num; i++)
+ if (!isnan (values[i]))
+ {
+ num++;
+ sum += values[i];
+ }
+
+ if ((num == 0) /* All data sources are undefined. */
+ || (sum == 0.0)) /* Sum is zero, cannot calculate percentage. */
+ {
+ for (i = 0; i < ds->ds_num; i++)
+ values_copy[i] = NAN;
+ }
+ else /* We can actually calculate the percentage. */
+ {
+ for (i = 0; i < ds->ds_num; i++)
+ values_copy[i] = 100.0 * values[i] / sum;
+ }
+ } /* if (UT_FLAG_PERCENTAGE) */
for (i = 0; i < ds->ds_num; i++)
{
int status;
- status = ut_check_one_data_source (ds, vl, th, values, i);
+ status = ut_check_one_data_source (ds, vl, th, values_copy, i);
if (ret < status)
{
ret = status;
return (2);
} /* }}} int ut_check_interesting */
-/* vim: set sw=2 ts=8 sts=2 tw=78 fdm=marker : */
+/* vim: set sw=2 ts=8 sts=2 tw=78 et fdm=marker : */