- 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.
* 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
------------------------------------
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])
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
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
#@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
# </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"
=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.
--- /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 = val;
+ else
+ vt.gauge = (double)val;
+
+ 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_GAUGE)
+ vt.gauge = val;
+ else
+ vt.counter = val;
+
+ 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 */
{
"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
{
--- /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 : */
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
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
+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