author | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Sat, 27 Nov 2010 10:46:11 +0000 (11:46 +0100) | ||
committer | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Sat, 27 Nov 2010 10:46:11 +0000 (11:46 +0100) |
Conflicts:
src/utils_rrdcreate.c
src/utils_rrdcreate.c
103 files changed:
diff --git a/.gitignore b/.gitignore
index e8f9af66d7879336910ff56dd76f8b70d796dd23..cbdd62f821579ae7369bbd1931b9bc4ef0bd60f2 100644 (file)
--- a/.gitignore
+++ b/.gitignore
# python stuff
*.pyc
+
+# tag stuff
+src/tags
+
+# backup stuff
+*~
index 45689652ab1eb1fbfc3df8c2677434d924212c57..c57f90b2d0c38aa625f48e280dac736570ec0284 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
Antony Dovgal <tony at daylessday.org>
- memcached plugin.
+Aurélien Reynaud <collectd at wattapower.net>
+ - LPAR plugin.
+ - Various fixes for AIX, HP-UX and Solaris.
+
Bruno Prémont <bonbons at linux-vserver.org>
- BIND plugin.
- Many bugreports and -fixes in various plugins,
Jason Pepas <cell at ices.utexas.edu>
- nfs plugin.
+Jérôme Renard <jerome.renard at gmail.com>
+ - varnish plugin.
+
Luboš Staněk <kolektor at atlas.cz>
- sensors plugin improvements.
- Time and effort to find a nasty bug in the ntpd-plugin.
Scott Garrett <sgarrett at technomancer.com>
- tape plugin.
+Sebastien Pahl <sebastien.pahl at dotcloud.com>
+ - AMQP plugin.
+
Simon Kuhnle <simon at blarzwurst.de>
- OpenBSD code for the cpu and memory plugins.
index 5063069009e490e245e57e3498f07a61cb3c2cbf..2ed8934fc92e43842dcab3ed7df8808bc5aa4bfb 100644 (file)
--- a/README
+++ b/README
- load
System load average over the last 1, 5 and 15 minutes.
+ - lpar
+ Detailed CPU statistics of the “Logical Partitions” virtualization
+ technique built into IBM's POWER processors.
+
- libvirt
CPU, disk and network I/O statistics from virtual machines.
collectd without the need to start a heavy interpreter every interval.
See collectd-python(5) for details.
+ - redis
+ The redis plugin gathers information from a redis server, including:
+ uptime, used memory, total connections etc.
+
- routeros
Query interface and wireless registration statistics from RouterOS.
- users
Users currently logged in.
+ - varnish
+ Various statistics from Varnish, an HTTP accelerator.
+
- vmem
Virtual memory statistics, e. g. the number of page-ins/-outs or the
number of pagefaults.
* Output can be written or sent to various destinations by the following
plugins:
+ - amqp
+ Sends JSON-encoded data to an Advanced Message Queuing Protocol (AMQP)
+ server, such as RabbitMQ.
+
- csv
Write to comma separated values (CSV) files. This needs lots of
diskspace but is extremely portable and can be analysed with almost
* libclntsh (optional)
Used by the `oracle' plugin.
+ * libcredis (optional)
+ Used by the redis plugin. Please note that you require a 0.2.2 version
+ or higher. <http://code.google.com/p/credis/>
+
* libcurl (optional)
If you want to use the `apache', `ascent', `curl', `nginx', or `write_http'
plugin.
Used by the `python' plugin. Currently, only 2.3 ≦ Python < 3 is supported.
<http://www.python.org/>
+ * librabbitmq (optional; also called “rabbitmq-c”)
+ Used by the AMQP plugin for AMQP connections, for example to RabbitMQ.
+ <http://hg.rabbitmq.com/rabbitmq-c/>
+
* librouteros (optional)
Used by the `routeros' plugin to connect to a device running `RouterOS'.
<http://verplant.org/librouteros/>
Parse JSON data. This is needed for the `curl_json' plugin.
<http://github.com/lloyd/yajl>
+ * libvarnish (optional)
+ Fetches statistics from a Varnish instance. This is needed for the Varnish plugin
+ <http://varnish-cache.org>
+
Configuring / Compiling / Installing
------------------------------------
diff --git a/bindings/java/org/collectd/api/CollectdFlushInterface.java b/bindings/java/org/collectd/api/CollectdFlushInterface.java
index 3e492ddffd9a7f404579b77ef119087c59fee24d..410c61c60ef21d2d350e29a699fe1c2e5630d42c 100644 (file)
*/
public interface CollectdFlushInterface
{
- public int flush (int timeout, String identifier);
+ public int flush (Number timeout, String identifier);
}
diff --git a/bindings/java/org/collectd/api/ValueList.java b/bindings/java/org/collectd/api/ValueList.java
index 1baeff24ed7fb8e58e6a80df22c576f3adb3b78c..b8d6f40f86f604b56eb042eb413a11f6226fa58b 100644 (file)
_ds = new DataSet (_type, dsrc);
}
+ /**
+ * Returns the interval (in milliseconds) of the value list.
+ */
public long getInterval() {
return _interval;
}
+ /**
+ * Sets the interval (in milliseconds) of the value list.
+ */
public void setInterval(long interval) {
_interval = interval;
}
diff --git a/bindings/java/org/collectd/java/GenericJMXConfConnection.java b/bindings/java/org/collectd/java/GenericJMXConfConnection.java
index ffa9ded4fbdc874b32dc3c5e6472df5352c6c59d..0c81bc9ad941760f07021530d6663f32ee34b75f 100644 (file)
/*
* collectd/java - org/collectd/java/GenericJMXConfConnection.java
- * Copyright (C) 2009 Florian octo Forster
+ * Copyright (C) 2009,2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
private String _username = null;
private String _password = null;
private String _host = null;
+ private String _instance_prefix = null;
private String _service_url = null;
private MBeanServerConnection _jmx_connection = null;
private List<GenericJMXConfMBean> _mbeans = null;
if (tmp != null)
this._service_url = tmp;
}
+ else if (child.getKey ().equalsIgnoreCase ("InstancePrefix"))
+ {
+ String tmp = getConfigString (child);
+ if (tmp != null)
+ this._instance_prefix = tmp;
+ }
else if (child.getKey ().equalsIgnoreCase ("Collect"))
{
String tmp = getConfigString (child);
{
int status;
- status = this._mbeans.get (i).query (this._jmx_connection, pd);
+ status = this._mbeans.get (i).query (this._jmx_connection, pd,
+ this._instance_prefix);
if (status != 0)
{
this._jmx_connection = null;
diff --git a/bindings/java/org/collectd/java/GenericJMXConfMBean.java b/bindings/java/org/collectd/java/GenericJMXConfMBean.java
index 1587bd5f9729009d13d72f8a31766439f33a6341..b1fbfb3ec18c14fadf0ae56c845d8ff76a0f5417 100644 (file)
/*
* collectd/java - org/collectd/java/GenericJMXConfMBean.java
- * Copyright (C) 2009 Florian octo Forster
+ * Copyright (C) 2009,2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
return (v.getString ());
} /* }}} String getConfigString */
- private String join (String separator, List<String> list) /* {{{ */
- {
- StringBuffer sb;
-
- sb = new StringBuffer ();
-
- for (int i = 0; i < list.size (); i++)
- {
- if (i > 0)
- sb.append ("-");
- sb.append (list.get (i));
- }
-
- return (sb.toString ());
- } /* }}} String join */
-
/*
* <MBean "alias name">
* ObjectName "object name"
return (this._name);
} /* }}} */
- public int query (MBeanServerConnection conn, PluginData pd) /* {{{ */
+ public int query (MBeanServerConnection conn, PluginData pd, /* {{{ */
+ String instance_prefix)
{
Set<ObjectName> names;
Iterator<ObjectName> iter;
ObjectName objName;
PluginData pd_tmp;
List<String> instanceList;
- String instance;
+ StringBuffer instance;
objName = iter.next ();
pd_tmp = new PluginData (pd);
instanceList = new ArrayList<String> ();
+ instance = new StringBuffer ();
Collectd.logDebug ("GenericJMXConfMBean: objName = "
+ objName.toString ());
}
}
+ if (instance_prefix != null)
+ instance.append (instance_prefix);
+
if (this._instance_prefix != null)
- instance = new String (this._instance_prefix
- + join ("-", instanceList));
- else
- instance = join ("-", instanceList);
- pd_tmp.setPluginInstance (instance);
+ instance.append (this._instance_prefix);
+
+ for (int i = 0; i < instanceList.size (); i++)
+ {
+ if (i > 0)
+ instance.append ("-");
+ instance.append (instanceList.get (i));
+ }
+
+ pd_tmp.setPluginInstance (instance.toString ());
- Collectd.logDebug ("GenericJMXConfMBean: instance = " + instance);
+ Collectd.logDebug ("GenericJMXConfMBean: instance = " + instance.toString ());
for (int i = 0; i < this._values.size (); i++)
this._values.get (i).query (conn, objName, pd_tmp);
index f1b5d859874c0affc08143e1a536ca6f99747dc6..ca3b5d2349805a505ae22df4faad8c7b9feda529 100644 (file)
}
}
-sub plugin_flush_one {
- my $timeout = shift;
- my $name = shift;
-
- WARNING ("Collectd::plugin_flush_one is deprecated - "
- . "use Collectd::plugin_flush instead.");
-
- if (! (defined ($timeout) && defined ($name))) {
- ERROR ("Usage: Collectd::plugin_flush_one(timeout, name)");
- return;
- }
-
- plugin_flush (plugins => $name, timeout => $timeout);
-}
-
-sub plugin_flush_all {
- my $timeout = shift;
-
- WARNING ("Collectd::plugin_flush_all is deprecated - "
- . "use Collectd::plugin_flush instead.");
-
- if (! defined ($timeout)) {
- ERROR ("Usage: Collectd::plugin_flush_all(timeout)");
- return;
- }
-
- plugin_flush (timeout => $timeout);
-}
-
sub fc_call {
my $type = shift;
my $name = shift;
diff --git a/configure.in b/configure.in
index a47fed03a67237582cdb07f7c8c2e9ef4043da3f..3b46188a3e73ea9ac4cb7be49b3db4bd1dccc2d7 100644 (file)
--- a/configure.in
+++ b/configure.in
if test "x$enable_standards" = "xyes"
then
AC_DEFINE(_ISOC99_SOURCE, 1, [Define to enforce ISO C99 compliance.])
- AC_DEFINE(_POSIX_C_SOURCE, 200112L, [Define to enforce POSIX.1-2001 compliance.])
- AC_DEFINE(_XOPEN_SOURCE, 600, [Define to enforce X/Open 6 (XSI) compliance.])
+ AC_DEFINE(_POSIX_C_SOURCE, 200809L, [Define to enforce POSIX.1-2008 compliance.])
+ AC_DEFINE(_XOPEN_SOURCE, 700, [Define to enforce X/Open 7 (XSI) compliance.])
AC_DEFINE(_REENTRANT, 1, [Define to enable reentrancy interfaces.])
+ if test "x$GCC" = "xyes"
+ then
+ CFLAGS="$CFLAGS -std=c99"
+ fi
fi
AM_CONDITIONAL(BUILD_FEATURE_STANDARDS, test "x$enable_standards" = "xyes")
AC_CHECK_FUNCS(socket, [], AC_CHECK_LIB(socket, socket, [socket_needs_socket="yes"], AC_MSG_ERROR(cannot find socket)))
AM_CONDITIONAL(BUILD_WITH_LIBSOCKET, test "x$socket_needs_socket" = "xyes")
+clock_gettime_needs_rt="no"
+clock_gettime_needs_posix4="no"
+have_clock_gettime="no"
+AC_CHECK_FUNCS(clock_gettime, [have_clock_gettime="yes"])
+if test "x$have_clock_gettime" = "xno"
+then
+ AC_CHECK_LIB(rt, clock_gettime, [clock_gettime_needs_rt="yes"
+ have_clock_gettime="yes"])
+fi
+if test "x$have_clock_gettime" = "xno"
+then
+ AC_CHECK_LIB(posix4, clock_gettime, [clock_gettime_needs_posix4="yes"
+ have_clock_gettime="yes"])
+fi
+if test "x$have_clock_gettime" = "xyes"
+then
+ AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if the clock_gettime(2) function is available.])
+else
+ AC_MSG_WARN(cannot find clock_gettime)
+fi
+
nanosleep_needs_rt="no"
nanosleep_needs_posix4="no"
AC_CHECK_FUNCS(nanosleep,
AC_CHECK_LIB(posix4, nanosleep,
[nanosleep_needs_posix4="yes"],
AC_MSG_ERROR(cannot find nanosleep))))
-AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$nanosleep_needs_rt" = "xyes")
-AM_CONDITIONAL(BUILD_WITH_LIBPOSIX4, test "x$nanosleep_needs_posix4" = "xyes")
+
+AM_CONDITIONAL(BUILD_WITH_LIBRT, test "x$clock_gettime_needs_rt" = "xyes" || test "x$nanosleep_needs_rt" = "xyes")
+AM_CONDITIONAL(BUILD_WITH_LIBPOSIX4, test "x$clock_gettime_needs_posix4" = "xyes" || test "x$nanosleep_needs_posix4" = "xyes")
AC_CHECK_FUNCS(sysctl, [have_sysctl="yes"], [have_sysctl="no"])
AC_CHECK_FUNCS(sysctlbyname, [have_sysctlbyname="yes"], [have_sysctlbyname="no"])
AC_CHECK_FUNCS(getutent, [have_getutent="yes"], [have_getutent="no"])
AC_CHECK_FUNCS(getutxent, [have_getutxent="yes"], [have_getutxent="no"])
AC_CHECK_FUNCS(swapctl, [have_swapctl="yes"], [have_swapctl="no"])
+if test "x$have_swapctl" = "xyes"; then
+ AC_CACHE_CHECK([whether swapctl takes two arguments],
+ [c_cv_have_swapctl_two_args],
+ AC_COMPILE_IFELSE(
+ AC_LANG_PROGRAM([[AC_INCLUDES_DEFAULT
+#if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
+# undef _FILE_OFFSET_BITS
+# undef _LARGEFILE64_SOURCE
+#endif
+#include <sys/stat.h>
+#include <sys/swap.h>]],
+ [[
+ int num = swapctl(0, NULL);
+ ]]
+ ),
+ [c_cv_have_swapctl_two_args="yes"],
+ [c_cv_have_swapctl_two_args="no"]
+ )
+ )
+ AC_CACHE_CHECK([whether swapctl takes three arguments],
+ [c_cv_have_swapctl_three_args],
+ AC_COMPILE_IFELSE(
+ AC_LANG_PROGRAM([[AC_INCLUDES_DEFAULT
+#if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
+# undef _FILE_OFFSET_BITS
+# undef _LARGEFILE64_SOURCE
+#endif
+#include <sys/stat.h>
+#include <sys/swap.h>]],
+ [[
+ int num = swapctl(0, NULL,0);
+ ]]
+ ),
+ [c_cv_have_swapctl_three_args="yes"],
+ [c_cv_have_swapctl_three_args="no"]
+ )
+ )
+fi
+# Check for different versions of `swapctl' here..
+if test "x$have_swapctl" = "xyes"; then
+ if test "x$c_cv_have_swapctl_two_args" = "xyes"; then
+ AC_DEFINE(HAVE_SWAPCTL_TWO_ARGS, 1,
+ [Define if the function swapctl exists and takes two arguments.])
+ fi
+ if test "x$c_cv_have_swapctl_three_args" = "xyes"; then
+ AC_DEFINE(HAVE_SWAPCTL_THREE_ARGS, 1,
+ [Define if the function swapctl exists and takes three arguments.])
+ fi
+fi
# For load module
AC_CHECK_FUNCS(getloadavg, [have_getloadavg="yes"], [have_getloadavg="no"])
if test "x$with_perfstat" = "xyes"
then
AC_DEFINE(HAVE_PERFSTAT, 1, [Define to 1 if you have the 'perfstat' library (-lperfstat)])
+ # struct members pertaining to donation have been added to libperfstat somewhere between AIX5.3ML5 and AIX5.3ML9
+ AC_CHECK_MEMBER([perfstat_partition_type_t.b.donate_enabled], [], [], [[#include <libperfstat.h]])
+ if test "x$av_cv_member_perfstat_partition_type_t_b_donate_enabled" = "xyes"
+ then
+ AC_DEFINE(PERFSTAT_SUPPORTS_DONATION, 1, [Define to 1 if your version of the 'perfstat' library supports donation])
+ fi
fi
AM_CONDITIONAL(BUILD_WITH_PERFSTAT, test "x$with_perfstat" = "xyes")
fi
AM_CONDITIONAL(BUILD_WITH_LIBKVM_OPENFILES, test "x$with_kvm_openfiles" = "xyes")
+# --with-libcredis {{{
+AC_ARG_WITH(libcredis, [AS_HELP_STRING([--with-libcredis@<:@=PREFIX@:>@], [Path to libcredis.])],
+[
+ if test "x$withval" = "xyes"
+ then
+ with_libcredis="yes"
+ else if test "x$withval" = "xno"
+ then
+ with_libcredis="no"
+ else
+ with_libcredis="yes"
+ LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS -I$withval/include"
+ LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS -L$withval/lib"
+ fi; fi
+],
+[with_libcredis="yes"])
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+
+CPPFLAGS="$CPPFLAGS $LIBCREDIS_CPPFLAGS"
+LDFLAGS="$LDFLAGS $LIBCREDIS_LDFLAGS"
+
+if test "x$with_libcredis" = "xyes"
+then
+ if test "x$LIBCREDIS_CPPFLAGS" != "x"
+ then
+ AC_MSG_NOTICE([libcredis CPPFLAGS: $LIBCREDIS_CPPFLAGS])
+ fi
+ AC_CHECK_HEADERS(credis.h,
+ [with_libcredis="yes"],
+ [with_libcredis="no ('credis.h' not found)"])
+fi
+if test "x$with_libcredis" = "xyes"
+then
+ if test "x$LIBCREDIS_LDFLAGS" != "x"
+ then
+ AC_MSG_NOTICE([libcredis LDFLAGS: $LIBCREDIS_LDFLAGS])
+ fi
+ AC_CHECK_LIB(credis, credis_info,
+ [with_libcredis="yes"],
+ [with_libcredis="no (symbol 'credis_info' not found)"])
+
+fi
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+
+if test "x$with_libcredis" = "xyes"
+then
+ BUILD_WITH_LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS"
+ BUILD_WITH_LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS"
+ AC_SUBST(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBCREDIS_LDFLAGS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBCREDIS, test "x$with_libcredis" = "xyes")
+# }}}
+
# --with-libcurl {{{
with_curl_config="curl-config"
with_curl_cflags=""
fi
# }}} --with-python
+# --with-librabbitmq {{{
+with_librabbitmq_cppflags=""
+with_librabbitmq_ldflags=""
+AC_ARG_WITH(librabbitmq, [AS_HELP_STRING([--with-librabbitmq@<:@=PREFIX@:>@], [Path to librabbitmq.])],
+[
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ then
+ with_librabbitmq_cppflags="-I$withval/include"
+ with_librabbitmq_ldflags="-L$withval/lib"
+ with_librabbitmq="yes"
+ else
+ with_librabbitmq="$withval"
+ fi
+],
+[
+ with_librabbitmq="yes"
+])
+if test "x$with_librabbitmq" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
+
+ AC_CHECK_HEADERS(amqp.h, [with_librabbitmq="yes"], [with_librabbitmq="no (amqp.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_librabbitmq" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_librabbitmq_cppflags"
+ LDFLAGS="$LDFLAGS $with_librabbitmq_ldflags"
+
+ AC_CHECK_LIB(rabbitmq, amqp_basic_publish, [with_librabbitmq="yes"], [with_librabbitmq="no (Symbol 'amqp_basic_publish' not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_librabbitmq" = "xyes"
+then
+ BUILD_WITH_LIBRABBITMQ_CPPFLAGS="$with_librabbitmq_cppflags"
+ BUILD_WITH_LIBRABBITMQ_LDFLAGS="$with_librabbitmq_ldflags"
+ BUILD_WITH_LIBRABBITMQ_LIBS="-lrabbitmq"
+ AC_SUBST(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
+ AC_SUBST(BUILD_WITH_LIBRABBITMQ_LIBS)
+ AC_DEFINE(HAVE_LIBRABBITMQ, 1, [Define if librabbitmq is present and usable.])
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBRABBITMQ, test "x$with_librabbitmq" = "xyes")
+# }}}
+
# --with-librouteros {{{
AC_ARG_WITH(librouteros, [AS_HELP_STRING([--with-librouteros@<:@=PREFIX@:>@], [Path to librouteros.])],
[
AM_CONDITIONAL(BUILD_WITH_LIBYAJL, test "x$with_libyajl" = "xyes")
# }}}
+# --with-libvarnish {{{
+with_libvarnish_cppflags=""
+with_libvarnish_cflags=""
+with_libvarnish_libs=""
+AC_ARG_WITH(libvarnish, [AS_HELP_STRING([--with-libvarnish@<:@=PREFIX@:>@], [Path to libvarnish.])],
+[
+ if test "x$withval" = "xno"
+ then
+ with_libvarnish="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_libvarnish="use_pkgconfig"
+ else if test -d "$with_libvarnish/lib"
+ then
+ AC_MSG_NOTICE([Not checking for libvarnish: Manually configured])
+ with_libvarnish_cflags="-I$withval/include"
+ with_libvarnish_libs="-L$withval/lib -lvarnish -lvarnishcompat -lvarnishapi"
+ with_libvarnish="yes"
+ fi; fi; fi
+],
+[with_libvarnish="use_pkgconfig"])
+
+# configure using pkg-config
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+ if test "x$PKG_CONFIG" = "x"
+ then
+ with_libvarnish="no (Don't have pkg-config)"
+ fi
+fi
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+ AC_MSG_NOTICE([Checking for varnishapi using $PKG_CONFIG])
+ $PKG_CONFIG --exists 'varnishapi' 2>/dev/null
+ if test $? -ne 0
+ then
+ with_libvarnish="no (pkg-config doesn't know library)"
+ fi
+fi
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+ with_libvarnish_cflags="`$PKG_CONFIG --cflags 'varnishapi'`"
+ if test $? -ne 0
+ then
+ with_libvarnish="no ($PKG_CONFIG failed)"
+ fi
+ with_libvarnish_libs="`$PKG_CONFIG --libs 'varnishapi'`"
+ if test $? -ne 0
+ then
+ with_libvarnish="no ($PKG_CONFIG failed)"
+ fi
+fi
+if test "x$with_libvarnish" = "xuse_pkgconfig"
+then
+ with_libvarnish="yes"
+fi
+
+# with_libvarnish_cflags and with_libvarnish_libs are set up now, let's do
+# the actual checks.
+if test "x$with_libvarnish" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libvarnish_cflags"
+ AC_CHECK_HEADERS(varnish/varnishapi.h, [], [with_libvarnish="no (varnish/varnishapi.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libvarnish" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ #SAVE_LDFLAGS="$LDFLAGS"
+
+ CPPFLAGS="$CPPFLAGS $with_libvarnish_cflags"
+ #LDFLAGS="$LDFLAGS $with_libvarnish_libs"
+
+ AC_CHECK_LIB(varnishapi, VSL_OpenStats,
+ [with_libvarnish="yes"],
+ [with_libvarnish="no (symbol VSL_OpenStats not found)"],
+ [$with_libvarnish_libs])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ #LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_libvarnish" = "xyes"
+then
+ BUILD_WITH_LIBVARNISH_CFLAGS="$with_libvarnish_cflags"
+ BUILD_WITH_LIBVARNISH_LIBS="$with_libvarnish_libs"
+ AC_SUBST(BUILD_WITH_LIBVARNISH_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBVARNISH_LIBS)
+fi
+# }}}
+
# pkg-config --exists 'libxml-2.0'; pkg-config --exists libvirt {{{
with_libxml2="no (pkg-config isn't available)"
with_libxml2_cflags=""
fi
if test "x$have_sysctlbyname" = "xyes"
then
+ plugin_contextswitch="yes"
plugin_cpu="yes"
plugin_memory="yes"
plugin_tcpconns="yes"
m4_divert_once([HELP_ENABLE], [])
+AC_PLUGIN([amqp], [$with_librabbitmq], [AMQP output plugin])
AC_PLUGIN([apache], [$with_libcurl], [Apache httpd statistics])
AC_PLUGIN([apcups], [yes], [Statistics of UPSes by APC])
AC_PLUGIN([apple_sensors], [$with_libiokit], [Apple's hardware sensors])
AC_PLUGIN([libvirt], [$plugin_libvirt], [Virtual machine statistics])
AC_PLUGIN([load], [$plugin_load], [System load])
AC_PLUGIN([logfile], [yes], [File logging plugin])
+AC_PLUGIN([lpar], [$with_perfstat], [AIX logical partitions statistics])
AC_PLUGIN([madwifi], [$have_linux_wireless_h], [Madwifi wireless statistics])
AC_PLUGIN([match_empty_counter], [yes], [The empty counter match])
AC_PLUGIN([match_hashed], [yes], [The hashed match])
AC_PLUGIN([processes], [$plugin_processes], [Process statistics])
AC_PLUGIN([protocols], [$plugin_protocols], [Protocol (IP, TCP, ...) statistics])
AC_PLUGIN([python], [$with_python], [Embed a Python interpreter])
+AC_PLUGIN([redis], [$with_libcredis], [Redis plugin])
AC_PLUGIN([routeros], [$with_librouteros], [RouterOS plugin])
AC_PLUGIN([rrdcached], [$librrd_rrdc_update], [RRDTool output plugin])
AC_PLUGIN([rrdtool], [$with_librrd], [RRDTool output plugin])
AC_PLUGIN([target_replace], [yes], [The replace target])
AC_PLUGIN([target_scale],[yes], [The scale target])
AC_PLUGIN([target_set], [yes], [The set target])
+AC_PLUGIN([target_v5upgrade], [yes], [The v5upgrade target])
AC_PLUGIN([tcpconns], [$plugin_tcpconns], [TCP connection statistics])
AC_PLUGIN([teamspeak2], [yes], [TeamSpeak2 server statistics])
AC_PLUGIN([ted], [$plugin_ted], [Read The Energy Detective values])
AC_PLUGIN([uptime], [$plugin_uptime], [Uptime statistics])
AC_PLUGIN([users], [$plugin_users], [User statistics])
AC_PLUGIN([uuid], [yes], [UUID as hostname plugin])
+AC_PLUGIN([varnish], [$with_libvarnish], [Varnish cache statistics])
AC_PLUGIN([vmem], [$plugin_vmem], [Virtual memory statistics])
AC_PLUGIN([vserver], [$plugin_vserver], [Linux VServer statistics])
AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics])
AC_PLUGIN([write_http], [$with_libcurl], [HTTP output plugin])
+AC_PLUGIN([write_redis], [$with_libcredis], [Redis output plugin])
AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics])
AC_PLUGIN([zfs_arc], [$plugin_zfs_arc], [ZFS ARC statistics])
Libraries:
libcurl . . . . . . . $with_libcurl
libdbi . . . . . . . $with_libdbi
+ libcredis . . . . . . $with_libcredis
libesmtp . . . . . . $with_libesmtp
libganglia . . . . . $with_libganglia
libgcrypt . . . . . . $with_libgcrypt
libperl . . . . . . . $with_libperl
libpq . . . . . . . . $with_libpq
libpthread . . . . . $with_libpthread
+ librabbitmq . . . . . $with_librabbitmq
librouteros . . . . . $with_librouteros
librrd . . . . . . . $with_librrd
libsensors . . . . . $with_libsensors
libstatgrab . . . . . $with_libstatgrab
libtokyotyrant . . . $with_libtokyotyrant
libupsclient . . . . $with_libupsclient
+ libvarnish . . . . . $with_libvarnish
libvirt . . . . . . . $with_libvirt
libxml2 . . . . . . . $with_libxml2
libxmms . . . . . . . $with_libxmms
perl . . . . . . . . $with_perl_bindings
Modules:
+ amqp . . . . . . . $enable_amqp
apache . . . . . . . $enable_apache
apcups . . . . . . . $enable_apcups
apple_sensors . . . . $enable_apple_sensors
libvirt . . . . . . . $enable_libvirt
load . . . . . . . . $enable_load
logfile . . . . . . . $enable_logfile
+ lpar... . . . . . . . $enable_lpar
madwifi . . . . . . . $enable_madwifi
match_empty_counter . $enable_match_empty_counter
match_hashed . . . . $enable_match_hashed
processes . . . . . . $enable_processes
protocols . . . . . . $enable_protocols
python . . . . . . . $enable_python
+ redis . . . . . . . . $enable_redis
routeros . . . . . . $enable_routeros
rrdcached . . . . . . $enable_rrdcached
rrdtool . . . . . . . $enable_rrdtool
target_replace . . . $enable_target_replace
target_scale . . . . $enable_target_scale
target_set . . . . . $enable_target_set
+ target_v5upgrade . . $enable_target_v5upgrade
tcpconns . . . . . . $enable_tcpconns
teamspeak2 . . . . . $enable_teamspeak2
ted . . . . . . . . . $enable_ted
uptime . . . . . . . $enable_uptime
users . . . . . . . . $enable_users
uuid . . . . . . . . $enable_uuid
+ varnish . . . . . . . $enable_varnish
vmem . . . . . . . . $enable_vmem
vserver . . . . . . . $enable_vserver
wireless . . . . . . $enable_wireless
write_http . . . . . $enable_write_http
+ write_redis . . . . . $enable_write_redis
xmms . . . . . . . . $enable_xmms
zfs_arc . . . . . . . $enable_zfs_arc
diff --git a/contrib/exec-munin.px b/contrib/exec-munin.px
index 907ea9bccac0ad3bc68b2779216500c311d1b558..3e62ce009ae71ef16bcfe2d4ee118628e65ef26f 100755 (executable)
--- a/contrib/exec-munin.px
+++ b/contrib/exec-munin.px
our $ConfigFile = '/etc/exec-munin.conf';
our $TypeMap = {};
our $Scripts = [];
-our $Interval = 300;
+our $Interval = defined ($ENV{'COLLECTD_INTERVAL'}) ? (0 + $ENV{'COLLECTD_INTERVAL'}) : 300;
+our $Hostname = defined ($ENV{'COLLECTD_HOSTNAME'}) ? $ENV{'COLLECTD_HOSTNAME'} : '';
main ();
exit (0);
my $pinst;
my $time = time ();
my $script = shift;
- my $host = hostname () || 'localhost';
+ my $host = $Hostname || hostname () || 'localhost';
if (!open ($fh, '-|', $script))
{
print STDERR "Cannot execute $script: $!";
my $field = $1;
my $value = $2;
my $type = (defined ($TypeMap->{$field})) ? $TypeMap->{$field} : $field;
+ my $ident = "$host/munin-$pinst/$type";
- print "$host/munin-$pinst/$type interval=$Interval $time:$value\n";
+ $ident =~ s/"/\\"/g;
+
+ print qq(PUTVAL "$ident" interval=$Interval $time:$value\n);
}
}
diff --git a/contrib/exec-nagios.px b/contrib/exec-nagios.px
index 938721fc55624977fa89d5ea3a1d289531573b6d..4b112f95139aa97fc0b04b3044c528f3218837f8 100755 (executable)
--- a/contrib/exec-nagios.px
+++ b/contrib/exec-nagios.px
our $ConfigFile = '/etc/exec-nagios.conf';
our $TypeMap = {};
our $Scripts = [];
-our $Interval = 300;
+our $Interval = defined ($ENV{'COLLECTD_INTERVAL'}) ? (0 + $ENV{'COLLECTD_INTERVAL'}) : 300;
+our $Hostname = defined ($ENV{'COLLECTD_HOSTNAME'}) ? $ENV{'COLLECTD_HOSTNAME'} : '';
main ();
exit (0);
my $type = shift;
my $time = shift;
my $line = shift;
+ my $ident = "$host/$plugin-$pinst/$type-$tinst";
my $tinst;
my $value;
return;
}
- print "PUTVAL $host/$plugin-$pinst/$type-$tinst interval=$Interval ${time}:$value\n";
+ $ident =~ s/"/\\"/g;
+
+ print qq(PUTVAL "$ident" interval=$Interval ${time}:$value\n);
}
sub execute_script
my $time = time ();
my $script = shift;
my @args = ();
- my $host = hostname () || 'localhost';
+ my $host = $Hostname || hostname () || 'localhost';
my $state = 0;
my $serviceoutput;
diff --git a/contrib/exec-smartctl b/contrib/exec-smartctl
index d469816037946d34ae2daf7df5f36b91da0bfb11..99b69860b99effc5f775e68e9fbb8acbf08b7515 100755 (executable)
--- a/contrib/exec-smartctl
+++ b/contrib/exec-smartctl
# smart ALL = (root) NOPASSWD: SMARTCTL
# -- >8 --
-HOST="huhu"
-INTERVAL=60
+HOSTNAME="${COLLECTD_HOSTNAME:-`hostname -f`}"
+INTERVAL="${COLLECTD_INTERVAL:-60}"
-while true
+while sleep "$INTERVAL"
do
TEMP=$((sudo smartctl -d 3ware,0 -A /dev/twe0 | grep Temperature_Celsius | awk '{ print $10; }') 2>/dev/null);
if [ $? -ne 0 ]
then
TEMP="U"
fi
- echo "$HOST/exec-smart/temperature-3ware_0 interval=$INTERVAL N:$TEMP"
+ echo "PUTVAL $HOSTNAME/exec-smart/temperature-3ware_0 interval=$INTERVAL N:$TEMP"
TEMP=$((sudo smartctl -d 3ware,1 -A /dev/twe0 | grep Temperature_Celsius | awk '{ print $10; }') 2>/dev/null);
if [ $? -ne 0 ]
then
TEMP="U"
fi
- echo "$HOST/exec-smart/temperature-3ware_1 interval=$INTERVAL N:$TEMP"
+ echo "PUTVAL $HOSTNAME/exec-smart/temperature-3ware_1 interval=$INTERVAL N:$TEMP"
TEMP=$((sudo smartctl -d ata -A /dev/sda | grep Temperature_Celsius | awk '{ print $10; }') 2>/dev/null);
if [ $? -ne 0 ]
then
TEMP="U"
fi
- echo "$HOST/exec-smart/temperature-sata_0 interval=$INTERVAL N:$TEMP"
-
- sleep $INTERVAL
+ echo "PUTVAL $HOSTNAME/exec-smart/temperature-sata_0 interval=$INTERVAL N:$TEMP"
done
diff --git a/src/Makefile.am b/src/Makefile.am
index c6b0538d305a572b67a5ec06ff63c3506279793b..1a7ba5b1240eacbff8f3ec84eedb2747dd13e1e7 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
sbin_PROGRAMS = collectd collectdmon
-bin_PROGRAMS = collectd-nagios
+bin_PROGRAMS = collectd-nagios collectdctl
collectd_SOURCES = collectd.c collectd.h \
common.c common.h \
utils_subst.c utils_subst.h \
utils_tail.c utils_tail.h \
utils_threshold.c utils_threshold.h \
+ utils_time.c utils_time.h \
types_list.c types_list.h
collectd_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
collectd_nagios_LDADD += libcollectdclient/libcollectdclient.la
collectd_nagios_DEPENDENCIES = libcollectdclient/libcollectdclient.la
+
+collectdctl_SOURCES = collectdctl.c
+collectdctl_LDADD =
+if BUILD_WITH_LIBSOCKET
+collectdctl_LDADD += -lsocket
+endif
+if BUILD_AIX
+collectdctl_LDADD += -lm
+endif
+collectdctl_LDADD += libcollectdclient/libcollectdclient.la
+collectdctl_DEPENDENCIES = libcollectdclient/libcollectdclient.la
+
+
pkglib_LTLIBRARIES =
BUILT_SOURCES =
CLEANFILES =
+if BUILD_PLUGIN_AMQP
+pkglib_LTLIBRARIES += amqp.la
+amqp_la_SOURCES = amqp.c \
+ utils_cmd_putval.c utils_cmd_putval.h \
+ utils_format_json.c utils_format_json.h
+amqp_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
+amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
+amqp_la_LIBADD = $(BUILD_WITH_LIBRABBITMQ_LIBS)
+collectd_LDADD += "-dlopen" amqp.la
+collectd_DEPENDENCIES += amqp.la
+endif
+
if BUILD_PLUGIN_APACHE
pkglib_LTLIBRARIES += apache.la
apache_la_SOURCES = apache.c
collectd_DEPENDENCIES += logfile.la
endif
+if BUILD_PLUGIN_LPAR
+pkglib_LTLIBRARIES += lpar.la
+lpar_la_SOURCES = lpar.c
+lpar_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" lpar.la
+collectd_DEPENDENCIES += lpar.la
+lpar_la_LIBADD = -lperfstat
+endif
+
if BUILD_PLUGIN_MADWIFI
pkglib_LTLIBRARIES += madwifi.la
madwifi_la_SOURCES = madwifi.c madwifi.h
collectd_DEPENDENCIES += protocols.la
endif
+if BUILD_PLUGIN_REDIS
+pkglib_LTLIBRARIES += redis.la
+redis_la_SOURCES = redis.c
+redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
+redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+redis_la_LIBADD = -lcredis
+collectd_LDADD += "-dlopen" redis.la
+collectd_DEPENDENCIES += redis.la
+endif
+
if BUILD_PLUGIN_ROUTEROS
pkglib_LTLIBRARIES += routeros.la
routeros_la_SOURCES = routeros.c
collectd_DEPENDENCIES += target_set.la
endif
+if BUILD_PLUGIN_TARGET_V5UPGRADE
+pkglib_LTLIBRARIES += target_v5upgrade.la
+target_v5upgrade_la_SOURCES = target_v5upgrade.c
+target_v5upgrade_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" target_v5upgrade.la
+collectd_DEPENDENCIES += target_v5upgrade.la
+endif
+
if BUILD_PLUGIN_TCPCONNS
pkglib_LTLIBRARIES += tcpconns.la
tcpconns_la_SOURCES = tcpconns.c
collectd_DEPENDENCIES += uuid.la
endif
+if BUILD_PLUGIN_VARNISH
+pkglib_LTLIBRARIES += varnish.la
+varnish_la_SOURCES = varnish.c
+varnish_la_LDFLAGS = -module -avoid-version
+varnish_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBVARNISH_CFLAGS)
+varnish_la_LIBADD = $(BUILD_WITH_LIBVARNISH_LIBS)
+collectd_LDADD += "-dlopen" varnish.la
+collectd_DEPENDENCIES += varnish.la
+endif
+
if BUILD_PLUGIN_VMEM
pkglib_LTLIBRARIES += vmem.la
vmem_la_SOURCES = vmem.c
collectd_DEPENDENCIES += write_http.la
endif
+if BUILD_PLUGIN_WRITE_REDIS
+pkglib_LTLIBRARIES += write_redis.la
+write_redis_la_SOURCES = write_redis.c
+write_redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
+write_redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+write_redis_la_LIBADD = -lcredis
+collectd_LDADD += "-dlopen" write_redis.la
+collectd_DEPENDENCIES += write_redis.la
+endif
+
if BUILD_PLUGIN_XMMS
pkglib_LTLIBRARIES += xmms.la
xmms_la_SOURCES = xmms.c
collectd.conf.5 \
collectd-email.5 \
collectd-exec.5 \
+ collectdctl.1 \
collectd-java.5 \
collectdmon.1 \
collectd-nagios.1 \
EXTRA_DIST += collectd.conf.pod \
collectd-email.pod \
collectd-exec.pod \
+ collectdctl.pod \
collectd-java.pod \
collectdmon.pod \
collectd-nagios.pod \
diff --git a/src/amqp.c b/src/amqp.c
--- /dev/null
+++ b/src/amqp.c
@@ -0,0 +1,939 @@
+/**
+ * collectd - src/amqp.c
+ * Copyright (C) 2009 Sebastien Pahl
+ * Copyright (C) 2010 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Sebastien Pahl <sebastien.pahl at dotcloud.com>
+ * Florian Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_cmd_putval.h"
+#include "utils_format_json.h"
+
+#include <pthread.h>
+
+#include <amqp.h>
+#include <amqp_framing.h>
+
+/* Defines for the delivery mode. I have no idea why they're not defined by the
+ * library.. */
+#define CAMQP_DM_VOLATILE 1
+#define CAMQP_DM_PERSISTENT 2
+
+#define CAMQP_FORMAT_COMMAND 1
+#define CAMQP_FORMAT_JSON 2
+
+#define CAMQP_CHANNEL 1
+
+/*
+ * Data types
+ */
+struct camqp_config_s
+{
+ _Bool publish;
+ char *name;
+
+ char *host;
+ int port;
+ char *vhost;
+ char *user;
+ char *password;
+
+ char *exchange;
+ char *routing_key;
+
+ /* publish only */
+ uint8_t delivery_mode;
+ _Bool store_rates;
+ int format;
+
+ /* subscribe only */
+ char *exchange_type;
+ char *queue;
+
+ amqp_connection_state_t connection;
+ pthread_mutex_t lock;
+};
+typedef struct camqp_config_s camqp_config_t;
+
+/*
+ * Global variables
+ */
+static const char *def_host = "localhost";
+static const char *def_vhost = "/";
+static const char *def_user = "guest";
+static const char *def_password = "guest";
+static const char *def_exchange = "amq.fanout";
+
+static pthread_t *subscriber_threads = NULL;
+static size_t subscriber_threads_num = 0;
+static _Bool subscriber_threads_running = 1;
+
+#define CONF(c,f) (((c)->f != NULL) ? (c)->f : def_##f)
+
+/*
+ * Functions
+ */
+static void camqp_close_connection (camqp_config_t *conf) /* {{{ */
+{
+ int sockfd;
+
+ if ((conf == NULL) || (conf->connection == NULL))
+ return;
+
+ sockfd = amqp_get_sockfd (conf->connection);
+ amqp_channel_close (conf->connection, CAMQP_CHANNEL, AMQP_REPLY_SUCCESS);
+ amqp_connection_close (conf->connection, AMQP_REPLY_SUCCESS);
+ amqp_destroy_connection (conf->connection);
+ close (sockfd);
+ conf->connection = NULL;
+} /* }}} void camqp_close_connection */
+
+static void camqp_config_free (void *ptr) /* {{{ */
+{
+ camqp_config_t *conf = ptr;
+
+ if (conf == NULL)
+ return;
+
+ camqp_close_connection (conf);
+
+ sfree (conf->name);
+ sfree (conf->host);
+ sfree (conf->vhost);
+ sfree (conf->user);
+ sfree (conf->password);
+ sfree (conf->exchange);
+ sfree (conf->exchange_type);
+ sfree (conf->queue);
+ sfree (conf->routing_key);
+
+ sfree (conf);
+} /* }}} void camqp_config_free */
+
+static char *camqp_bytes_cstring (amqp_bytes_t *in) /* {{{ */
+{
+ char *ret;
+
+ if ((in == NULL) || (in->bytes == NULL))
+ return (NULL);
+
+ ret = malloc (in->len + 1);
+ if (ret == NULL)
+ return (NULL);
+
+ memcpy (ret, in->bytes, in->len);
+ ret[in->len] = 0;
+
+ return (ret);
+} /* }}} char *camqp_bytes_cstring */
+
+static _Bool camqp_is_error (camqp_config_t *conf) /* {{{ */
+{
+ amqp_rpc_reply_t r;
+
+ r = amqp_get_rpc_reply (conf->connection);
+ if (r.reply_type == AMQP_RESPONSE_NORMAL)
+ return (0);
+
+ return (1);
+} /* }}} _Bool camqp_is_error */
+
+static char *camqp_strerror (camqp_config_t *conf, /* {{{ */
+ char *buffer, size_t buffer_size)
+{
+ amqp_rpc_reply_t r;
+
+ r = amqp_get_rpc_reply (conf->connection);
+ switch (r.reply_type)
+ {
+ case AMQP_RESPONSE_NORMAL:
+ sstrncpy (buffer, "Success", sizeof (buffer));
+ break;
+
+ case AMQP_RESPONSE_NONE:
+ sstrncpy (buffer, "Missing RPC reply type", sizeof (buffer));
+ break;
+
+ case AMQP_RESPONSE_LIBRARY_EXCEPTION:
+ if (r.library_errno)
+ return (sstrerror (r.library_errno, buffer, buffer_size));
+ else
+ sstrncpy (buffer, "End of stream", sizeof (buffer));
+ break;
+
+ case AMQP_RESPONSE_SERVER_EXCEPTION:
+ if (r.reply.id == AMQP_CONNECTION_CLOSE_METHOD)
+ {
+ amqp_connection_close_t *m = r.reply.decoded;
+ char *tmp = camqp_bytes_cstring (&m->reply_text);
+ ssnprintf (buffer, buffer_size, "Server connection error %d: %s",
+ m->reply_code, tmp);
+ sfree (tmp);
+ }
+ else if (r.reply.id == AMQP_CHANNEL_CLOSE_METHOD)
+ {
+ amqp_channel_close_t *m = r.reply.decoded;
+ char *tmp = camqp_bytes_cstring (&m->reply_text);
+ ssnprintf (buffer, buffer_size, "Server channel error %d: %s",
+ m->reply_code, tmp);
+ sfree (tmp);
+ }
+ else
+ {
+ ssnprintf (buffer, buffer_size, "Server error method %#"PRIx32,
+ r.reply.id);
+ }
+ break;
+
+ default:
+ ssnprintf (buffer, buffer_size, "Unknown reply type %i",
+ (int) r.reply_type);
+ }
+
+ return (buffer);
+} /* }}} char *camqp_strerror */
+
+static int camqp_create_exchange (camqp_config_t *conf) /* {{{ */
+{
+ amqp_exchange_declare_ok_t *ed_ret;
+
+ if (conf->exchange_type == NULL)
+ return (0);
+
+ ed_ret = amqp_exchange_declare (conf->connection,
+ /* channel = */ CAMQP_CHANNEL,
+ /* exchange = */ amqp_cstring_bytes (conf->exchange),
+ /* type = */ amqp_cstring_bytes (conf->exchange_type),
+ /* passive = */ 0,
+ /* durable = */ 0,
+ /* auto_delete = */ 1,
+ /* arguments = */ AMQP_EMPTY_TABLE);
+ if ((ed_ret == NULL) && camqp_is_error (conf))
+ {
+ char errbuf[1024];
+ ERROR ("amqp plugin: amqp_exchange_declare failed: %s",
+ camqp_strerror (conf, errbuf, sizeof (errbuf)));
+ camqp_close_connection (conf);
+ return (-1);
+ }
+
+ INFO ("amqp plugin: Successfully created exchange \"%s\" "
+ "with type \"%s\".",
+ conf->exchange, conf->exchange_type);
+
+ return (0);
+} /* }}} int camqp_create_exchange */
+
+static int camqp_setup_queue (camqp_config_t *conf) /* {{{ */
+{
+ amqp_queue_declare_ok_t *qd_ret;
+ amqp_basic_consume_ok_t *cm_ret;
+
+ qd_ret = amqp_queue_declare (conf->connection,
+ /* channel = */ CAMQP_CHANNEL,
+ /* queue = */ (conf->queue != NULL)
+ ? amqp_cstring_bytes (conf->queue)
+ : AMQP_EMPTY_BYTES,
+ /* passive = */ 0,
+ /* durable = */ 0,
+ /* exclusive = */ 0,
+ /* auto_delete = */ 1,
+ /* arguments = */ AMQP_EMPTY_TABLE);
+ if (qd_ret == NULL)
+ {
+ ERROR ("amqp plugin: amqp_queue_declare failed.");
+ camqp_close_connection (conf);
+ return (-1);
+ }
+
+ if (conf->queue == NULL)
+ {
+ conf->queue = camqp_bytes_cstring (&qd_ret->queue);
+ if (conf->queue == NULL)
+ {
+ ERROR ("amqp plugin: camqp_bytes_cstring failed.");
+ camqp_close_connection (conf);
+ return (-1);
+ }
+
+ INFO ("amqp plugin: Created queue \"%s\".", conf->queue);
+ }
+ DEBUG ("amqp plugin: Successfully created queue \"%s\".", conf->queue);
+
+ /* bind to an exchange */
+ if (conf->exchange != NULL)
+ {
+ amqp_queue_bind_ok_t *qb_ret;
+
+ assert (conf->queue != NULL);
+ qb_ret = amqp_queue_bind (conf->connection,
+ /* channel = */ CAMQP_CHANNEL,
+ /* queue = */ amqp_cstring_bytes (conf->queue),
+ /* exchange = */ amqp_cstring_bytes (conf->exchange),
+ /* routing_key = */ (conf->routing_key != NULL)
+ ? amqp_cstring_bytes (conf->routing_key)
+ : AMQP_EMPTY_BYTES,
+ /* arguments = */ AMQP_EMPTY_TABLE);
+ if ((qb_ret == NULL) && camqp_is_error (conf))
+ {
+ char errbuf[1024];
+ ERROR ("amqp plugin: amqp_queue_bind failed: %s",
+ camqp_strerror (conf, errbuf, sizeof (errbuf)));
+ camqp_close_connection (conf);
+ return (-1);
+ }
+
+ DEBUG ("amqp plugin: Successfully bound queue \"%s\" to exchange \"%s\".",
+ conf->queue, conf->exchange);
+ } /* if (conf->exchange != NULL) */
+
+ cm_ret = amqp_basic_consume (conf->connection,
+ /* channel = */ CAMQP_CHANNEL,
+ /* queue = */ amqp_cstring_bytes (conf->queue),
+ /* consumer_tag = */ AMQP_EMPTY_BYTES,
+ /* no_local = */ 0,
+ /* no_ack = */ 1,
+ /* exclusive = */ 0);
+ if ((cm_ret == NULL) && camqp_is_error (conf))
+ {
+ char errbuf[1024];
+ ERROR ("amqp plugin: amqp_basic_consume failed: %s",
+ camqp_strerror (conf, errbuf, sizeof (errbuf)));
+ camqp_close_connection (conf);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int camqp_setup_queue */
+
+static int camqp_connect (camqp_config_t *conf) /* {{{ */
+{
+ amqp_rpc_reply_t reply;
+ int sockfd;
+ int status;
+
+ if (conf->connection != NULL)
+ return (0);
+
+ conf->connection = amqp_new_connection ();
+ if (conf->connection == NULL)
+ {
+ ERROR ("amqp plugin: amqp_new_connection failed.");
+ return (ENOMEM);
+ }
+
+ sockfd = amqp_open_socket (CONF(conf, host), conf->port);
+ if (sockfd < 0)
+ {
+ char errbuf[1024];
+ status = (-1) * sockfd;
+ ERROR ("amqp plugin: amqp_open_socket failed: %s",
+ sstrerror (status, errbuf, sizeof (errbuf)));
+ amqp_destroy_connection (conf->connection);
+ conf->connection = NULL;
+ return (status);
+ }
+ amqp_set_sockfd (conf->connection, sockfd);
+
+ reply = amqp_login (conf->connection, CONF(conf, vhost),
+ /* channel max = */ 0,
+ /* frame max = */ 131072,
+ /* heartbeat = */ 0,
+ /* authentication = */ AMQP_SASL_METHOD_PLAIN,
+ CONF(conf, user), CONF(conf, password));
+ if (reply.reply_type != AMQP_RESPONSE_NORMAL)
+ {
+ ERROR ("amqp plugin: amqp_login (vhost = %s, user = %s) failed.",
+ CONF(conf, vhost), CONF(conf, user));
+ amqp_destroy_connection (conf->connection);
+ close (sockfd);
+ conf->connection = NULL;
+ return (1);
+ }
+
+ amqp_channel_open (conf->connection, /* channel = */ 1);
+ /* FIXME: Is checking "reply.reply_type" really correct here? How does
+ * it get set? --octo */
+ if (reply.reply_type != AMQP_RESPONSE_NORMAL)
+ {
+ ERROR ("amqp plugin: amqp_channel_open failed.");
+ amqp_connection_close (conf->connection, AMQP_REPLY_SUCCESS);
+ amqp_destroy_connection (conf->connection);
+ close(sockfd);
+ conf->connection = NULL;
+ return (1);
+ }
+
+ INFO ("amqp plugin: Successfully opened connection to vhost \"%s\" "
+ "on %s:%i.", CONF(conf, vhost), CONF(conf, host), conf->port);
+
+ status = camqp_create_exchange (conf);
+ if (status != 0)
+ return (status);
+
+ if (!conf->publish)
+ return (camqp_setup_queue (conf));
+ return (0);
+} /* }}} int camqp_connect */
+
+static int camqp_shutdown (void) /* {{{ */
+{
+ size_t i;
+
+ DEBUG ("amqp plugin: Shutting down %zu subscriber threads.",
+ subscriber_threads_num);
+
+ subscriber_threads_running = 0;
+ for (i = 0; i < subscriber_threads_num; i++)
+ {
+ /* FIXME: Sending a signal is not very elegant here. Maybe find out how
+ * to use a timeout in the thread and check for the variable in regular
+ * intervals. */
+ pthread_kill (subscriber_threads[i], SIGTERM);
+ pthread_join (subscriber_threads[i], /* retval = */ NULL);
+ }
+
+ subscriber_threads_num = 0;
+ sfree (subscriber_threads);
+
+ DEBUG ("amqp plugin: All subscriber threads exited.");
+
+ return (0);
+} /* }}} int camqp_shutdown */
+
+/*
+ * Subscribing code
+ */
+static int camqp_read_body (camqp_config_t *conf, /* {{{ */
+ size_t body_size, const char *content_type)
+{
+ char body[body_size + 1];
+ char *body_ptr;
+ size_t received;
+ amqp_frame_t frame;
+ int status;
+
+ memset (body, 0, sizeof (body));
+ body_ptr = &body[0];
+ received = 0;
+
+ while (received < body_size)
+ {
+ status = amqp_simple_wait_frame (conf->connection, &frame);
+ if (status < 0)
+ {
+ char errbuf[1024];
+ status = (-1) * status;
+ ERROR ("amqp plugin: amqp_simple_wait_frame failed: %s",
+ sstrerror (status, errbuf, sizeof (errbuf)));
+ camqp_close_connection (conf);
+ return (status);
+ }
+
+ if (frame.frame_type != AMQP_FRAME_BODY)
+ {
+ NOTICE ("amqp plugin: Unexpected frame type: %#"PRIx8,
+ frame.frame_type);
+ return (-1);
+ }
+
+ if ((body_size - received) < frame.payload.body_fragment.len)
+ {
+ WARNING ("amqp plugin: Body is larger than indicated by header.");
+ return (-1);
+ }
+
+ memcpy (body_ptr, frame.payload.body_fragment.bytes,
+ frame.payload.body_fragment.len);
+ body_ptr += frame.payload.body_fragment.len;
+ received += frame.payload.body_fragment.len;
+ } /* while (received < body_size) */
+
+ if (strcasecmp ("text/collectd", content_type) == 0)
+ {
+ status = handle_putval (stderr, body);
+ if (status != 0)
+ ERROR ("amqp plugin: handle_putval failed with status %i.",
+ status);
+ return (status);
+ }
+ else if (strcasecmp ("application/json", content_type) == 0)
+ {
+ ERROR ("amqp plugin: camqp_read_body: Parsing JSON data has not "
+ "been implemented yet. FIXME!");
+ return (0);
+ }
+ else
+ {
+ ERROR ("amqp plugin: camqp_read_body: Unknown content type \"%s\".",
+ content_type);
+ return (EINVAL);
+ }
+
+ /* not reached */
+ return (0);
+} /* }}} int camqp_read_body */
+
+static int camqp_read_header (camqp_config_t *conf) /* {{{ */
+{
+ int status;
+ amqp_frame_t frame;
+ amqp_basic_properties_t *properties;
+ char *content_type;
+
+ status = amqp_simple_wait_frame (conf->connection, &frame);
+ if (status < 0)
+ {
+ char errbuf[1024];
+ status = (-1) * status;
+ ERROR ("amqp plugin: amqp_simple_wait_frame failed: %s",
+ sstrerror (status, errbuf, sizeof (errbuf)));
+ camqp_close_connection (conf);
+ return (status);
+ }
+
+ if (frame.frame_type != AMQP_FRAME_HEADER)
+ {
+ NOTICE ("amqp plugin: Unexpected frame type: %#"PRIx8,
+ frame.frame_type);
+ return (-1);
+ }
+
+ properties = frame.payload.properties.decoded;
+ content_type = camqp_bytes_cstring (&properties->content_type);
+ if (content_type == NULL)
+ {
+ ERROR ("amqp plugin: Unable to determine content type.");
+ return (-1);
+ }
+
+ status = camqp_read_body (conf,
+ (size_t) frame.payload.properties.body_size,
+ content_type);
+
+ sfree (content_type);
+ return (status);
+} /* }}} int camqp_read_header */
+
+static void *camqp_subscribe_thread (void *user_data) /* {{{ */
+{
+ camqp_config_t *conf = user_data;
+ int status;
+
+ while (subscriber_threads_running)
+ {
+ amqp_frame_t frame;
+
+ status = camqp_connect (conf);
+ if (status != 0)
+ {
+ ERROR ("amqp plugin: camqp_connect failed. "
+ "Will sleep for %i seconds.", interval_g);
+ sleep (interval_g);
+ continue;
+ }
+
+ status = amqp_simple_wait_frame (conf->connection, &frame);
+ if (status < 0)
+ {
+ ERROR ("amqp plugin: amqp_simple_wait_frame failed. "
+ "Will sleep for %i seconds.", interval_g);
+ camqp_close_connection (conf);
+ sleep (interval_g);
+ continue;
+ }
+
+ if (frame.frame_type != AMQP_FRAME_METHOD)
+ {
+ DEBUG ("amqp plugin: Unexpected frame type: %#"PRIx8,
+ frame.frame_type);
+ continue;
+ }
+
+ if (frame.payload.method.id != AMQP_BASIC_DELIVER_METHOD)
+ {
+ DEBUG ("amqp plugin: Unexpected method id: %#"PRIx32,
+ frame.payload.method.id);
+ continue;
+ }
+
+ status = camqp_read_header (conf);
+
+ amqp_maybe_release_buffers (conf->connection);
+ } /* while (subscriber_threads_running) */
+
+ camqp_config_free (conf);
+ pthread_exit (NULL);
+} /* }}} void *camqp_subscribe_thread */
+
+static int camqp_subscribe_init (camqp_config_t *conf) /* {{{ */
+{
+ int status;
+ pthread_t *tmp;
+
+ tmp = realloc (subscriber_threads,
+ sizeof (*subscriber_threads) * (subscriber_threads_num + 1));
+ if (tmp == NULL)
+ {
+ ERROR ("amqp plugin: realloc failed.");
+ camqp_config_free (conf);
+ return (ENOMEM);
+ }
+ subscriber_threads = tmp;
+ tmp = subscriber_threads + subscriber_threads_num;
+ memset (tmp, 0, sizeof (*tmp));
+
+ status = pthread_create (tmp, /* attr = */ NULL,
+ camqp_subscribe_thread, conf);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("amqp plugin: pthread_create failed: %s",
+ sstrerror (status, errbuf, sizeof (errbuf)));
+ camqp_config_free (conf);
+ return (status);
+ }
+
+ subscriber_threads_num++;
+
+ return (0);
+} /* }}} int camqp_subscribe_init */
+
+/*
+ * Publishing code
+ */
+/* XXX: You must hold "conf->lock" when calling this function! */
+static int camqp_write_locked (camqp_config_t *conf, /* {{{ */
+ const char *buffer, const char *routing_key)
+{
+ amqp_basic_properties_t props;
+ int status;
+
+ status = camqp_connect (conf);
+ if (status != 0)
+ return (status);
+
+ memset (&props, 0, sizeof (props));
+ props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG
+ | AMQP_BASIC_DELIVERY_MODE_FLAG
+ | AMQP_BASIC_APP_ID_FLAG;
+ if (conf->format == CAMQP_FORMAT_COMMAND)
+ props.content_type = amqp_cstring_bytes("text/collectd");
+ else if (conf->format == CAMQP_FORMAT_JSON)
+ props.content_type = amqp_cstring_bytes("application/json");
+ else
+ assert (23 == 42);
+ props.delivery_mode = conf->delivery_mode;
+ props.app_id = amqp_cstring_bytes("collectd");
+
+ status = amqp_basic_publish(conf->connection,
+ /* channel = */ 1,
+ amqp_cstring_bytes(CONF(conf, exchange)),
+ amqp_cstring_bytes (routing_key),
+ /* mandatory = */ 0,
+ /* immediate = */ 0,
+ &props,
+ amqp_cstring_bytes(buffer));
+ if (status != 0)
+ {
+ ERROR ("amqp plugin: amqp_basic_publish failed with status %i.",
+ status);
+ camqp_close_connection (conf);
+ }
+
+ return (status);
+} /* }}} int camqp_write_locked */
+
+static int camqp_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
+ user_data_t *user_data)
+{
+ camqp_config_t *conf = user_data->data;
+ char routing_key[6 * DATA_MAX_NAME_LEN];
+ char buffer[4096];
+ int status;
+
+ if ((ds == NULL) || (vl == NULL) || (conf == NULL))
+ return (EINVAL);
+
+ memset (buffer, 0, sizeof (buffer));
+
+ if (conf->routing_key != NULL)
+ {
+ sstrncpy (routing_key, conf->routing_key, sizeof (routing_key));
+ }
+ else
+ {
+ size_t i;
+ ssnprintf (routing_key, sizeof (routing_key), "collectd/%s/%s/%s/%s/%s",
+ vl->host,
+ vl->plugin, vl->plugin_instance,
+ vl->type, vl->type_instance);
+
+ /* Switch slashes (the only character forbidden by collectd) and dots
+ * (the separation character used by AMQP). */
+ for (i = 0; routing_key[i] != 0; i++)
+ {
+ if (routing_key[i] == '.')
+ routing_key[i] = '/';
+ else if (routing_key[i] == '/')
+ routing_key[i] = '.';
+ }
+ }
+
+ if (conf->format == CAMQP_FORMAT_COMMAND)
+ {
+ status = create_putval (buffer, sizeof (buffer), ds, vl);
+ if (status != 0)
+ {
+ ERROR ("amqp plugin: create_putval failed with status %i.",
+ status);
+ return (status);
+ }
+ }
+ else if (conf->format == CAMQP_FORMAT_JSON)
+ {
+ size_t bfree = sizeof (buffer);
+ size_t bfill = 0;
+
+ format_json_initialize (buffer, &bfill, &bfree);
+ format_json_value_list (buffer, &bfill, &bfree, ds, vl, conf->store_rates);
+ format_json_finalize (buffer, &bfill, &bfree);
+ }
+ else
+ {
+ ERROR ("amqp plugin: Invalid format (%i).", conf->format);
+ return (-1);
+ }
+
+ pthread_mutex_lock (&conf->lock);
+ status = camqp_write_locked (conf, buffer, routing_key);
+ pthread_mutex_unlock (&conf->lock);
+
+ return (status);
+} /* }}} int camqp_write */
+
+/*
+ * Config handling
+ */
+static int camqp_config_set_format (oconfig_item_t *ci, /* {{{ */
+ camqp_config_t *conf)
+{
+ char *string;
+ int status;
+
+ string = NULL;
+ status = cf_util_get_string (ci, &string);
+ if (status != 0)
+ return (status);
+
+ assert (string != NULL);
+ if (strcasecmp ("Command", string) == 0)
+ conf->format = CAMQP_FORMAT_COMMAND;
+ else if (strcasecmp ("JSON", string) == 0)
+ conf->format = CAMQP_FORMAT_JSON;
+ else
+ {
+ WARNING ("amqp plugin: Invalid format string: %s",
+ string);
+ }
+
+ free (string);
+
+ return (0);
+} /* }}} int config_set_string */
+
+static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */
+ _Bool publish)
+{
+ camqp_config_t *conf;
+ int status;
+ int i;
+
+ conf = malloc (sizeof (*conf));
+ if (conf == NULL)
+ {
+ ERROR ("amqp plugin: malloc failed.");
+ return (ENOMEM);
+ }
+
+ /* Initialize "conf" {{{ */
+ memset (conf, 0, sizeof (*conf));
+ conf->publish = publish;
+ conf->name = NULL;
+ conf->format = CAMQP_FORMAT_COMMAND;
+ conf->host = NULL;
+ conf->port = 5672;
+ conf->vhost = NULL;
+ conf->user = NULL;
+ conf->password = NULL;
+ conf->exchange = NULL;
+ conf->routing_key = NULL;
+ /* publish only */
+ conf->delivery_mode = CAMQP_DM_VOLATILE;
+ conf->store_rates = 0;
+ /* subscribe only */
+ conf->exchange_type = NULL;
+ conf->queue = NULL;
+ /* general */
+ conf->connection = NULL;
+ pthread_mutex_init (&conf->lock, /* attr = */ NULL);
+ /* }}} */
+
+ status = cf_util_get_string (ci, &conf->name);
+ if (status != 0)
+ {
+ sfree (conf);
+ return (status);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Host", child->key) == 0)
+ status = cf_util_get_string (child, &conf->host);
+ else if (strcasecmp ("Port", child->key) == 0)
+ {
+ status = cf_util_get_port_number (child);
+ if (status > 0)
+ {
+ conf->port = status;
+ status = 0;
+ }
+ }
+ else if (strcasecmp ("VHost", child->key) == 0)
+ status = cf_util_get_string (child, &conf->vhost);
+ else if (strcasecmp ("User", child->key) == 0)
+ status = cf_util_get_string (child, &conf->user);
+ else if (strcasecmp ("Password", child->key) == 0)
+ status = cf_util_get_string (child, &conf->password);
+ else if (strcasecmp ("Exchange", child->key) == 0)
+ status = cf_util_get_string (child, &conf->exchange);
+ else if ((strcasecmp ("ExchangeType", child->key) == 0) && !publish)
+ status = cf_util_get_string (child, &conf->exchange_type);
+ else if ((strcasecmp ("Queue", child->key) == 0) && !publish)
+ status = cf_util_get_string (child, &conf->queue);
+ else if (strcasecmp ("RoutingKey", child->key) == 0)
+ status = cf_util_get_string (child, &conf->routing_key);
+ else if ((strcasecmp ("Persistent", child->key) == 0) && publish)
+ {
+ _Bool tmp = 0;
+ status = cf_util_get_boolean (child, &tmp);
+ if (tmp)
+ conf->delivery_mode = CAMQP_DM_PERSISTENT;
+ else
+ conf->delivery_mode = CAMQP_DM_VOLATILE;
+ }
+ else if ((strcasecmp ("StoreRates", child->key) == 0) && publish)
+ status = cf_util_get_boolean (child, &conf->store_rates);
+ else if ((strcasecmp ("Format", child->key) == 0) && publish)
+ status = camqp_config_set_format (child, conf);
+ else
+ WARNING ("amqp plugin: Ignoring unknown "
+ "configuration option \"%s\".", child->key);
+
+ if (status != 0)
+ break;
+ } /* for (i = 0; i < ci->children_num; i++) */
+
+ if ((status == 0) && (conf->exchange == NULL))
+ {
+ if (conf->exchange_type != NULL)
+ WARNING ("amqp plugin: The option \"ExchangeType\" was given "
+ "without the \"Exchange\" option. It will be ignored.");
+
+ if (!publish && (conf->routing_key != NULL))
+ WARNING ("amqp plugin: The option \"RoutingKey\" was given "
+ "without the \"Exchange\" option. It will be ignored.");
+
+ }
+
+ if (status != 0)
+ {
+ camqp_config_free (conf);
+ return (status);
+ }
+
+ if (conf->exchange != NULL)
+ {
+ DEBUG ("amqp plugin: camqp_config_connection: exchange = %s;",
+ conf->exchange);
+ }
+
+ if (publish)
+ {
+ char cbname[128];
+ user_data_t ud = { conf, camqp_config_free };
+
+ ssnprintf (cbname, sizeof (cbname), "amqp/%s", conf->name);
+
+ status = plugin_register_write (cbname, camqp_write, &ud);
+ if (status != 0)
+ {
+ camqp_config_free (conf);
+ return (status);
+ }
+ }
+ else
+ {
+ status = camqp_subscribe_init (conf);
+ if (status != 0)
+ {
+ camqp_config_free (conf);
+ return (status);
+ }
+ }
+
+ return (0);
+} /* }}} int camqp_config_connection */
+
+static int camqp_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Publish", child->key) == 0)
+ camqp_config_connection (child, /* publish = */ 1);
+ else if (strcasecmp ("Subscribe", child->key) == 0)
+ camqp_config_connection (child, /* publish = */ 0);
+ else
+ WARNING ("amqp plugin: Ignoring unknown config option \"%s\".",
+ child->key);
+ } /* for (ci->children_num) */
+
+ return (0);
+} /* }}} int camqp_config */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("amqp", camqp_config);
+ plugin_register_shutdown ("amqp", camqp_shutdown);
+} /* void module_register */
+
+/* vim: set sw=4 sts=4 et fdm=marker : */
diff --git a/src/apache.c b/src/apache.c
index 3d6d957c5c2a721a3ce328fd19e27c2439e39a8c..506ba84ec23e58d9396e9165454c3a08a6e33be3 100644 (file)
--- a/src/apache.c
+++ b/src/apache.c
/**
* collectd - src/apache.c
- * Copyright (C) 2006-2009 Florian octo Forster
+ * Copyright (C) 2006-2010 Florian octo Forster
* Copyright (C) 2007 Florent EppO Monbillard
* Copyright (C) 2009 Amit Gupta
*
st->server_type = APACHE;
else if (strstr (buf, "lighttpd") != NULL)
st->server_type = LIGHTTPD;
+ else if (strstr (buf, "IBM_HTTP_Server") != NULL)
+ st->server_type = APACHE;
else
{
const char *hdr = buf;
{
int status = 0;
int i;
- oconfig_item_t *lci = NULL; /* legacy config */
for (i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
- if (strcasecmp ("Instance", child->key) == 0 && child->children_num > 0)
+ if (strcasecmp ("Instance", child->key) == 0)
config_add (child);
else
- {
- /* legacy mode - convert to <Instance ...> config */
- if (lci == NULL)
- {
- lci = malloc (sizeof(*lci));
- if (lci == NULL)
- {
- ERROR ("apache plugin: malloc failed.");
- return (-1);
- }
- memset (lci, '\0', sizeof (*lci));
- }
-
- lci->children_num++;
- lci->children =
- realloc (lci->children,
- lci->children_num * sizeof (*child));
- if (lci->children == NULL)
- {
- ERROR ("apache plugin: realloc failed.");
- return (-1);
- }
- memcpy (&lci->children[lci->children_num-1], child, sizeof (*child));
- }
+ WARNING ("apache plugin: The configuration option "
+ "\"%s\" is not allowed here. Did you "
+ "forget to add an <Instance /> block "
+ "around the configuration?",
+ child->key);
} /* for (ci->children) */
- if (lci)
- {
- /* create a <Instance ""> entry */
- lci->key = "Instance";
- lci->values_num = 1;
- lci->values = (oconfig_value_t *) malloc (lci->values_num * sizeof (oconfig_value_t));
- lci->values[0].type = OCONFIG_TYPE_STRING;
- lci->values[0].value.string = "";
-
- status = config_add (lci);
- sfree (lci->values);
- sfree (lci->children);
- sfree (lci);
- }
-
- return status;
+ return (status);
} /* int config */
/* initialize curl for each host */
st->server_type = APACHE;
else if (strcasecmp(st->server, "lighttpd") == 0)
st->server_type = LIGHTTPD;
+ else if (strcasecmp(st->server, "ibm_http_server") == 0)
+ st->server_type = APACHE;
else
WARNING ("apache plugin: Unknown `Server' setting: %s",
st->server);
diff --git a/src/bind.c b/src/bind.c
index 6e0b907f1e89203150a554b76ea0fc93312de211..47215c74bae0b6422d058dd5697a9d1fc180f0b6 100644 (file)
--- a/src/bind.c
+++ b/src/bind.c
vl.values = values;
vl.values_len = 1;
- vl.time = ts;
+ vl.time = TIME_T_TO_CDTIME_T (ts);
sstrncpy(vl.host, hostname_g, sizeof(vl.host));
sstrncpy(vl.plugin, "bind", sizeof(vl.plugin));
if (plugin_instance) {
diff --git a/src/collectd-exec.pod b/src/collectd-exec.pod
index 81b3a2ecc07ecb11302b7ede4d2e26f87e72f0d8..10f68290e9bbc8ae8c7479364068f0b3ccae5b30 100644 (file)
--- a/src/collectd-exec.pod
+++ b/src/collectd-exec.pod
The user, the binary is executed as, may not have root privileges, i.E<nbsp>e.
must have an UID that is non-zero. This is for your own good.
+=item
+
+Early versions of the plugin did not use a command but treated all lines as if
+they were arguments to the I<PUTVAL> command. When the I<PUTNOTIF> command was
+implemented, this behavior was kept for lines which start with an unknown
+command for backwards compatibility. This compatibility code has been removed
+in I<collectdE<nbsp>5>.
+
=back
=head1 SEE ALSO
diff --git a/src/collectd-java.pod b/src/collectd-java.pod
index 9c0c6eba1646cf771bea4bdf80b327b203723980..9e2f81aa9b9f0056d3aefa215605688b47f8ae81 100644 (file)
--- a/src/collectd-java.pod
+++ b/src/collectd-java.pod
Use I<password> to authenticate to the server. If not given, unauthenticated
access is used.
+=item B<InstancePrefix> I<prefix>
+
+Prefixes the generated I<plugin instance> with I<prefix>. If a second
+I<InstancePrefix> is specified in a referenced I<MBean> block, the prefix
+specified in the I<Connection> block will appear at the beginning of the
+I<plugin instance>, the prefix specified in the I<MBean> block will be appended
+to it.
+
=item B<Collect> I<mbean_block_name>
Configures which of the I<MBean> blocks to use with this connection. May be
diff --git a/src/collectd-nagios.c b/src/collectd-nagios.c
index 45162bd3de607170e3b34399e078b851fd4a58bd..b3c1855aba2be7d98a3c112b62b5ddbebe33f609 100644 (file)
--- a/src/collectd-nagios.c
+++ b/src/collectd-nagios.c
/**
* collectd-nagios - src/collectd-nagios.c
- * Copyright (C) 2008 Florian octo Forster
+ * Copyright (C) 2008-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
# include "config.h"
#endif
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+
#if !defined(__GNUC__) || !__GNUC__
# define __attribute__(x) /**/
#endif
#include <string.h>
#include <strings.h>
#include <assert.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <math.h>
#include "libcollectdclient/client.h"
-/*
- * This is copied directly from collectd.h. Make changes there!
- */
-#if NAN_STATIC_DEFAULT
-# include <math.h>
-/* #endif NAN_STATIC_DEFAULT*/
-#elif NAN_STATIC_ISOC
-# ifndef __USE_ISOC99
-# define DISABLE_ISOC99 1
-# define __USE_ISOC99 1
-# endif /* !defined(__USE_ISOC99) */
-# include <math.h>
-# if DISABLE_ISOC99
-# undef DISABLE_ISOC99
-# undef __USE_ISOC99
-# endif /* DISABLE_ISOC99 */
-/* #endif NAN_STATIC_ISOC */
-#elif NAN_ZERO_ZERO
-# include <math.h>
-# ifdef NAN
-# undef NAN
-# endif
-# define NAN (0.0 / 0.0)
-# ifndef isnan
-# define isnan(f) ((f) != (f))
-# endif /* !defined(isnan) */
-#endif /* NAN_ZERO_ZERO */
-
#define RET_OKAY 0
#define RET_WARNING 1
#define RET_CRITICAL 2
static range_t range_critical_g;
static range_t range_warning_g;
static int consolitation_g = CON_NONE;
+static _Bool nan_is_error_g = 0;
static char **match_ds_g = NULL;
static int match_ds_num_g = 0;
" -H <host> Hostname to query the values for.\n"
" -c <range> Critical range\n"
" -w <range> Warning range\n"
+ " -m Treat \"Not a Number\" (NaN) as critical (default: warning)\n"
"\n"
"Consolidation functions:\n"
" none: Apply the warning- and critical-ranges to each data-source\n"
for (i = 0; i < values_num; i++)
{
if (isnan (values[i]))
- num_warning++;
+ {
+ if (nan_is_error_g)
+ num_critical++;
+ else
+ num_warning++;
+ }
else if (match_range (&range_critical_g, values[i]) != 0)
num_critical++;
else if (match_range (&range_warning_g, values[i]) != 0)
total_num = 0;
for (i = 0; i < values_num; i++)
{
- if (!isnan (values[i]))
+ if (isnan (values[i]))
{
- total += values[i];
- total_num++;
+ if (!nan_is_error_g)
+ continue;
+
+ printf ("CRITICAL: Data source \"%s\" is NaN\n",
+ values_names[i]);
+ return (RET_CRITICAL);
}
+
+ total += values[i];
+ total_num++;
}
if (total_num == 0)
total_num = 0;
for (i = 0; i < values_num; i++)
{
- if (!isnan (values[i]))
+ if (isnan (values[i]))
{
- total += values[i];
- total_num++;
+ if (!nan_is_error_g)
+ continue;
+
+ printf ("CRITICAL: Data source \"%s\" is NaN\n",
+ values_names[i]);
+ return (RET_CRITICAL);
}
+
+ total += values[i];
+ total_num++;
}
if (total_num == 0)
}
for (i = 0; i < values_num; i++)
- if (!isnan (values[i]))
- sum += values[i];
+ {
+ if (isnan (values[i]))
+ {
+ if (!nan_is_error_g)
+ continue;
+
+ printf ("CRITICAL: Data source \"%s\" is NaN\n",
+ values_names[i]);
+ return (RET_CRITICAL);
+ }
+
+ sum += values[i];
+ }
if (sum == 0.0)
{
{
int c;
- c = getopt (argc, argv, "w:c:s:n:H:g:d:h");
+ c = getopt (argc, argv, "w:c:s:n:H:g:d:hm");
if (c < 0)
break;
match_ds_num_g++;
break;
}
+ case 'm':
+ nan_is_error_g = 1;
+ break;
default:
usage (argv[0]);
} /* switch (c) */
index c6347eac9361746c8f60b6b33713983d466da241..d7c749cd3391aefc86369c208193063111655fe6 100644 (file)
--- a/src/collectd-nagios.pod
+++ b/src/collectd-nagios.pod
I<min> is then assumed to be zero. If I<max> (but not the trailing colon) is
omitted, I<max> is assumed to be positive infinity.
+=item B<-m>
+
+If this option is given, "Not a Number" (NaN) is treated as I<critical>. By
+default, the I<none> consolidation reports NaNs as I<warning>. Other
+consolidations simply ignore NaN values.
+
=back
=head1 RETURN VALUE
diff --git a/src/collectd-perl.pod b/src/collectd-perl.pod
index 5c11b65281cea66df6cf786f102e7abbb363ee0a..6b44722cfe808605603a549ac3690c5998bb1eb7 100644 (file)
--- a/src/collectd-perl.pod
+++ b/src/collectd-perl.pod
@@ -376,11 +376,6 @@ is found (and the number of values matches the number of data-sources) then the
type, data-set and value-list is passed to all write-callbacks that are
registered with the daemon.
-B<Note>: Prior to version 4.4 of collectd, the data-set type used to be passed
-as the first argument to B<plugin_register>. This syntax is still supported
-for backwards compatibility but has been deprecated and will be removed in
-some future version of collectd.
-
=item B<plugin_write> ([B<plugins> => I<...>][, B<datasets> => I<...>],
B<valuelists> => I<...>)
the B<plugins> and B<identifiers> arguments may either be a string or a
reference to an array of strings.
-=item B<plugin_flush_one> (I<timeout>, I<plugin>)
-
-This is identical to using "plugin_flush (timeout =E<gt> I<timeout>, plugins
-=E<gt> I<plugin>".
-
-B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_one> has been
-deprecated and will be removed in some future version of collectd. Use
-B<plugin_flush> instead.
-
-=item B<plugin_flush_all> (I<timeout>)
-
-This is identical to using "plugin_flush (timeout =E<gt> I<timeout>)".
-
-B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_all> has been
-deprecated and will be removed in some future version of collectd. Use
-B<plugin_flush> instead.
-
=item B<plugin_dispatch_notification> (I<notification>)
Submits a I<notification> to the daemon which will then pass it to all
diff --git a/src/collectd.c b/src/collectd.c
index 277d3b0dc9432917db2f0483ec812742148852e3..d33d1d6685ff4755d9ab460a526313b468d6f71d 100644 (file)
--- a/src/collectd.c
+++ b/src/collectd.c
* Global variables
*/
char hostname_g[DATA_MAX_NAME_LEN];
-int interval_g;
+cdtime_t interval_g;
int timeout_g;
#if HAVE_LIBKSTAT
kstat_ctl_t *kc;
static void *do_flush (void __attribute__((unused)) *arg)
{
INFO ("Flushing all data.");
- plugin_flush (NULL, -1, NULL);
+ plugin_flush (/* plugin = */ NULL,
+ /* timeout = */ 0,
+ /* ident = */ NULL);
INFO ("Finished flushing all data.");
pthread_exit (NULL);
return NULL;
str = global_option_get ("Interval");
if (str == NULL)
- str = "10";
- interval_g = atoi (str);
- if (interval_g <= 0)
{
- fprintf (stderr, "Cannot set the interval to a correct value.\n"
- "Please check your settings.\n");
- return (-1);
+ interval_g = TIME_T_TO_CDTIME_T (10);
+ }
+ else
+ {
+ double tmp;
+
+ tmp = atof (str);
+ if (tmp <= 0.0)
+ {
+ fprintf (stderr, "Cannot set the interval to a "
+ "correct value.\n"
+ "Please check your settings.\n");
+ return (-1);
+ }
+
+ interval_g = DOUBLE_TO_CDTIME_T (tmp);
}
- DEBUG ("interval_g = %i;", interval_g);
+ DEBUG ("interval_g = %.3f;", CDTIME_T_TO_DOUBLE (interval_g));
str = global_option_get ("Timeout");
if (str == NULL)
static int do_loop (void)
{
- struct timeval tv_now;
- struct timeval tv_next;
- struct timeval tv_wait;
- struct timespec ts_wait;
+ cdtime_t wait_until;
+
+ wait_until = cdtime () + interval_g;
while (loop == 0)
{
- if (gettimeofday (&tv_next, NULL) < 0)
- {
- char errbuf[1024];
- ERROR ("gettimeofday failed: %s",
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
- }
- tv_next.tv_sec += interval_g;
+ struct timespec ts_wait = { 0, 0 };
+ cdtime_t now;
#if HAVE_LIBKSTAT
update_kstat ();
/* Issue all plugins */
plugin_read_all ();
- if (gettimeofday (&tv_now, NULL) < 0)
- {
- char errbuf[1024];
- ERROR ("gettimeofday failed: %s",
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
- }
-
- if (timeval_cmp (tv_next, tv_now, &tv_wait) <= 0)
+ now = cdtime ();
+ if (now >= wait_until)
{
WARNING ("Not sleeping because the next interval is "
- "%i.%06i seconds in the past!",
- (int) tv_wait.tv_sec, (int) tv_wait.tv_usec);
+ "%.3f seconds in the past!",
+ CDTIME_T_TO_DOUBLE (now - wait_until));
+ wait_until = now + interval_g;
continue;
}
- ts_wait.tv_sec = tv_wait.tv_sec;
- ts_wait.tv_nsec = (long) (1000 * tv_wait.tv_usec);
+ CDTIME_T_TO_TIMESPEC (wait_until - now, &ts_wait);
+ wait_until = wait_until + interval_g;
- while ((loop == 0) && (nanosleep (&ts_wait, &ts_wait) == -1))
+ while ((loop == 0) && (nanosleep (&ts_wait, &ts_wait) != 0))
{
if (errno != EINTR)
{
}
} /* while (loop == 0) */
- DEBUG ("return (0);");
return (0);
} /* int do_loop */
diff --git a/src/collectd.conf.in b/src/collectd.conf.in
index d8e39dbebb3c9b362d98827acd9ab05da1078186..12259098700110c2ae31f877c8e4084f21f73aa9 100644 (file)
--- a/src/collectd.conf.in
+++ b/src/collectd.conf.in
##############################################################################
#Hostname "localhost"
-FQDNLookup true
+#FQDNLookup true
#BaseDir "@prefix@/var/lib/@PACKAGE_NAME@"
#PIDFile "@prefix@/var/run/@PACKAGE_NAME@.pid"
#PluginDir "@prefix@/lib/@PACKAGE_NAME@"
# to missing dependencies or because they have been deactivated explicitly. #
##############################################################################
+#@BUILD_PLUGIN_AMQP_TRUE@LoadPlugin amqp
#@BUILD_PLUGIN_APACHE_TRUE@LoadPlugin apache
#@BUILD_PLUGIN_APCUPS_TRUE@LoadPlugin apcups
#@BUILD_PLUGIN_APPLE_SENSORS_TRUE@LoadPlugin apple_sensors
#@BUILD_PLUGIN_JAVA_TRUE@LoadPlugin java
#@BUILD_PLUGIN_LIBVIRT_TRUE@LoadPlugin libvirt
@BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
+#@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
#@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
#@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
#@BUILD_PLUGIN_MEMCACHEC_TRUE@LoadPlugin memcachec
#@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
#@BUILD_PLUGIN_PROTOCOLS_TRUE@LoadPlugin protocols
#@BUILD_PLUGIN_PYTHON_TRUE@LoadPlugin python
+#@BUILD_PLUGIN_REDIS_TRUE@LoadPlugin redis
#@BUILD_PLUGIN_ROUTEROS_TRUE@LoadPlugin routeros
#@BUILD_PLUGIN_RRDCACHED_TRUE@LoadPlugin rrdcached
@LOAD_PLUGIN_RRDTOOL@LoadPlugin rrdtool
#@BUILD_PLUGIN_UPTIME_TRUE@LoadPlugin uptime
#@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
#@BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid
+#@BUILD_PLUGIN_VARNISH_TRUE@LoadPlugin varnish
#@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem
#@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
#@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
#@BUILD_PLUGIN_WRITE_HTTP_TRUE@LoadPlugin write_http
+#@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis
#@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
#@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc
# ription of those options is available in the collectd.conf(5) manual page. #
##############################################################################
+#<Plugin "amqp">
+# <Publish "name">
+# Host "localhost"
+# Port "5672"
+# VHost "/"
+# User "guest"
+# Password "guest"
+# Exchange "amq.fanout"
+# RoutingKey "collectd"
+# Persistent false
+# StoreRates false
+# </Publish>
+#</Plugin>
+
#<Plugin apache>
-# URL "http://localhost/status?auto"
-# User "www-user"
-# Password "secret"
-# CACert "/etc/ssl/ca.crt"
+# <Instance "local">
+# URL "http://localhost/status?auto"
+# User "www-user"
+# Password "secret"
+# CACert "/etc/ssl/ca.crt"
+# </Instance>
#</Plugin>
#<Plugin apcups>
# InterfaceDevice "name:device"
# IgnoreSelected false
# HostnameFormat name
+# InterfaceFormat name
+#</Plugin>
+
+#<Plugin lpar>
+# CpuPoolStats false
+# ReportBySerial false
#</Plugin>
#<Plugin madwifi>
# </Module>
#</Plugin>
+#<Plugin redis>
+# <Node example>
+# Host "redis.example.com"
+# Port "6379"
+# Timeout 2000
+# </Node>
+#</Plugin>
+
#<Plugin routeros>
# <Router>
# Host "router.example.com"
# SocketFile "@prefix@/var/run/@PACKAGE_NAME@-unixsock"
# SocketGroup "collectd"
# SocketPerms "0660"
+# DeleteSocket false
#</Plugin>
#<Plugin uuid>
# UUIDFile "/etc/uuid"
#</Plugin>
+#<Plugin varnish>
+# This tag support an argument if you want to
+# monitor the local instance just use </Instance>
+# If you prefer defining another instance you can do
+# so by using <Instance "myinstance">
+# <Instance>
+# CollectCache true
+# CollectBackend true
+# CollectConnections true
+# CollectSHM true
+# CollectESI false
+# CollectFetch false
+# CollectHCB false
+# CollectSMA false
+# CollectSMS false
+# CollectSM false
+# CollectTotals false
+# CollectWorkers false
+# </Instance>
+#</Plugin>
+
#<Plugin vmem>
# Verbose false
#</Plugin>
# </URL>
#</Plugin>
+#<Plugin write_redis>
+# <Node "example">
+# Host "localhost"
+# Port "6379"
+# Timeout 1000
+# </Node>
+#</Plugin>
+
##############################################################################
# Filter configuration #
#----------------------------------------------------------------------------#
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index bfb7309575f85ad8322f7859b34a2b265ebf3625..c1c9a253c31a3ce7d53fdfef28726158735d314e 100644 (file)
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
If B<Hostname> is determined automatically this setting controls whether or not
the daemon should try to figure out the "fully qualified domain name", FQDN.
-This is done using a lookup of the name returned by C<gethostname>.
-
-Using this feature (i.E<nbsp>e. setting this option to B<true>) is recommended.
-However, to preserve backwards compatibility the default is set to B<false>.
-The sample config file that is installed with C<makeE<nbsp>install> includes a
-line which sets this option, though, so that default installations will have
-this setting enabled.
+This is done using a lookup of the name returned by C<gethostname>. This option
+is enabled by default.
=item B<PreCacheChain> I<ChainName>
F<README> file shipped with the sourcecode and hopefully binary packets as
well.
+=head2 Plugin C<amqp>
+
+The I<AMQMP plugin> can be used to communicate with other instances of
+I<collectd> or third party applications using an AMQP message broker. Values
+are sent to or received from the broker, which handles routing, queueing and
+possibly filtering or messages.
+
+ <Plugin "amqp">
+ # Send values to an AMQP broker
+ <Publish "some_name">
+ Host "localhost"
+ Port "5672"
+ VHost "/"
+ User "guest"
+ Password "guest"
+ Exchange "amq.fanout"
+ # ExchangeType "fanout"
+ # RoutingKey "collectd"
+ # Persistent false
+ # Format "command"
+ # StoreRates false
+ </Publish>
+
+ # Receive values from an AMQP broker
+ <Subscribe "some_name">
+ Host "localhost"
+ Port "5672"
+ VHost "/"
+ User "guest"
+ Password "guest"
+ Exchange "amq.fanout"
+ # ExchangeType "fanout"
+ # Queue "queue_name"
+ # RoutingKey "collectd.#"
+ </Subscribe>
+ </Plugin>
+
+The plugin's configuration consists of a number of I<Publish> and I<Subscribe>
+blocks, which configure sending and receiving of values respectively. The two
+blocks are very similar, so unless otherwise noted, an option can be used in
+either block. The name given in the blocks starting tag is only used for
+reporting messages, but may be used to support I<flushing> of certain
+I<Publish> blocks in the future.
+
+=over 4
+
+=item B<Host> I<Host>
+
+Hostname or IP-address of the AMQP broker. Defaults to the default behavior of
+the underlying communications library, I<rabbitmq-c>, which is "localhost".
+
+=item B<Port> I<Port>
+
+Service name or port number on which the AMQP broker accepts connections. This
+argument must be a string, even if the numeric form is used. Defaults to
+"5672".
+
+=item B<VHost> I<VHost>
+
+Name of the I<virtual host> on the AMQP broker to use. Defaults to "/".
+
+=item B<User> I<User>
+
+=item B<Password> I<Password>
+
+Credentials used to authenticate to the AMQP broker. By default "guest"/"guest"
+is used.
+
+=item B<Exchange> I<Exchange>
+
+In I<Publish> blocks, this option specifies the I<exchange> to send values to.
+By default, "amq.fanout" will be used.
+
+In I<Subscribe> blocks this option is optional. If given, a I<binding> between
+the given exchange and the I<queue> is created, using the I<routing key> if
+configured. See the B<Queue> and B<RoutingKey> options below.
+
+=item B<ExchangeType> I<Type>
+
+If given, the plugin will try to create the configured I<exchange> with this
+I<type> after connecting. When in a I<Subscribe> block, the I<queue> will then
+be bound to this exchange.
+
+=item B<Queue> I<Queue> (Subscribe only)
+
+Configures the I<queue> name to subscribe to. If no queue name was configures
+explicitly, a unique queue name will be created by the broker.
+
+=item B<RoutingKey> I<Key>
+
+In I<Publish> blocks, this configures the routing key to set on all outgoing
+messages. If not given, the routing key will be computed from the I<identifier>
+of the value. The host, plugin, type and the two instances are concatenated
+together using dots as the separator and all containing dots replaced with
+slashes. For example "collectd.host/example/com.cpu.0.cpu.user". This makes it
+possible to receive only specific values using a "topic" exchange.
+
+In I<Subscribe> blocks, configures the I<routing key> used when creating a
+I<binding> between an I<exchange> and the I<queue>. The usual wildcards can be
+used to filter messages when using a "topic" exchange. If you're only
+interested in CPU statistics, you could use the routing key "collectd.*.cpu.#"
+for example.
+
+=item B<Persistent> B<true>|B<false> (Publish only)
+
+Selects the I<delivery method> to use. If set to B<true>, the I<persistent>
+mode will be used, i.e. delivery is guaranteed. If set to B<false> (the
+default), the I<transient> delivery mode will be used, i.e. messages may be
+lost due to high load, overflowing queues or similar issues.
+
+=item B<Format> B<Command>|B<JSON> (Publish only)
+
+Selects the format in which messages are sent to the broker. If set to
+B<Command> (the default), values are sent as C<PUTVAL> commands which are
+identical to the syntax used by the I<Exec> and I<UnixSock plugins>. In this
+case, the C<Content-Type> header field will be set to C<text/collectd>.
+
+If set to B<JSON>, the values are encoded in the I<JavaScript Object Notation>,
+an easy and straight forward exchange format. The C<Content-Type> header field
+will be set to C<application/json>.
+
+A subscribing client I<should> use the C<Content-Type> header field to
+determine how to decode the values. Currently, the I<AMQP plugin> itself can
+only decode the B<Command> format.
+
+=item B<StoreRates> B<true>|B<false> (Publish only)
+
+Determines whether or not C<COUNTER>, C<DERIVE> and C<ABSOLUTE> data sources
+are converted to a I<rate> (i.e. a C<GAUGE> value). If set to B<false> (the
+default), no conversion is performed. Otherwise the conversion is performed
+using the internal value cache.
+
+Please note that currently this option is only used if the B<Format> option has
+been set to B<JSON>.
+
+=back
+
=head2 Plugin C<apache>
To configure the C<apache>-plugin you first need to configure the Apache
also supported. It introduces a new field, called C<BusyServers>, to count the
number of currently connected clients. This field is also supported.
-The following options are accepted by the C<apache>-plugin:
+The configuration of the I<Apache> plugin consists of one or more
+C<E<lt>InstanceE<nbsp>/E<gt>> blocks. Each block requires one string argument
+as the instance name. For example:
+
+ <Plugin "apache">
+ <Instance "www1">
+ URL "http://www1.example.com/mod_status?auto"
+ </Instance>
+ <Instance "www2">
+ URL "http://www2.example.com/mod_status?auto"
+ </Instance>
+ </Plugin>
+
+The instance name will be used as the I<plugin instance>. To emulate the old
+(versionE<nbsp>4) behavior, you can use an empty string (""). In order for the
+plugin to work correctly, each instance name must be unique. This is not
+enforced by the plugin and it is your responsibility to ensure it.
+
+The following options are accepted within each I<Instance> block:
=over 4
Sets the URL of the C<mod_status> output. This needs to be the output generated
by C<ExtendedStatus on> and it needs to be the machine readable output
-generated by appending the C<?auto> argument.
+generated by appending the C<?auto> argument. This option is I<mandatory>.
=item B<User> I<Username>
@@ -1030,22 +1180,6 @@ Report using the device name rather than the mountpoint. i.e. with this I<false>
(the default), it will report a disk as "root", but with it I<true>, it will be
"sda1" (or whichever).
-=item B<ReportReserved> B<true>|B<false>
-
-When enabled, the blocks reserved for root are reported separately. When
-disabled (the default for backwards compatibility reasons) the reserved space
-will be included in the "free" space.
-
-When disabled, the "df" type will be used to store "free" and "used" space. The
-mount point or disk name (see option B<ReportByDevice>) is used as type
-instance in this case (again: backwards compatibility).
-
-When enabled, the type "df_complex" is used and three files are created. The
-mount point or disk name is used as plugin instance and the type instance is
-set to "free", "reserved" and "used" as appropriate.
-
-Enabling this option is recommended.
-
=item B<ReportInodes> B<true>|B<false>
Enables or disables reporting of free, reserved and used inodes. Defaults to
TCP-Port to connect to. Defaults to B<7634>.
-=item B<TranslateDevicename> I<true>|I<false>
-
-If enabled, translate the disk names to major/minor device numbers
-(e.E<nbsp>g. "8-0" for /dev/sda). For backwards compatibility this defaults to
-I<true> but it's recommended to disable it as it will probably be removed in
-the next major version.
-
=back
=head2 Plugin C<interface>
means to concatenate the guest name and UUID (with a literal colon character
between, thus I<"foo:1234-1234-1234-1234">).
+=item B<InterfaceFormat> B<name>|B<address>
+
+When the libvirt plugin logs interface data, it sets the name of the collected
+data according to this setting. The default is to use the path as provided by
+the hypervisor (the "dev" property of the target node), which is equal to
+setting B<name>.
+
+B<address> means use the interface's mac address. This is useful since the
+interface path might change between reboots of a guest or across migrations.
+
=back
=head2 Plugin C<logfile>
Sets the file to write log messages to. The special strings B<stdout> and
B<stderr> can be used to write to the standard output and standard error
-channels, respectively. This, of course, only makes much sense when collectd is
-running in foreground- or non-daemon-mode.
+channels, respectively. This, of course, only makes much sense when I<collectd>
+is running in foreground- or non-daemon-mode.
=item B<Timestamp> B<true>|B<false>
log file (e.E<nbsp>g. when rotating the logs). The plugin reopens the file
for each line it writes.
+=head2 Plugin C<lpar>
+
+The I<LPAR plugin> reads CPU statistics of I<Logical Partitions>, a
+virtualization technique for IBM POWER processors. It takes into account CPU
+time stolen from or donated to a partition, in addition to the usual user,
+system, I/O statistics.
+
+The following configuration options are available:
+
+=over 4
+
+=item B<CpuPoolStats> B<false>|B<true>
+
+When enabled, statistics about the processor pool are read, too. The partition
+needs to have pool authority in order to be able to acquire this information.
+Defaults to false.
+
+=item B<ReportBySerial> B<false>|B<true>
+
+If enabled, the serial of the physical machine the partition is currently
+running on is reported as I<hostname> and the logical hostname of the machine
+is reported in the I<plugin instance>. Otherwise, the logical hostname will be
+used (just like other plugins) and the I<plugin instance> will be empty.
+Defaults to false.
+
+=back
+
=head2 Plugin C<mbmon>
The C<mbmon plugin> uses mbmon to retrieve temperature, voltage, etc.
The C<mysql plugin> requires B<mysqlclient> to be installed. It connects to
one or more databases when started and keeps the connection up as long as
possible. When the connection is interrupted for whatever reason it will try
-to re-connect. The plugin will complaint loudly in case anything goes wrong.
+to re-connect. The plugin will complain loudly in case anything goes wrong.
This plugin issues the MySQL C<SHOW STATUS> / C<SHOW GLOBAL STATUS> command
and collects information about MySQL network traffic, executed statements,
=item B<MaxPacketSize> I<1024-65535>
Set the maximum size for datagrams received over the network. Packets larger
-than this will be truncated.
+than this will be truncated. Defaults to 1452E<nbsp>bytes.
=item B<Forward> I<true|false>
necessary it's not a huge problem since the plugin has a duplicate detection,
so the values will not loop.
-=item B<CacheFlush> I<Seconds>
-
-For each host/plugin/type combination the C<network plugin> caches the time of
-the last value being sent or received. Every I<Seconds> seconds the plugin
-searches and removes all entries that are older than I<Seconds> seconds, thus
-freeing the unused memory again. Since this process is somewhat expensive and
-normally doesn't do much, this value should not be too small. The default is
-1800 seconds, but setting this to 86400 seconds (one day) will not do much harm
-either.
-
=item B<ReportStats> B<true>|B<false>
The network plugin cannot only receive and send statistics, it can also create
The returned lines will be handled separately one after another.
-=item B<Query> I<sql query statement>
-
-This is a deprecated synonym for B<Statement>. It will be removed in version 5
-of collectd.
-
=item B<Param> I<hostname>|I<database>|I<username>|I<interval>
Specify the parameters which should be passed to the SQL query. The parameters
@@ -3364,21 +3513,6 @@ This option is required inside a B<Result> block and may be specified multiple
times. If multiple B<ValuesFrom> options are specified, the columns are read
in the given order.
-=item B<Column> I<type> [I<type instance>]
-
-This is a deprecated alternative to a B<Result> block. It will be removed in
-version 5 of collectd. It is equivalent to the following B<Result> block:
-
- <Result>
- Type I<type>
- InstancePrefix I<type instance>
- ValuesFrom I<name of the x. column>
- </Result>
-
-The order of the B<Column> options defines which columns of the query result
-should be used. The first option specifies the data found in the first column,
-the second option that of the second column, and so on.
-
=item B<MinVersion> I<version>
=item B<MaxVersion> I<version>
and patch-level versions, each represented as two-decimal-digit numbers. For
example, version 8.2.3 will become 80203.
-=item B<MinPGVersion> I<version>
-
-=item B<MaxPGVersion> I<version>
-
-These are deprecated synonyms for B<MinVersion> and B<MaxVersion>
-respectively. They will be removed in version 5 of collectd.
-
=back
The following predefined queries are available (the definitions can be found
=back
+=head2 Plugin C<redis>
+
+The I<Redis plugin> connects to one or more Redis servers and gathers
+information about each server's state. For each server there is a I<Node> block
+which configures the connection parameters for this node.
+
+ <Plugin redis>
+ <Node "example">
+ Host "localhost"
+ Port "6379"
+ Timeout 2000
+ </Node>
+ </Plugin>
+
+The information shown in the synopsis above is the I<default configuration>
+which is used by the plugin if no configuration is present.
+
+=over 4
+
+=item B<Node> I<Nodename>
+
+The B<Node> block identifies a new Redis node, that is a new Redis instance
+running in an specified host and port. The name for node is a canonical
+identifier which is used as I<plugin instance>. It is limited to
+64E<nbsp>characters in length.
+
+=item B<Host> I<Hostname>
+
+The B<Host> option is the hostname or IP-address where the Redis instance is
+running on.
+
+=item B<Port> I<Port>
+
+The B<Port> option is the TCP port on which the Redis instance accepts
+connections. Either a service name of a port number may be given. Please note
+that numerical port numbers must be given as a string, too.
+
+=item B<Timeout> I<Timeout in miliseconds>
+
+The B<Timeout> option set the socket timeout for node response. Since the Redis
+read function is blocking, you should keep this value as low as possible. Keep
+in mind that the sum of all B<Timeout> values for all B<Nodes> should be lower
+than B<Interval> defined globally.
+
+=back
+
=head2 Plugin C<rrdcached>
The C<rrdcached> plugin uses the RRDtool accelerator daemon, L<rrdcached(1)>,
@@ -4416,6 +4589,13 @@ Change the file permissions of the UNIX-socket after it has been created. The
permissions must be given as a numeric, octal value as you would pass to
L<chmod(1)>. Defaults to B<0770>.
+=item B<DeleteSocket> B<false>|B<true>
+
+If set to B<true>, delete the socket file before calling L<bind(2)>, if a file
+with the given name already exists. If I<collectd> crashes a socket file may be
+left over, preventing the daemon from opening a new socket when restarted.
+Since this is potentially dangerous, this defaults to B<false>.
+
=back
=head2 Plugin C<uuid>
=back
+=head2 Plugin C<varnish>
+
+The Varnish plugin collects information about Varnish, an HTTP accelerator.
+
+=over 4
+
+=item B<CollectCache> B<true>|B<false>
+
+Cache hits and misses. True by default.
+
+=item B<CollectConnections> B<true>|B<false>
+
+Number of client connections received, accepted and dropped. True by default.
+
+=item B<CollectBackend> B<true>|B<false>
+
+Back-end connection statistics, such as successful, reused,
+and closed connections. True by default.
+
+=item B<CollectSHM> B<true>|B<false>
+
+Statistics about the shared memory log, a memory region to store
+log messages which is flushed to disk when full. True by default.
+
+=item B<CollectESI> B<true>|B<false>
+
+Edge Side Includes (ESI) parse statistics. False by default.
+
+=item B<CollectFetch> B<true>|B<false>
+
+Statistics about fetches (HTTP requests sent to the backend). False by default.
+
+=item B<CollectHCB> B<true>|B<false>
+
+Inserts and look-ups in the crit bit tree based hash. Look-ups are
+divided into locked and unlocked look-ups. False by default.
+
+=item B<CollectSMA> B<true>|B<false>
+
+malloc or umem (umem_alloc(3MALLOC) based) storage statistics.
+The umem storage component is Solaris specific. False by default.
+
+=item B<CollectSMS> B<true>|B<false>
+
+synth (synthetic content) storage statistics. This storage
+component is used internally only. False by default.
+
+=item B<CollectSM> B<true>|B<false>
+
+file (memory mapped file) storage statistics. False by default.
+
+=item B<CollectTotals> B<true>|B<false>
+
+Collects overview counters, such as the number of sessions created,
+the number of requests and bytes transferred. False by default.
+
+=item B<CollectWorkers> B<true>|B<false>
+
+Collect statistics about worker threads. False by default.
+
+=back
+
=head2 Plugin C<vmem>
The C<vmem> plugin collects information about the usage of virtual memory.
WarningMin 100000000
</Type>
</Plugin>
+
+ <Type "load">
+ DataSource "midterm"
+ FailureMax 4
+ Hits 3
+ Hysteresis 3
+ </Type>
</Host>
</Threshold>
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>.
+=item B<Hits> I<Value>
+
+Sets the number of occurrences which the threshold must be arised before to
+dispatch any notification or, in other words, the number of B<Interval>s
+than the threshold must be match before dispatch any notification.
+
+=item B<Hysteresis> I<Value>
+
+Sets the hysteresis value for threshold. The hysteresis is a method to
+prevent flapping between states, until a new received value for
+a previously matched threshold down below the threshold condition
+(B<WarningMax>, B<FailureMin> or everthing else) minus the hysteresis value,
+the failure (respectively warning) state will be keep.
+
+=item B<Interesting> B<true>|B<false>
+
+If set to B<true> (the default), the threshold must be treated as
+interesting and, when a number of B<Timeout> values will lost, then
+a missing notification will be dispatched. On the other hand, if set to
+B<false>, the missing notification will never dispatched for this threshold.
+
=back
=head1 FILTER CONFIGURATION
diff --git a/src/collectd.h b/src/collectd.h
index e7fc4e3554f4c0c0ea90403994af186e11d4cf56..8dd0f4263b55a1921ab5e105c354f37948226b20 100644 (file)
--- a/src/collectd.h
+++ b/src/collectd.h
#if HAVE_STDINT_H
# include <stdint.h>
#endif
-#if HAVE_STDBOOL_H
-# include <stdbool.h>
-#else
-# ifndef HAVE__BOOL
-# ifdef __cplusplus
-typedef bool _Bool;
-# else
-# define _Bool signed char
-# endif
-# endif
-# define bool _Bool
-# define false 0
-# define true 1
-# define __bool_true_false_are_defined 1
-#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
# endif
#endif
-extern char hostname_g[];
-extern int interval_g;
-extern int timeout_g;
+/* Type for time as used by "utils_time.h" */
+typedef uint64_t cdtime_t;
+
+extern char hostname_g[];
+extern cdtime_t interval_g;
+extern int timeout_g;
#endif /* COLLECTD_H */
diff --git a/src/collectdctl.c b/src/collectdctl.c
--- /dev/null
+++ b/src/collectdctl.c
@@ -0,0 +1,591 @@
+/**
+ * collectd - src/collectdctl.c
+ * Copyright (C) 2010 Håkon J Dugstad Johnsen
+ * Copyright (C) 2010 Sebastian Harl
+ *
+ * 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:
+ * Håkon J Dugstad Johnsen <hakon-dugstad.johnsen at telenor.com>
+ * Sebastian "tokkee" Harl <sh@tokkee.org>
+ **/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <math.h>
+
+#include "libcollectdclient/client.h"
+
+
+#define DEFAULT_SOCK LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock"
+
+extern char *optarg;
+extern int optind;
+
+static void exit_usage (const char *name, int status) {
+ fprintf ((status == 0) ? stdout : stderr,
+ "Usage: %s [options] <command> [cmd options]\n\n"
+
+ "Available options:\n"
+ " -s Path to collectd's UNIX socket.\n"
+ " Default: "DEFAULT_SOCK"\n"
+
+ "\n -h Display this help and exit.\n"
+
+ "\nAvailable commands:\n\n"
+
+ " * getval <identifier>\n"
+ " * flush [timeout=<seconds>] [plugin=<name>] [identifier=<id>]\n"
+ " * listval\n"
+ " * putval <identifier> [interval=<seconds>] <value-list(s)>\n"
+
+ "\nIdentifiers:\n\n"
+
+ "An identifier has the following format:\n\n"
+
+ " [<hostname>/]<plugin>[-<plugin_instance>]/<type>[-<type_instance>]\n\n"
+
+ "Hostname defaults to the local hostname if omitted (e.g., uptime/uptime).\n"
+ "No error is returned if the specified identifier does not exist.\n"
+
+ "\n"PACKAGE" "VERSION", http://collectd.org/\n"
+ "by Florian octo Forster <octo@verplant.org>\n"
+ "for contributions see `AUTHORS'\n"
+ , name);
+ exit (status);
+}
+
+/* Count the number of occurrences of the character 'chr'
+ * in the specified string. */
+static int count_chars (const char *str, char chr) {
+ int count = 0;
+
+ while (*str != '\0') {
+ if (*str == chr) {
+ count++;
+ }
+ str++;
+ }
+
+ return count;
+} /* count_chars */
+
+static int array_grow (void **array, int *array_len, size_t elem_size)
+{
+ void *tmp;
+
+ assert ((array != NULL) && (array_len != NULL));
+
+ tmp = realloc (*array, (*array_len + 1) * elem_size);
+ if (tmp == NULL) {
+ fprintf (stderr, "ERROR: Failed to allocate memory.\n");
+ return (-1);
+ }
+
+ *array = tmp;
+ ++(*array_len);
+ return (0);
+} /* array_grow */
+
+static int parse_identifier (lcc_connection_t *c,
+ const char *value, lcc_identifier_t *ident)
+{
+ char hostname[1024];
+ char ident_str[1024] = "";
+ int n_slashes;
+
+ int status;
+
+ n_slashes = count_chars (value, '/');
+ if (n_slashes == 1) {
+ /* The user has omitted the hostname part of the identifier
+ * (there is only one '/' in the identifier)
+ * Let's add the local hostname */
+ if (gethostname (hostname, sizeof (hostname)) != 0) {
+ fprintf (stderr, "ERROR: Failed to get local hostname: %s",
+ strerror (errno));
+ return (-1);
+ }
+ hostname[sizeof (hostname) - 1] = '\0';
+
+ snprintf (ident_str, sizeof (ident_str), "%s/%s", hostname, value);
+ ident_str[sizeof(ident_str) - 1] = '\0';
+ }
+ else {
+ strncpy (ident_str, value, sizeof (ident_str));
+ ident_str[sizeof (ident_str) - 1] = '\0';
+ }
+
+ status = lcc_string_to_identifier (c, ident, ident_str);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: Failed to parse identifier ``%s'': %s.\n",
+ ident_str, lcc_strerror(c));
+ return (-1);
+ }
+ return (0);
+} /* parse_identifier */
+
+static int getval (lcc_connection_t *c, int argc, char **argv)
+{
+ lcc_identifier_t ident;
+
+ size_t ret_values_num = 0;
+ gauge_t *ret_values = NULL;
+ char **ret_values_names = NULL;
+
+ int status;
+ size_t i;
+
+ assert (strcasecmp (argv[0], "getval") == 0);
+
+ if (argc != 2) {
+ fprintf (stderr, "ERROR: getval: Missing identifier.\n");
+ return (-1);
+ }
+
+ memset (&ident, 0, sizeof (ident));
+ status = parse_identifier (c, argv[1], &ident);
+ if (status != 0)
+ return (status);
+
+#define BAIL_OUT(s) \
+ do { \
+ if (ret_values != NULL) \
+ free (ret_values); \
+ if (ret_values_names != NULL) { \
+ for (i = 0; i < ret_values_num; ++i) \
+ free (ret_values_names[i]); \
+ free (ret_values_names); \
+ } \
+ ret_values_num = 0; \
+ return (s); \
+ } while (0)
+
+ status = lcc_getval (c, &ident,
+ &ret_values_num, &ret_values, &ret_values_names);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+ BAIL_OUT (-1);
+ }
+
+ for (i = 0; i < ret_values_num; ++i)
+ printf ("%s=%e\n", ret_values_names[i], ret_values[i]);
+ BAIL_OUT (0);
+#undef BAIL_OUT
+} /* getval */
+
+static int flush (lcc_connection_t *c, int argc, char **argv)
+{
+ int timeout = -1;
+
+ lcc_identifier_t *identifiers = NULL;
+ int identifiers_num = 0;
+
+ char **plugins = NULL;
+ int plugins_num = 0;
+
+ int status;
+ int i;
+
+ assert (strcasecmp (argv[0], "flush") == 0);
+
+#define BAIL_OUT(s) \
+ do { \
+ if (identifiers != NULL) \
+ free (identifiers); \
+ identifiers_num = 0; \
+ if (plugins != NULL) \
+ free (plugins); \
+ plugins_num = 0; \
+ return (s); \
+ } while (0)
+
+ for (i = 1; i < argc; ++i) {
+ char *key, *value;
+
+ key = argv[i];
+ value = strchr (argv[i], (int)'=');
+
+ if (! value) {
+ fprintf (stderr, "ERROR: flush: Invalid option ``%s''.\n", argv[i]);
+ BAIL_OUT (-1);
+ }
+
+ *value = '\0';
+ ++value;
+
+ if (strcasecmp (key, "timeout") == 0) {
+ char *endptr = NULL;
+
+ timeout = (int) strtol (value, &endptr, 0);
+
+ if (endptr == value) {
+ fprintf (stderr, "ERROR: Failed to parse timeout as number: %s.\n",
+ value);
+ BAIL_OUT (-1);
+ }
+ else if ((endptr != NULL) && (*endptr != '\0')) {
+ fprintf (stderr, "WARNING: Ignoring trailing garbage after timeout: "
+ "%s.\n", endptr);
+ }
+ }
+ else if (strcasecmp (key, "plugin") == 0) {
+ status = array_grow ((void *)&plugins, &plugins_num,
+ sizeof (*plugins));
+ if (status != 0)
+ BAIL_OUT (status);
+
+ plugins[plugins_num - 1] = value;
+ }
+ else if (strcasecmp (key, "identifier") == 0) {
+ status = array_grow ((void *)&identifiers, &identifiers_num,
+ sizeof (*identifiers));
+ if (status != 0)
+ BAIL_OUT (status);
+
+ memset (identifiers + (identifiers_num - 1), 0, sizeof (*identifiers));
+ status = parse_identifier (c, value,
+ identifiers + (identifiers_num - 1));
+ if (status != 0)
+ BAIL_OUT (status);
+ }
+ else {
+ fprintf (stderr, "ERROR: flush: Unknown option `%s'.\n", key);
+ BAIL_OUT (-1);
+ }
+ }
+
+ if (plugins_num == 0) {
+ status = array_grow ((void *)&plugins, &plugins_num, sizeof (*plugins));
+ if (status != 0)
+ BAIL_OUT (status);
+
+ assert (plugins_num == 1);
+ plugins[0] = NULL;
+ }
+
+ for (i = 0; i < plugins_num; ++i) {
+ if (identifiers_num == 0) {
+ status = lcc_flush (c, plugins[i], NULL, timeout);
+ if (status != 0)
+ fprintf (stderr, "ERROR: Failed to flush plugin `%s': %s.\n",
+ (plugins[i] == NULL) ? "(all)" : plugins[i], lcc_strerror (c));
+ }
+ else {
+ int j;
+
+ for (j = 0; j < identifiers_num; ++j) {
+ status = lcc_flush (c, plugins[i], identifiers + j, timeout);
+ if (status != 0) {
+ char id[1024];
+
+ lcc_identifier_to_string (c, id, sizeof (id), identifiers + j);
+ fprintf (stderr, "ERROR: Failed to flush plugin `%s', "
+ "identifier `%s': %s.\n",
+ (plugins[i] == NULL) ? "(all)" : plugins[i],
+ id, lcc_strerror (c));
+ }
+ }
+ }
+ }
+
+ BAIL_OUT (0);
+#undef BAIL_OUT
+} /* flush */
+
+static int listval (lcc_connection_t *c, int argc, char **argv)
+{
+ lcc_identifier_t *ret_ident = NULL;
+ size_t ret_ident_num = 0;
+
+ int status;
+ size_t i;
+
+ assert (strcasecmp (argv[0], "listval") == 0);
+
+ if (argc != 1) {
+ fprintf (stderr, "ERROR: listval: Does not accept any arguments.\n");
+ return (-1);
+ }
+
+#define BAIL_OUT(s) \
+ do { \
+ if (ret_ident != NULL) \
+ free (ret_ident); \
+ ret_ident_num = 0; \
+ return (s); \
+ } while (0)
+
+ status = lcc_listval (c, &ret_ident, &ret_ident_num);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+ BAIL_OUT (status);
+ }
+
+ for (i = 0; i < ret_ident_num; ++i) {
+ char id[1024];
+
+ status = lcc_identifier_to_string (c, id, sizeof (id), ret_ident + i);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: listval: Failed to convert returned "
+ "identifier to a string: %s\n", lcc_strerror (c));
+ continue;
+ }
+
+ printf ("%s\n", id);
+ }
+ BAIL_OUT (0);
+#undef BAIL_OUT
+} /* listval */
+
+static int putval (lcc_connection_t *c, int argc, char **argv)
+{
+ lcc_value_list_t vl = LCC_VALUE_LIST_INIT;
+
+ /* 64 ought to be enough for anybody ;-) */
+ value_t values[64];
+ int values_types[64];
+ size_t values_len = 0;
+
+ int status;
+ int i;
+
+ assert (strcasecmp (argv[0], "putval") == 0);
+
+ if (argc < 3) {
+ fprintf (stderr, "ERROR: putval: Missing identifier "
+ "and/or value list.\n");
+ return (-1);
+ }
+
+ vl.values = values;
+ vl.values_types = values_types;
+
+ status = parse_identifier (c, argv[1], &vl.identifier);
+ if (status != 0)
+ return (status);
+
+ for (i = 2; i < argc; ++i) {
+ char *tmp;
+
+ tmp = strchr (argv[i], (int)'=');
+
+ if (tmp != NULL) { /* option */
+ char *key = argv[i];
+ char *value = tmp;
+
+ *value = '\0';
+ ++value;
+
+ if (strcasecmp (key, "interval") == 0) {
+ char *endptr;
+
+ vl.interval = strtol (value, &endptr, 0);
+
+ if (endptr == value) {
+ fprintf (stderr, "ERROR: Failed to parse interval as number: %s.\n",
+ value);
+ return (-1);
+ }
+ else if ((endptr != NULL) && (*endptr != '\0')) {
+ fprintf (stderr, "WARNING: Ignoring trailing garbage after "
+ "interval: %s.\n", endptr);
+ }
+ }
+ else {
+ fprintf (stderr, "ERROR: putval: Unknown option `%s'.\n", key);
+ return (-1);
+ }
+ }
+ else { /* value list */
+ char *value;
+
+ tmp = strchr (argv[i], (int)':');
+
+ if (tmp == NULL) {
+ fprintf (stderr, "ERROR: putval: Invalid value list: %s.\n",
+ argv[i]);
+ return (-1);
+ }
+
+ *tmp = '\0';
+ ++tmp;
+
+ if (strcasecmp (argv[i], "N") == 0) {
+ vl.time = 0;
+ }
+ else {
+ char *endptr;
+
+ vl.time = strtol (argv[i], &endptr, 0);
+
+ if (endptr == argv[i]) {
+ fprintf (stderr, "ERROR: Failed to parse time as number: %s.\n",
+ argv[i]);
+ return (-1);
+ }
+ else if ((endptr != NULL) && (*endptr != '\0')) {
+ fprintf (stderr, "ERROR: Garbage after time: %s.\n", endptr);
+ return (-1);
+ }
+ }
+
+ values_len = 0;
+ value = tmp;
+ while (value != 0) {
+ char *dot, *endptr;
+
+ tmp = strchr (argv[i], (int)':');
+
+ if (tmp != NULL) {
+ *tmp = '\0';
+ ++tmp;
+ }
+
+ /* This is a bit of a hack, but parsing types.db just does not make
+ * much sense imho -- the server might have different types defined
+ * anyway. Also, lcc uses the type information for formatting the
+ * number only, so the real meaning does not matter. -tokkee */
+ dot = strchr (value, (int)'.');
+ endptr = NULL;
+ if (strcasecmp (value, "U") == 0) {
+ values[values_len].gauge = NAN;
+ values_types[values_len] = LCC_TYPE_GAUGE;
+ }
+ else if (dot) { /* floating point value */
+ values[values_len].gauge = strtod (value, &endptr);
+ values_types[values_len] = LCC_TYPE_GAUGE;
+ }
+ else { /* integer */
+ values[values_len].counter = strtol (value, &endptr, 0);
+ values_types[values_len] = LCC_TYPE_COUNTER;
+ }
+ ++values_len;
+
+ if (endptr == value) {
+ fprintf (stderr, "ERROR: Failed to parse value as number: %s.\n",
+ argv[i]);
+ return (-1);
+ }
+ else if ((endptr != NULL) && (*endptr != '\0')) {
+ fprintf (stderr, "ERROR: Garbage after value: %s.\n", endptr);
+ return (-1);
+ }
+
+ value = tmp;
+ }
+
+ assert (values_len >= 1);
+ vl.values_len = values_len;
+
+ status = lcc_putval (c, &vl);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+ return (-1);
+ }
+ }
+ }
+
+ if (values_len == 0) {
+ fprintf (stderr, "ERROR: putval: Missing value list(s).\n");
+ return (-1);
+ }
+ return (0);
+} /* putval */
+
+int main (int argc, char **argv) {
+ char address[1024] = "unix:"DEFAULT_SOCK;
+
+ lcc_connection_t *c;
+
+ int status;
+
+ while (42) {
+ int c;
+
+ c = getopt (argc, argv, "s:h");
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 's':
+ snprintf (address, sizeof (address), "unix:%s", optarg);
+ address[sizeof (address) - 1] = '\0';
+ break;
+ case 'h':
+ exit_usage (argv[0], 0);
+ break;
+ default:
+ exit_usage (argv[0], 1);
+ }
+ }
+
+ if (optind >= argc) {
+ fprintf (stderr, "%s: missing command\n", argv[0]);
+ exit_usage (argv[0], 1);
+ }
+
+ c = NULL;
+ status = lcc_connect (address, &c);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: Failed to connect to daemon at %s: %s.\n",
+ address, strerror (errno));
+ return (1);
+ }
+
+ if (strcasecmp (argv[optind], "getval") == 0)
+ status = getval (c, argc - optind, argv + optind);
+ else if (strcasecmp (argv[optind], "flush") == 0)
+ status = flush (c, argc - optind, argv + optind);
+ else if (strcasecmp (argv[optind], "listval") == 0)
+ status = listval (c, argc - optind, argv + optind);
+ else if (strcasecmp (argv[optind], "putval") == 0)
+ status = putval (c, argc - optind, argv + optind);
+ else {
+ fprintf (stderr, "%s: invalid command: %s\n", argv[0], argv[optind]);
+ return (1);
+ }
+
+ LCC_DESTROY (c);
+
+ if (status != 0)
+ return (status);
+ return (0);
+} /* main */
+
+/* vim: set sw=2 ts=2 tw=78 expandtab : */
+
diff --git a/src/collectdctl.pod b/src/collectdctl.pod
--- /dev/null
+++ b/src/collectdctl.pod
@@ -0,0 +1,160 @@
+=head1 NAME
+
+collectdctl - Control interface for collectd
+
+=head1 SYNOPSIS
+
+collectdctl I<[options]> I<E<lt>commandE<gt>> I<[command options]>
+
+=head1 DESCRIPTION
+
+collectdctl provides a control interface for collectd, which may be used to
+interact with the daemon using the C<unixsock plugin>.
+
+=head1 OPTIONS
+
+collectdctl supports the following options:
+
+=over 4
+
+=item B<-s> I<socket>
+
+Path to the UNIX socket opened by collectd's C<unixsock plugin>.
+Default: /var/run/collectd-unixsock
+
+=item B<-h>
+
+Display usage information and exit.
+
+=back
+
+=head1 AVAILABLE COMMANDS
+
+The following commands are supported:
+
+=over 4
+
+=item B<getval> I<E<lt>identifierE<gt>>
+
+Query the latest collected value identified by the specified
+I<E<lt>identifierE<gt>> (see below). The value-list associated with that
+data-set is returned as a list of key-value-pairs, each on its own line. Keys
+and values are separated by the equal sign (C<=>).
+
+=item B<flush> [B<timeout=>I<E<lt>secondsE<gt>>] [B<plugin=>I<E<lt>nameE<gt>>]
+[B<identifier=>I<E<lt>idE<gt>>]
+
+Flush the daemon. This is useful, e.E<nbsp>g., to make sure that the latest
+values have been written to the respective RRD file before graphing them or
+copying them to somewhere else.
+
+The following options are supported by the flush command:
+
+=over 4
+
+=item B<timeout=>I<E<lt>secondsE<gt>>
+
+Flush values older than the specified timeout (in seconds) only.
+
+=item B<plugin=>I<E<lt>nameE<gt>>
+
+Flush the specified plugin only. I.E<nbsp>e., data cached by the specified
+plugin is written to disk (or network or whatever), if the plugin supports
+that operation.
+
+Example: B<rrdtool>.
+
+=item B<identifier=>I<E<lt>idE<gt>>
+
+If this option is present, only the data specified by the specified identifier
+(see below) will be flushed. Note that this option is not supported by all
+plugins (e.E<nbsp>g., the C<network> plugin does not support this).
+
+=back
+
+The B<plugin> and B<identifier> options may be specified more than once. In
+that case, all combinations of specified plugins and identifiers will be
+flushed only.
+
+=item B<listval>
+
+Returns a list of all values (by their identifier) available to the
+C<unixsock> plugin. Each value is printed on its own line. I.E<nbsp>e., this
+command returns a list of valid identifiers that may be used with the other
+commands.
+
+=item B<putval> I<E<lt>identifierE<gt>> [B<interval=>I<E<lt>secondsE<gt>>]
+I<E<lt>value-list(s)E<gt>>
+
+Submit one or more values (identified by I<E<lt>identifierE<gt>>, see below)
+to the daemon which will then dispatch them to the write plugins. B<interval>
+specifies the interval (in seconds) used to collect the values following that
+option. It defaults to the default of the running collectd instance receiving
+the data. Multiple I<E<lt>value-list(s)E<gt>> (see below) may be specified.
+Each of them will be submitted to the daemon. The values have to match the
+data-set definition specified by the type as given in the identifier (see
+L<types.db(5)> for details).
+
+=back
+
+=head1 IDENTIFIERS
+
+An identifier has the following format:
+
+[I<hostname>/]I<plugin>[-I<plugin_instance>]/I<type>[-I<type_instance>]
+
+Examples:
+ somehost/cpu-0/cpu-idle
+ uptime/uptime
+ otherhost/memory/memory-used
+
+Hostname defaults to the local (non-fully qualified) hostname if omitted. No
+error is returned if the specified identifier does not exist (this is a
+limitation in the C<libcollectdclient> library).
+
+=head1 VALUE-LIST
+
+A value list describes one data-set as handled by collectd. It is a colon
+(C<:>) separated list of the time and the values. Each value is either given
+as an integer if the data-type is a counter, or as a double if the data-type
+is a gauge value. A literal C<U> is interpreted as an undefined gauge value.
+The number of values and the data-types have to match the type specified in
+the identifier (see L<types.db(5)> for details). The time is specified as
+epoch (i.E<nbsp>e., standard UNIX time) or as a literal C<N> which will be
+interpreted as now.
+
+=head1 EXAMPLES
+
+=over 4
+
+=item C<collectdctl flush plugin=rrdtool identifier=somehost/cpu-0/cpu-wait>
+
+Flushes all CPU wait RRD values of the first CPU of the local host.
+I.E<nbsp>e., writes all pending RRD updates of that data-source to disk.
+
+=item C<for ident in `collectdctl listval | grep users/users`; do
+ collectdctl getval $ident;
+ done>
+
+Query the latest number of logged in users on all hosts known to the local
+collectd instance.
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<collectd-unixsock(5)>,
+L<types.db(5)>
+
+=head1 AUTHOR
+
+collectd has been written by Florian Forster E<lt>octo at verplant.orgE<gt>
+and many contributors (see `AUTHORS').
+
+collectdctl has been written by
+Håkon J Dugstad Johnsen E<lt>hakon-dugstad.johnsenE<nbsp>atE<nbsp>telenor.comE<gt>
+and Sebastian Harl E<lt>sh at tokkee.orgE<gt>.
+
+=cut
diff --git a/src/common.c b/src/common.c
index 2598036ddff77d0c7aac985771658ce67c1bc788..1c80e8f1b8cd6d2f85dfebd482e30caf88cdf6d0 100644 (file)
--- a/src/common.c
+++ b/src/common.c
/**
* collectd - src/common.c
- * Copyright (C) 2005-2009 Florian octo Forster
+ * Copyright (C) 2005-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
* Niki W. Waibel <niki.waibel@gmx.net>
* Sebastian Harl <sh at tokkee.org>
* Michał Mirosław <mirq-linux at rere.qmqm.pl>
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_cache.h"
#if HAVE_PTHREAD_H
# include <pthread.h>
return (0);
} /* int format_name */
+int format_values (char *ret, size_t ret_len, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl,
+ _Bool store_rates)
+{
+ size_t offset = 0;
+ int status;
+ int i;
+ gauge_t *rates = NULL;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ memset (ret, 0, ret_len);
+
+#define BUFFER_ADD(...) do { \
+ status = ssnprintf (ret + offset, ret_len - offset, \
+ __VA_ARGS__); \
+ if (status < 1) \
+ { \
+ sfree (rates); \
+ return (-1); \
+ } \
+ else if (((size_t) status) >= (ret_len - offset)) \
+ { \
+ sfree (rates); \
+ return (-1); \
+ } \
+ else \
+ offset += ((size_t) status); \
+} while (0)
+
+ BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time));
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_GAUGE)
+ BUFFER_ADD (":%f", vl->values[i].gauge);
+ else if (store_rates)
+ {
+ if (rates == NULL)
+ rates = uc_get_rate (ds, vl);
+ if (rates == NULL)
+ {
+ WARNING ("format_values: "
+ "uc_get_rate failed.");
+ return (-1);
+ }
+ BUFFER_ADD (":%g", rates[i]);
+ }
+ else if (ds->ds[i].type == DS_TYPE_COUNTER)
+ BUFFER_ADD (":%llu", vl->values[i].counter);
+ else if (ds->ds[i].type == DS_TYPE_DERIVE)
+ BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
+ else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+ BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
+ else
+ {
+ ERROR ("format_values plugin: Unknown data source type: %i",
+ ds->ds[i].type);
+ sfree (rates);
+ return (-1);
+ }
+ } /* for ds->ds_num */
+
+#undef BUFFER_ADD
+
+ sfree (rates);
+ return (0);
+} /* }}} int format_values */
+
int parse_identifier (char *str, char **ret_host,
char **ret_plugin, char **ret_plugin_instance,
char **ret_type, char **ret_type_instance)
return (0);
} /* int parse_identifier */
+int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */
+{
+ char str_copy[6 * DATA_MAX_NAME_LEN];
+ char *host = NULL;
+ char *plugin = NULL;
+ char *plugin_instance = NULL;
+ char *type = NULL;
+ char *type_instance = NULL;
+ int status;
+
+ if ((str == NULL) || (vl == NULL))
+ return (EINVAL);
+
+ sstrncpy (str_copy, str, sizeof (str_copy));
+
+ status = parse_identifier (str_copy, &host,
+ &plugin, &plugin_instance,
+ &type, &type_instance);
+ if (status != 0)
+ return (status);
+
+ sstrncpy (vl->host, host, sizeof (host));
+ sstrncpy (vl->plugin, plugin, sizeof (plugin));
+ sstrncpy (vl->plugin_instance, plugin_instance, sizeof (plugin_instance));
+ sstrncpy (vl->type, type, sizeof (type));
+ sstrncpy (vl->type_instance, type_instance, sizeof (type_instance));
+
+ return (0);
+} /* }}} int parse_identifier_vl */
+
int parse_value (const char *value, value_t *ret_value, int ds_type)
{
char *endptr = NULL;
if (i == -1)
{
if (strcmp ("N", ptr) == 0)
- vl->time = time (NULL);
+ vl->time = cdtime ();
else
- vl->time = (time_t) atoi (ptr);
+ {
+ char *endptr = NULL;
+ double tmp;
+
+ errno = 0;
+ tmp = strtod (ptr, &endptr);
+ if ((errno != 0) /* Overflow */
+ || (endptr == ptr) /* Invalid string */
+ || (endptr == NULL) /* This should not happen */
+ || (*endptr != 0)) /* Trailing chars */
+ return (-1);
+
+ vl->time = DOUBLE_TO_CDTIME_T (tmp);
+ }
}
else
{
diff --git a/src/common.h b/src/common.h
index 229f7098d6c8948ed69656f5dc30d3e69f47d705..425d6e2d6c5b74b729439be7be89b095b9e7c2d0 100644 (file)
--- a/src/common.h
+++ b/src/common.h
/**
* collectd - src/common.h
- * Copyright (C) 2005-2009 Florian octo Forster
+ * Copyright (C) 2005-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
* Niki W. Waibel <niki.waibel@gmx.net>
**/
#define FORMAT_VL(ret, ret_len, vl) \
format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
(vl)->type, (vl)->type_instance)
+int format_values (char *ret, size_t ret_len,
+ const data_set_t *ds, const value_list_t *vl,
+ _Bool store_rates);
int parse_identifier (char *str, char **ret_host,
char **ret_plugin, char **ret_plugin_instance,
char **ret_type, char **ret_type_instance);
+int parse_identifier_vl (const char *str, value_list_t *vl);
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);
diff --git a/src/configfile.c b/src/configfile.c
index 0b7786f929605a311b4c8705a48e73a80ace68b4..e162dd995edf2efe69d37cf80616c1489f9d9717 100644 (file)
--- a/src/configfile.c
+++ b/src/configfile.c
/**
* collectd - src/configfile.c
- * Copyright (C) 2005-2009 Florian octo Forster
+ * Copyright (C) 2005-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
{"BaseDir", NULL, PKGLOCALSTATEDIR},
{"PIDFile", NULL, PIDFILE},
{"Hostname", NULL, NULL},
- {"FQDNLookup", NULL, "false"},
+ {"FQDNLookup", NULL, "true"},
{"Interval", NULL, "10"},
{"ReadThreads", NULL, "5"},
{"Timeout", NULL, "2"},
@@ -1014,11 +1014,37 @@ int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
return (-1);
}
- *ret_bool = ci->values[0].value.boolean ? true : false;
+ *ret_bool = ci->values[0].value.boolean ? 1 : 0;
return (0);
} /* }}} int cf_util_get_boolean */
+int cf_util_get_flag (const oconfig_item_t *ci, /* {{{ */
+ unsigned int *ret_value, unsigned int flag)
+{
+ int status;
+ _Bool b;
+
+ if (ret_value == NULL)
+ return (EINVAL);
+
+ b = 0;
+ status = cf_util_get_boolean (ci, &b);
+ if (status != 0)
+ return (status);
+
+ if (b)
+ {
+ *ret_value |= flag;
+ }
+ else
+ {
+ *ret_value &= ~flag;
+ }
+
+ return (0);
+} /* }}} int cf_util_get_flag */
+
/* Assures that the config option is a string. The string is then converted to
* a port number using `service_name_to_port_number' and returned. Returns the
* port number in the range [1-65535] or less than zero upon failure. */
return (service_name_to_port_number (ci->values[0].value.string));
} /* }}} int cf_util_get_port_number */
+
+int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value) /* {{{ */
+{
+ if ((ci == NULL) || (ret_value == NULL))
+ return (EINVAL);
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+ {
+ ERROR ("cf_util_get_cdtime: The %s option requires "
+ "exactly one numeric argument.", ci->key);
+ return (-1);
+ }
+
+ if (ci->values[0].value.number < 0.0)
+ {
+ ERROR ("cf_util_get_cdtime: The numeric argument of the %s "
+ "option must not be negative.", ci->key);
+ return (-1);
+ }
+
+ *ret_value = DOUBLE_TO_CDTIME_T (ci->values[0].value.number);
+
+ return (0);
+} /* }}} int cf_util_get_cdtime */
+
diff --git a/src/configfile.h b/src/configfile.h
index 432e09f5ba73f0663669dfe0f6bae7f65e154f48..65b1efcdd5a07d9a0d7fe7d50228470475bdb524 100644 (file)
--- a/src/configfile.h
+++ b/src/configfile.h
#define CONFIGFILE_H
/**
* collectd - src/configfile.h
- * Copyright (C) 2005,2006 Florian octo Forster
+ * Copyright (C) 2005-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
**/
#include "collectd.h"
+#include "utils_time.h"
#include "liboconfig/oconfig.h"
/*
* Otherwise, `ret_bool' is not changed and non-zero is returned. */
int cf_util_get_boolean (const oconfig_item_t *ci, _Bool *ret_bool);
+/* Assures the config option is a boolean and set or unset the given flag in
+ * `ret_value' as appropriate. Returns non-zero on error. */
+int cf_util_get_flag (const oconfig_item_t *ci,
+ unsigned int *ret_value, unsigned int flag);
+
/* Assures that the config option is a string. The string is then converted to
* a port number using `service_name_to_port_number' and returned. Returns the
* port number in the range [1-65535] or less than zero upon failure. */
int cf_util_get_port_number (const oconfig_item_t *ci);
+int cf_util_get_cdtime (const oconfig_item_t *ci, cdtime_t *ret_value);
+
#endif /* defined(CONFIGFILE_H) */
diff --git a/src/contextswitch.c b/src/contextswitch.c
index 06055ca59372299616a6f8b1bf105d30e34760f4..c207318f9d62425fbfb18e7e86727bce62b65bcb 100644 (file)
--- a/src/contextswitch.c
+++ b/src/contextswitch.c
/**
* collectd - src/contextswitch.c
* Copyright (C) 2009 Patrik Weiskircher
+ * Copyright (C) 2010 Kimo Rosenbaum
*
* 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
*
* Authors:
* Patrik Weiskircher <weiskircher at inqnet.at>
+ * Kimo Rosenbaum <http://github.com/kimor79>
**/
#include "collectd.h"
#include "common.h"
#include "plugin.h"
-#if !KERNEL_LINUX
+#ifdef HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+#endif
+
+#if HAVE_SYSCTLBYNAME
+/* no global variables */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif KERNEL_LINUX
+/* no global variables */
+/* #endif KERNEL_LINUX */
+
+#else
# error "No applicable input method."
#endif
static int cs_read (void)
{
+#if HAVE_SYSCTLBYNAME
+ int value = 0;
+ size_t value_len = sizeof (value);
+ int status;
+
+ status = sysctlbyname ("vm.stats.sys.v_swtch",
+ &value, &value_len,
+ /* new pointer = */ NULL, /* new length = */ 0);
+ if (status != 0)
+ {
+ ERROR("contextswitch plugin: sysctlbyname "
+ "(vm.stats.sys.v_swtch) failed");
+ return (-1);
+ }
+
+ cs_submit (value);
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif KERNEL_LINUX
FILE *fh;
char buffer[64];
int numfields;
if (status == -2)
ERROR ("contextswitch plugin: Unable to find context switch value.");
+#endif /* KERNEL_LINUX */
return status;
}
diff --git a/src/cpu.c b/src/cpu.c
index 7aa6361bad3b7959f3dcba1a98ecd079fc48fc04..3dbe80eeb1b7f4727b491803e93e841cac09200a 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
DEBUG ("host_processors returned %i %s", (int) cpu_list_len, cpu_list_len == 1 ? "processor" : "processors");
INFO ("cpu plugin: Found %i processor%s.", (int) cpu_list_len, cpu_list_len == 1 ? "" : "s");
- cpu_temp_retry_max = 86400 / interval_g;
+ cpu_temp_retry_max = 86400 / CDTIME_T_TO_TIME_T (interval_g);
/* #endif PROCESSOR_CPU_LOAD_INFO */
#elif defined(HAVE_LIBKSTAT)
diff --git a/src/cpython.h b/src/cpython.h
index 46e2301a1874f566098c15d54774fb1925b786de..4b8aa72143167864ff575147c5ef19949997ab50 100644 (file)
--- a/src/cpython.h
+++ b/src/cpython.h
PluginData data;
PyObject *values; /* Sequence */
PyObject *meta; /* dict */
- int interval;
+ double interval;
} Values;
PyTypeObject ValuesType;
#define Values_New() PyObject_CallFunctionObjArgs((PyObject *) &ValuesType, (void *) 0)
diff --git a/src/csv.c b/src/csv.c
index 96c1e3e7aba250179d6c950abbdb12f5fc7d7def..87a7b4e3a9d0a8cf82927d49913b947b699efe60 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
memset (buffer, '\0', buffer_len);
- status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ status = ssnprintf (buffer, buffer_len, "%.3f",
+ CDTIME_T_TO_DOUBLE (vl->time));
if ((status < 1) || (status >= buffer_len))
return (-1);
offset = status;
}
fprintf (use_stdio == 1 ? stdout : stderr,
- "PUTVAL %s interval=%i %s\n",
- filename, vl->interval, values);
+ "PUTVAL %s interval=%.3f %s\n",
+ filename,
+ CDTIME_T_TO_DOUBLE (vl->interval),
+ values);
return (0);
}
diff --git a/src/curl.c b/src/curl.c
index a533e147b1b6e2af1dcf00ff7634667b20bf4784..8b95c80febb279a1c6f2e0579787274bb113967f 100644 (file)
--- a/src/curl.c
+++ b/src/curl.c
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
@@ -596,7 +595,6 @@ static void cc_submit_response_time (const web_page_t *wp, double seconds) /* {{
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
diff --git a/src/curl_json.c b/src/curl_json.c
index 0527dc8d772ef0cce5952aac2a60f11cbb62f209..433764e285014902dd7bbe7f53371ed2cf364a7b 100644 (file)
--- a/src/curl_json.c
+++ b/src/curl_json.c
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)
+ if ((status != yajl_status_ok)
+ && (status != yajl_status_insufficient_data))
{
unsigned char *msg =
- yajl_get_error(db->yajl, 1, (unsigned char *)buf, len);
+ yajl_get_error(db->yajl, /* verbose = */ 1,
+ /* jsonText = */ (unsigned char *) buf, (unsigned int) len);
ERROR ("curl_json plugin: yajl_parse failed: %s", msg);
yajl_free_error(db->yajl, msg);
return (0); /* abort write callback */
}
status = curl_easy_perform (curl);
-
- yajl_free (db->yajl);
- db->yajl = yprev;
+ if (status != 0)
+ {
+ ERROR ("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)",
+ status, db->curl_errbuf, url);
+ yajl_free (db->yajl);
+ db->yajl = yprev;
+ return (-1);
+ }
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
/* The response code is zero if a non-HTTP transport was used. */
if ((rc != 0) && (rc != 200))
{
- ERROR ("curl_json plugin: curl_easy_perform failed with response code %ld (%s)",
- rc, url);
+ ERROR ("curl_json plugin: curl_easy_perform failed with "
+ "response code %ld (%s)", rc, url);
+ yajl_free (db->yajl);
+ db->yajl = yprev;
return (-1);
}
- if (status != 0)
+ status = yajl_parse_complete (db->yajl);
+ if (status != yajl_status_ok)
{
- ERROR ("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)",
- status, db->curl_errbuf, url);
+ unsigned char *errmsg;
+
+ errmsg = yajl_get_error (db->yajl, /* verbose = */ 0,
+ /* jsonText = */ NULL, /* jsonTextLen = */ 0);
+ ERROR ("curl_json plugin: yajl_parse_complete failed: %s",
+ (char *) errmsg);
+ yajl_free_error (db->yajl, errmsg);
+ yajl_free (db->yajl);
+ db->yajl = yprev;
return (-1);
}
+ yajl_free (db->yajl);
+ db->yajl = yprev;
return (0);
} /* }}} int cj_curl_perform */
diff --git a/src/dbi.c b/src/dbi.c
index 77f393f5fc6a606c8151860617f4da4b9f62a0d3..caa41ef64023d247bd14721f936b0323df0ccfae 100644 (file)
--- a/src/dbi.c
+++ b/src/dbi.c
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Query", child->key) == 0)
udb_query_create (&queries, &queries_num, child,
- /* callback = */ NULL, /* legacy mode = */ 0);
+ /* callback = */ NULL);
else if (strcasecmp ("Database", child->key) == 0)
cdbi_config_add_database (child);
else
udb_query_prepare_result (q, prep_area, hostname_g,
/* plugin = */ "dbi", db->name,
- column_names, column_num, /* interval = */ -1);
+ column_names, column_num, /* interval = */ 0);
/* 0 = error; 1 = success; */
status = dbi_result_first_row (res); /* {{{ */
diff --git a/src/df.c b/src/df.c
index fc80ac3f08c27c659d4261427be91345c62238be..4b3cba019cea9219289cc8adef7633a05e30a9ba 100644 (file)
--- a/src/df.c
+++ b/src/df.c
static ignorelist_t *il_mountpoint = NULL;
static ignorelist_t *il_fstype = NULL;
-static _Bool by_device = false;
-static _Bool report_reserved = false;
-static _Bool report_inodes = false;
+static _Bool by_device = 0;
+static _Bool report_inodes = 0;
static int df_init (void)
{
else if (strcasecmp (key, "ReportByDevice") == 0)
{
if (IS_TRUE (value))
- by_device = true;
-
- return (0);
- }
- else if (strcasecmp (key, "ReportReserved") == 0)
- {
- if (IS_TRUE (value))
- report_reserved = true;
- else
- report_reserved = false;
+ by_device = 1;
return (0);
}
else if (strcasecmp (key, "ReportInodes") == 0)
{
if (IS_TRUE (value))
- report_inodes = true;
+ report_inodes = 1;
else
- report_inodes = false;
+ report_inodes = 0;
return (0);
}
return (-1);
}
-static void df_submit_two (char *df_name,
- const char *type,
- gauge_t df_used,
- gauge_t df_free)
-{
- value_t values[2];
- value_list_t vl = VALUE_LIST_INIT;
-
- values[0].gauge = df_used;
- values[1].gauge = df_free;
-
- vl.values = values;
- vl.values_len = 2;
- sstrncpy (vl.host, hostname_g, sizeof (vl.host));
- sstrncpy (vl.plugin, "df", sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- sstrncpy (vl.type, type, sizeof (vl.type));
- sstrncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
-
- plugin_dispatch_values (&vl);
-} /* void df_submit_two */
-
__attribute__ ((nonnull(2)))
static void df_submit_one (char *plugin_instance,
const char *type, const char *type_instance,
{
unsigned long long blocksize;
char disk_name[256];
+ uint64_t blk_free;
+ uint64_t blk_reserved;
+ uint64_t blk_used;
if (ignorelist_match (il_device,
(mnt_ptr->spec_device != NULL)
blocksize = BLOCKSIZE(statbuf);
- if (report_reserved)
- {
- uint64_t blk_free;
- uint64_t blk_reserved;
- uint64_t blk_used;
-
- /* Sanity-check for the values in the struct */
- if (statbuf.f_bfree < statbuf.f_bavail)
- statbuf.f_bfree = statbuf.f_bavail;
- if (statbuf.f_blocks < statbuf.f_bfree)
- statbuf.f_blocks = statbuf.f_bfree;
-
- blk_free = (uint64_t) statbuf.f_bavail;
- blk_reserved = (uint64_t) (statbuf.f_bfree - statbuf.f_bavail);
- blk_used = (uint64_t) (statbuf.f_blocks - statbuf.f_bfree);
-
- df_submit_one (disk_name, "df_complex", "free",
- (gauge_t) (blk_free * blocksize));
- df_submit_one (disk_name, "df_complex", "reserved",
- (gauge_t) (blk_reserved * blocksize));
- df_submit_one (disk_name, "df_complex", "used",
- (gauge_t) (blk_used * blocksize));
- }
- else /* compatibility code */
- {
- gauge_t df_free;
- gauge_t df_used;
-
- df_free = statbuf.f_bfree * blocksize;
- df_used = (statbuf.f_blocks - statbuf.f_bfree) * blocksize;
-
- df_submit_two (disk_name, "df", df_used, df_free);
- }
+ /* Sanity-check for the values in the struct */
+ if (statbuf.f_bfree < statbuf.f_bavail)
+ statbuf.f_bfree = statbuf.f_bavail;
+ if (statbuf.f_blocks < statbuf.f_bfree)
+ statbuf.f_blocks = statbuf.f_bfree;
+
+ blk_free = (uint64_t) statbuf.f_bavail;
+ blk_reserved = (uint64_t) (statbuf.f_bfree - statbuf.f_bavail);
+ blk_used = (uint64_t) (statbuf.f_blocks - statbuf.f_bfree);
+
+ df_submit_one (disk_name, "df_complex", "free",
+ (gauge_t) (blk_free * blocksize));
+ df_submit_one (disk_name, "df_complex", "reserved",
+ (gauge_t) (blk_reserved * blocksize));
+ df_submit_one (disk_name, "df_complex", "used",
+ (gauge_t) (blk_used * blocksize));
/* inode handling */
if (report_inodes)
diff --git a/src/dns.c b/src/dns.c
index f3280c0bed9f65ef37d3e8e554be640ca36ab83d..47da4e94c122e60dbd3084212e09e71cb3e5fbc1 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
{
counter_list_t *entry;
- DEBUG ("counter_list_search (list = %p, key = %u)",
- (void *) *list, key);
-
for (entry = *list; entry != NULL; entry = entry->next)
if (entry->key == key)
break;
- DEBUG ("return (%p)", (void *) entry);
return (entry);
}
{
counter_list_t *entry;
- DEBUG ("counter_list_create (list = %p, key = %u, value = %u)",
- (void *) *list, key, value);
-
entry = (counter_list_t *) malloc (sizeof (counter_list_t));
if (entry == NULL)
return (NULL);
last->next = entry;
}
- DEBUG ("return (%p)", (void *) entry);
return (entry);
}
{
counter_list_t *entry;
- DEBUG ("counter_list_add (list = %p, key = %u, increment = %u)",
- (void *) *list, key, increment);
-
entry = counter_list_search (list, key);
if (entry != NULL)
{
counter_list_create (list, key, increment);
}
- DEBUG ("return ()");
}
static int dns_config (const char *key, const char *value)
pcap_obj = pcap_open_live ((pcap_device != NULL) ? pcap_device : "any",
PCAP_SNAPLEN,
0 /* Not promiscuous */,
- interval_g,
+ (int) CDTIME_T_TO_MS (interval_g / 2),
pcap_error);
if (pcap_obj == NULL)
{
return (NULL);
}
- DEBUG ("PCAP object created.");
+ DEBUG ("dns plugin: PCAP object created.");
dnstop_set_pcap_obj (pcap_obj);
dnstop_set_callback (dns_child_callback);
ERROR ("dns plugin: Listener thread is exiting "
"abnormally: %s", pcap_geterr (pcap_obj));
- DEBUG ("child is exiting");
+ DEBUG ("dns plugin: Child is exiting.");
pcap_close (pcap_obj);
listen_thread_init = 0;
for (i = 0; i < len; i++)
{
- DEBUG ("qtype = %u; counter = %u;", keys[i], values[i]);
+ DEBUG ("dns plugin: qtype = %u; counter = %u;", keys[i], values[i]);
submit_counter ("dns_qtype", qtype_str (keys[i]), values[i]);
}
for (i = 0; i < len; i++)
{
- DEBUG ("opcode = %u; counter = %u;", keys[i], values[i]);
+ DEBUG ("dns plugin: opcode = %u; counter = %u;", keys[i], values[i]);
submit_counter ("dns_opcode", opcode_str (keys[i]), values[i]);
}
for (i = 0; i < len; i++)
{
- DEBUG ("rcode = %u; counter = %u;", keys[i], values[i]);
+ DEBUG ("dns plugin: rcode = %u; counter = %u;", keys[i], values[i]);
submit_counter ("dns_rcode", rcode_str (keys[i]), values[i]);
}
diff --git a/src/exec.c b/src/exec.c
index c64f949fc57b4ac5cff424a6b27e7cd283e13184..8d5ae9c3894932c6b21abbc1dc8bb952b84da870 100644 (file)
--- a/src/exec.c
+++ b/src/exec.c
char buffer[1024];
#ifdef HAVE_SETENV
- ssnprintf (buffer, sizeof (buffer), "%i", interval_g);
+ ssnprintf (buffer, sizeof (buffer), "%.3f", CDTIME_T_TO_DOUBLE (interval_g));
setenv ("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1);
ssnprintf (buffer, sizeof (buffer), "%s", hostname_g);
setenv ("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1);
#else
- ssnprintf (buffer, sizeof (buffer), "COLLECTD_INTERVAL=%i", interval_g);
+ ssnprintf (buffer, sizeof (buffer), "COLLECTD_INTERVAL=%.3f",
+ CDTIME_T_TO_DOUBLE (interval_g));
putenv (buffer);
ssnprintf (buffer, sizeof (buffer), "COLLECTD_HOSTNAME=%s", hostname_g);
return (handle_putnotif (stdout, buffer));
else
{
- /* For backwards compatibility */
- char tmp[1220];
- /* Let's annoy the user a bit.. */
- INFO ("exec plugin: Prepending `PUTVAL' to this line: %s", buffer);
- ssnprintf (tmp, sizeof (tmp), "PUTVAL %s", buffer);
- return (handle_putval (stdout, tmp));
+ ERROR ("exec plugin: Unable to parse command, ignoring line: \"%s\"",
+ buffer);
+ return (-1);
}
} /* int parse_line }}} */
diff --git a/src/gmond.c b/src/gmond.c
index 2ffc42a57d93aadf0b3d3bf080d6566c093592f4..8c774e536ff9c23e112c3e440d18aa15284478c4 100644 (file)
--- a/src/gmond.c
+++ b/src/gmond.c
map->type, map->type_instance,
ds->ds_num);
if (se != NULL)
- se->vl.interval = (int) msg_meta.metric.tmax;
+ se->vl.interval = TIME_T_TO_CDTIME_T (msg_meta.metric.tmax);
pthread_mutex_unlock (&staging_lock);
if (se == NULL)
diff --git a/src/hddtemp.c b/src/hddtemp.c
index 4e083753202718c588f72b0b1a2c58dc3ef1f37c..4428b75ddc086db0be4e8cff39f95f6437e09e89 100644 (file)
--- a/src/hddtemp.c
+++ b/src/hddtemp.c
/**
* collectd - src/hddtemp.c
* Copyright (C) 2005,2006 Vincent Stehlé
- * Copyright (C) 2006,2007 Florian octo Forster
+ * Copyright (C) 2006-2010 Florian octo Forster
* Copyright (C) 2008 Sebastian Harl
*
* This program is free software; you can redistribute it and/or modify it
static const char *config_keys[] =
{
"Host",
- "Port",
- "TranslateDevicename"
+ "Port"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-typedef struct hddname
-{
- int major;
- int minor;
- char *name;
- struct hddname *next;
-} hddname_t;
-
-static hddname_t *first_hddname = NULL;
static char *hddtemp_host = NULL;
static char hddtemp_port[16];
-static int translate_devicename = 1;
/*
* NAME
else
sstrncpy (hddtemp_port, value, sizeof (hddtemp_port));
}
- else if (strcasecmp (key, "TranslateDevicename") == 0)
- {
- if (IS_TRUE (value))
- translate_devicename = 1;
- else
- translate_devicename = 0;
- }
else
{
return (-1);
return (0);
}
-/* In the init-function we initialize the `hddname_t' list used to translate
- * disk-names. Under Linux that's done using `/proc/partitions'. Under other
- * operating-systems, it's not done at all. */
-static int hddtemp_init (void)
-{
-#if KERNEL_LINUX
- FILE *fh;
- char buf[1024];
- int buflen;
-
- char *fields[16];
- int num_fields;
-
- int major;
- int minor;
- char *name;
- hddname_t *next;
- hddname_t *entry;
-
- next = first_hddname;
- while (next != NULL)
- {
- entry = next;
- next = entry->next;
-
- free (entry->name);
- free (entry);
- }
- first_hddname = NULL;
-
- if ((fh = fopen ("/proc/partitions", "r")) != NULL)
- {
- DEBUG ("hddtemp plugin: Looking at /proc/partitions...");
-
- while (fgets (buf, sizeof (buf), fh) != NULL)
- {
- /* Delete trailing newlines */
- buflen = strlen (buf);
-
- while ((buflen > 0) && ((buf[buflen-1] == '\n') || (buf[buflen-1] == '\r')))
- buf[--buflen] = '\0';
-
- /* We want lines of the form:
- *
- * 3 1 77842926 hda1
- *
- * ...so, skip everything else. */
- if (buflen == 0)
- continue;
-
- num_fields = strsplit (buf, fields, 16);
-
- if (num_fields != 4)
- continue;
-
- major = atoi (fields[0]);
- minor = atoi (fields[1]);
-
- /* We try to keep only entries, which may correspond to
- * physical disks and that may have a corresponding
- * entry in the hddtemp daemon. Basically, this means
- * IDE and SCSI. */
- switch (major)
- {
- /* SCSI. */
- case SCSI_DISK0_MAJOR:
- case SCSI_DISK1_MAJOR:
- case SCSI_DISK2_MAJOR:
- case SCSI_DISK3_MAJOR:
- case SCSI_DISK4_MAJOR:
- case SCSI_DISK5_MAJOR:
- case SCSI_DISK6_MAJOR:
- case SCSI_DISK7_MAJOR:
-#ifdef SCSI_DISK8_MAJOR
- case SCSI_DISK8_MAJOR:
- case SCSI_DISK9_MAJOR:
- case SCSI_DISK10_MAJOR:
- case SCSI_DISK11_MAJOR:
- case SCSI_DISK12_MAJOR:
- case SCSI_DISK13_MAJOR:
- case SCSI_DISK14_MAJOR:
- case SCSI_DISK15_MAJOR:
-#endif /* SCSI_DISK8_MAJOR */
- /* SCSI disks minors are multiples of 16.
- * Keep only those. */
- if (minor % 16)
- continue;
- break;
-
- /* IDE. */
- case IDE0_MAJOR:
- case IDE1_MAJOR:
- case IDE2_MAJOR:
- case IDE3_MAJOR:
- case IDE4_MAJOR:
- case IDE5_MAJOR:
- case IDE6_MAJOR:
- case IDE7_MAJOR:
- case IDE8_MAJOR:
- case IDE9_MAJOR:
- /* IDE disks minors can only be 0 or 64.
- * Keep only those. */
- if(minor != 0 && minor != 64)
- continue;
- break;
-
- /* Skip all other majors. */
- default:
- DEBUG ("hddtemp plugin: Skipping unknown major %i", major);
- continue;
- } /* switch (major) */
-
- if ((name = strdup (fields[3])) == NULL)
- {
- ERROR ("hddtemp plugin: strdup(%s) == NULL", fields[3]);
- continue;
- }
-
- if ((entry = (hddname_t *) malloc (sizeof (hddname_t))) == NULL)
- {
- ERROR ("hddtemp plugin: malloc (%u) == NULL",
- (unsigned int) sizeof (hddname_t));
- free (name);
- continue;
- }
-
- DEBUG ("hddtemp plugin: Found disk: %s (%u:%u).", name, major, minor);
-
- entry->major = major;
- entry->minor = minor;
- entry->name = name;
- entry->next = NULL;
-
- if (first_hddname == NULL)
- {
- first_hddname = entry;
- }
- else
- {
- entry->next = first_hddname;
- first_hddname = entry;
- }
- }
- fclose (fh);
- }
-#if COLLECT_DEBUG
- else
- {
- char errbuf[1024];
- DEBUG ("hddtemp plugin: Could not open /proc/partitions: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- }
-#endif /* COLLECT_DEBUG */
-#endif /* KERNEL_LINUX */
-
- return (0);
-} /* int hddtemp_init */
-
-/*
- * hddtemp_get_major_minor
- *
- * Description:
- * Try to "cook" a bit the drive name as returned
- * by the hddtemp daemon. The intend is to transform disk
- * names into <major>-<minor> when possible.
- */
-static char *hddtemp_get_major_minor (char *drive)
-{
- hddname_t *list;
- char *ret;
-
- for (list = first_hddname; list != NULL; list = list->next)
- if (strcmp (drive, list->name) == 0)
- break;
-
- if (list == NULL)
- {
- DEBUG ("hddtemp plugin: Don't know %s, keeping name as-is.", drive);
- return (strdup (drive));
- }
-
- if ((ret = (char *) malloc (128 * sizeof (char))) == NULL)
- return (NULL);
-
- if (ssnprintf (ret, 128, "%i-%i", list->major, list->minor) >= 128)
- {
- free (ret);
- return (NULL);
- }
-
- return (ret);
-}
-
static void hddtemp_submit (char *type_instance, double value)
{
value_t values[1];
for (i = 0; i < num_disks; i++)
{
- char *name, *major_minor;
+ char *name;
double temperature;
char *mode;
if (mode[0] == 'F')
temperature = (temperature - 32.0) * 5.0 / 9.0;
- if (translate_devicename
- && (major_minor = hddtemp_get_major_minor (name)) != NULL)
- {
- hddtemp_submit (major_minor, temperature);
- free (major_minor);
- }
- else
- {
- hddtemp_submit (name, temperature);
- }
+ hddtemp_submit (name, temperature);
}
return (0);
{
plugin_register_config ("hddtemp", hddtemp_config,
config_keys, config_keys_num);
- plugin_register_init ("hddtemp", hddtemp_init);
plugin_register_read ("hddtemp", hddtemp_read);
}
diff --git a/src/interface.c b/src/interface.c
index 1ba6c8c32b73199823134d1662d89975065dc1d9..177afbaa0847b8f1db0dac2dd89bf6d6bf8bb19e 100644 (file)
--- a/src/interface.c
+++ b/src/interface.c
vl.values_len = 2;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "interface", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
sstrncpy (vl.type, type, sizeof (vl.type));
- sstrncpy (vl.type_instance, dev, sizeof (vl.type_instance));
plugin_dispatch_values (&vl);
} /* void if_submit */
diff --git a/src/ipmi.c b/src/ipmi.c
index 95b3dbf5625fcd4c09aef04d2a880c5ca85d2ae8..f341320ddec54ed9135f6cec34759f30eb74ecd7 100644 (file)
--- a/src/ipmi.c
+++ b/src/ipmi.c
if (c_ipmi_nofiy_notpresent)
{
- notification_t n = { NOTIF_WARNING, time(NULL), "", "", "ipmi",
+ notification_t n = { NOTIF_WARNING, cdtime (), "", "", "ipmi",
"", "", "", NULL };
sstrncpy (n.host, hostname_g, sizeof (n.host));
if (c_ipmi_nofiy_notpresent)
{
- notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+ notification_t n = { NOTIF_OKAY, cdtime (), "", "", "ipmi",
"", "", "", NULL };
sstrncpy (n.host, hostname_g, sizeof (n.host));
if (c_ipmi_nofiy_add && (c_ipmi_init_in_progress == 0))
{
- notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+ notification_t n = { NOTIF_OKAY, cdtime (), "", "", "ipmi",
"", "", "", NULL };
sstrncpy (n.host, hostname_g, sizeof (n.host));
if (c_ipmi_nofiy_remove && c_ipmi_active)
{
- notification_t n = { NOTIF_WARNING, time(NULL), "", "",
+ notification_t n = { NOTIF_WARNING, cdtime (), "", "",
"ipmi", "", "", "", NULL };
sstrncpy (n.host, hostname_g, sizeof (n.host));
int status;
/* Don't send `ADD' notifications during startup (~ 1 minute) */
- c_ipmi_init_in_progress = 1 + (60 / interval_g);
+ time_t iv = CDTIME_T_TO_TIME_T (interval_g);
+ c_ipmi_init_in_progress = 1 + (60 / iv);
c_ipmi_active = 1;
diff --git a/src/ipvs.c b/src/ipvs.c
index 87eee108a79410853b6f02e107697b7a358f465a..f3a583b9d510edfbdae487d4aed2ab7ac2a91538 100644 (file)
--- a/src/ipvs.c
+++ b/src/ipvs.c
vl.values = values;
vl.values_len = 1;
- vl.interval = interval_g;
-
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
vl.values = values;
vl.values_len = 2;
- vl.interval = interval_g;
-
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
diff --git a/src/java.c b/src/java.c
index 528ec9c475656140b4572bf30361c1c082fbd46b..3089a5337fdc4b21b5c592d06185789da8e72107 100644 (file)
--- a/src/java.c
+++ b/src/java.c
static int cjni_read (user_data_t *user_data);
static int cjni_write (const data_set_t *ds, const value_list_t *vl,
user_data_t *ud);
-static int cjni_flush (int timeout, const char *identifier, user_data_t *ud);
+static int cjni_flush (cdtime_t timeout, const char *identifier, user_data_t *ud);
static void cjni_log (int severity, const char *message, user_data_t *ud);
static int cjni_notification (const notification_t *n, user_data_t *ud);
#undef SET_STRING
/* Set the `time' member. Java stores time in milliseconds. */
- status = ctoj_long (jvm_env, ((jlong) vl->time) * ((jlong) 1000),
+ status = ctoj_long (jvm_env, (jlong) CDTIME_T_TO_MS (vl->time),
c_valuelist, o_valuelist, "setTime");
if (status != 0)
{
}
/* Set the `interval' member.. */
- status = ctoj_long (jvm_env, (jlong) vl->interval,
+ status = ctoj_long (jvm_env,
+ (jlong) CDTIME_T_TO_MS (vl->interval),
c_valuelist, o_valuelist, "setInterval");
if (status != 0)
{
return (NULL);
}
- /* Set the `interval' member.. */
+ /* Set the `severity' member.. */
status = ctoj_int (jvm_env, (jint) n->severity,
c_notification, o_notification, "setSeverity");
if (status != 0)
return (-1);
}
/* Java measures time in milliseconds. */
- vl->time = (time_t) (tmp_long / ((jlong) 1000));
+ vl->time = MS_TO_CDTIME_T (tmp_long);
status = jtoc_long (jvm_env, &tmp_long,
class_ptr, object_ptr, "getInterval");
ERROR ("java plugin: jtoc_value_list: jtoc_long (getInterval) failed.");
return (-1);
}
- vl->interval = (int) tmp_long;
+ vl->interval = MS_TO_CDTIME_T (tmp_long);
status = jtoc_values_array (jvm_env, ds, vl, class_ptr, object_ptr);
if (status != 0)
@@ -1729,7 +1730,7 @@ static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{
case CB_TYPE_FLUSH:
method_name = "flush";
- method_signature = "(ILjava/lang/String;)I";
+ method_signature = "(Ljava/lang/Number;Ljava/lang/String;)I";
break;
case CB_TYPE_SHUTDOWN:
@@ -2551,11 +2552,12 @@ static int cjni_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
} /* }}} int cjni_write */
/* Call the CB_TYPE_FLUSH callback pointed to by the `user_data_t' pointer. */
-static int cjni_flush (int timeout, const char *identifier, /* {{{ */
+static int cjni_flush (cdtime_t timeout, const char *identifier, /* {{{ */
user_data_t *ud)
{
JNIEnv *jvm_env;
cjni_callback_info_t *cbi;
+ jobject o_timeout;
jobject o_identifier;
int status;
int ret_status;
cbi = (cjni_callback_info_t *) ud->data;
+ o_timeout = ctoj_jdouble_to_number (jvm_env,
+ (jdouble) CDTIME_T_TO_DOUBLE (timeout));
+ if (o_timeout == NULL)
+ {
+ ERROR ("java plugin: cjni_flush: Converting double "
+ "to Number object failed.");
+ return (-1);
+ }
+
o_identifier = NULL;
if (identifier != NULL)
{
o_identifier = (*jvm_env)->NewStringUTF (jvm_env, identifier);
if (o_identifier == NULL)
{
+ (*jvm_env)->DeleteLocalRef (jvm_env, o_timeout);
ERROR ("java plugin: cjni_flush: NewStringUTF failed.");
return (-1);
}
}
ret_status = (*jvm_env)->CallIntMethod (jvm_env,
- cbi->object, cbi->method, (jint) timeout, o_identifier);
+ cbi->object, cbi->method, o_timeout, o_identifier);
(*jvm_env)->DeleteLocalRef (jvm_env, o_identifier);
+ (*jvm_env)->DeleteLocalRef (jvm_env, o_timeout);
status = cjni_thread_detach ();
if (status != 0)
index 0c748ba7fa47e3b30f1d2a8d5c30dffdfd70d3e3..75ac7b6da0b96c1d901007ab8dd1f2d4c0470e06 100644 (file)
else if (vl->values_types[i] == LCC_TYPE_GAUGE)
{
if (isnan (vl->values[i].gauge))
- SSTRCPY (command, ":U");
+ SSTRCATF (command, ":U");
else
SSTRCATF (command, ":%g", vl->values[i].gauge);
}
index 11e7b13cc31575ee83d598a1f75984ae19b09e63..990035381c75d4198cf8fd6e1c202cb9891bf9ea 100644 (file)
lcc_identifier_t identifier;
};
typedef struct lcc_value_list_s lcc_value_list_t;
-#define LCC_VALUE_LIST_INIT { NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
+#define LCC_VALUE_LIST_INIT { NULL, NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
struct lcc_connection_s;
typedef struct lcc_connection_s lcc_connection_t;
diff --git a/src/libvirt.c b/src/libvirt.c
index bcbf0e6ad51a5527df6b9a74a6a7322bd916881c..5d9d84b6fa1a124d79fda845b3d0fba8fbbba39e 100644 (file)
--- a/src/libvirt.c
+++ b/src/libvirt.c
"IgnoreSelected",
"HostnameFormat",
+ "InterfaceFormat",
NULL
};
struct interface_device {
virDomainPtr dom; /* domain */
char *path; /* name of interface device */
+ char *address; /* mac address of interface device */
};
static struct interface_device *interface_devices = NULL;
static int nr_interface_devices = 0;
static void free_interface_devices (void);
-static int add_interface_device (virDomainPtr dom, const char *path);
+static int add_interface_device (virDomainPtr dom, const char *path, const char *address);
/* HostnameFormat. */
#define HF_MAX_FIELDS 3
static enum hf_field hostname_format[HF_MAX_FIELDS] =
{ hf_name };
+/* InterfaceFormat. */
+enum if_field {
+ if_address,
+ if_name
+};
+
+static enum if_field interface_format = if_name;
+
/* Time that we last refreshed. */
static time_t last_refresh = (time_t) 0;
static int refresh_lists (void);
-/* Submit functions. */
-static void cpu_submit (unsigned long long cpu_time,
- time_t t,
- virDomainPtr dom, const char *type);
-static void vcpu_submit (unsigned long long cpu_time,
- time_t t,
- virDomainPtr dom, int vcpu_nr, const char *type);
-static void submit_counter2 (const char *type, counter_t v0, counter_t v1,
- time_t t,
- virDomainPtr dom, const char *devname);
-
/* ERROR(...) macro for virterrors. */
#define VIRT_ERROR(conn,s) do { \
virErrorPtr err; \
if (err) ERROR ("%s: %s", (s), err->message); \
} while(0)
+static void
+init_value_list (value_list_t *vl, virDomainPtr dom)
+{
+ int i, n;
+ const char *name;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ char *host_ptr;
+ size_t host_len;
+
+ vl->interval = interval_g;
+
+ sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
+
+ vl->host[0] = '\0';
+ host_ptr = vl->host;
+ host_len = sizeof (vl->host);
+
+ /* Construct the hostname field according to HostnameFormat. */
+ for (i = 0; i < HF_MAX_FIELDS; ++i) {
+ if (hostname_format[i] == hf_none)
+ continue;
+
+ n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
+
+ if (i > 0 && n >= 1) {
+ strncat (vl->host, ":", 1);
+ n--;
+ }
+
+ switch (hostname_format[i]) {
+ case hf_none: break;
+ case hf_hostname:
+ strncat (vl->host, hostname_g, n);
+ break;
+ case hf_name:
+ name = virDomainGetName (dom);
+ if (name)
+ strncat (vl->host, name, n);
+ break;
+ case hf_uuid:
+ if (virDomainGetUUIDString (dom, uuid) == 0)
+ strncat (vl->host, uuid, n);
+ break;
+ }
+ }
+
+ vl->host[sizeof (vl->host) - 1] = '\0';
+} /* void init_value_list */
+
+static void
+cpu_submit (unsigned long long cpu_time,
+ virDomainPtr dom, const char *type)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ init_value_list (&vl, dom);
+
+ values[0].counter = cpu_time;
+
+ vl.values = values;
+ vl.values_len = 1;
+
+ sstrncpy (vl.type, type, sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+}
+
+static void
+vcpu_submit (counter_t cpu_time,
+ virDomainPtr dom, int vcpu_nr, const char *type)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ init_value_list (&vl, dom);
+
+ values[0].counter = cpu_time;
+ vl.values = values;
+ vl.values_len = 1;
+
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
+
+ plugin_dispatch_values (&vl);
+}
+
+static void
+submit_counter2 (const char *type, counter_t v0, counter_t v1,
+ virDomainPtr dom, const char *devname)
+{
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ init_value_list (&vl, dom);
+
+ values[0].counter = v0;
+ values[1].counter = v1;
+ vl.values = values;
+ vl.values_len = 2;
+
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* void submit_counter2 */
+
static int
lv_init (void)
{
n = strsplit (value_copy, fields, HF_MAX_FIELDS);
if (n < 1) {
- free (value_copy);
+ sfree (value_copy);
ERROR ("HostnameFormat: no fields");
return -1;
}
else if (strcasecmp (fields[i], "uuid") == 0)
hostname_format[i] = hf_uuid;
else {
- free (value_copy);
+ sfree (value_copy);
ERROR ("unknown HostnameFormat field: %s", fields[i]);
return -1;
}
}
- free (value_copy);
+ sfree (value_copy);
for (i = n; i < HF_MAX_FIELDS; ++i)
hostname_format[i] = hf_none;
return 0;
}
+ if (strcasecmp (key, "InterfaceFormat") == 0) {
+ if (strcasecmp (value, "name") == 0)
+ interface_format = if_name;
+ else if (strcasecmp (value, "address") == 0)
+ interface_format = if_address;
+ else {
+ ERROR ("unknown InterfaceFormat: %s", value);
+ return -1;
+ }
+ return 0;
+ }
+
/* Unrecognised option. */
return -1;
}
if (virDomainGetInfo (domains[i], &info) != 0)
continue;
- cpu_submit (info.cpuTime, t, domains[i], "virt_cpu_total");
+ cpu_submit (info.cpuTime, domains[i], "virt_cpu_total");
vinfo = malloc (info.nrVirtCpu * sizeof vinfo[0]);
if (vinfo == NULL) {
if (virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
NULL, 0) != 0) {
- free (vinfo);
+ sfree (vinfo);
continue;
}
for (j = 0; j < info.nrVirtCpu; ++j)
vcpu_submit (vinfo[j].cpuTime,
- t, domains[i], vinfo[j].number, "virt_vcpu");
+ domains[i], vinfo[j].number, "virt_vcpu");
- free (vinfo);
+ sfree (vinfo);
}
/* Get block device stats for each domain. */
if ((stats.rd_req != -1) && (stats.wr_req != -1))
submit_counter2 ("disk_ops",
(counter_t) stats.rd_req, (counter_t) stats.wr_req,
- t, block_devices[i].dom, block_devices[i].path);
+ block_devices[i].dom, block_devices[i].path);
if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1))
submit_counter2 ("disk_octets",
(counter_t) stats.rd_bytes, (counter_t) stats.wr_bytes,
- t, block_devices[i].dom, block_devices[i].path);
+ block_devices[i].dom, block_devices[i].path);
} /* for (nr_block_devices) */
/* Get interface stats for each domain. */
for (i = 0; i < nr_interface_devices; ++i) {
struct _virDomainInterfaceStats stats;
+ char *display_name = interface_devices[i].path;
+
+ if (interface_format == if_address)
+ display_name = interface_devices[i].address;
if (virDomainInterfaceStats (interface_devices[i].dom,
interface_devices[i].path,
if ((stats.rx_bytes != -1) && (stats.tx_bytes != -1))
submit_counter2 ("if_octets",
(counter_t) stats.rx_bytes, (counter_t) stats.tx_bytes,
- t, interface_devices[i].dom, interface_devices[i].path);
+ interface_devices[i].dom, display_name);
if ((stats.rx_packets != -1) && (stats.tx_packets != -1))
submit_counter2 ("if_packets",
(counter_t) stats.rx_packets, (counter_t) stats.tx_packets,
- t, interface_devices[i].dom, interface_devices[i].path);
+ interface_devices[i].dom, display_name);
if ((stats.rx_errs != -1) && (stats.tx_errs != -1))
submit_counter2 ("if_errors",
(counter_t) stats.rx_errs, (counter_t) stats.tx_errs,
- t, interface_devices[i].dom, interface_devices[i].path);
+ interface_devices[i].dom, display_name);
if ((stats.rx_drop != -1) && (stats.tx_drop != -1))
submit_counter2 ("if_dropped",
(counter_t) stats.rx_drop, (counter_t) stats.tx_drop,
- t, interface_devices[i].dom, interface_devices[i].path);
+ interface_devices[i].dom, display_name);
} /* for (nr_interface_devices) */
return 0;
n = virConnectListDomains (conn, domids, n);
if (n < 0) {
VIRT_ERROR (conn, "reading list of domains");
- free (domids);
+ sfree (domids);
return -1;
}
/* Network interfaces. */
xpath_obj = xmlXPathEval
- ((xmlChar *) "/domain/devices/interface/target[@dev]",
+ ((xmlChar *) "/domain/devices/interface[target[@dev]]",
xpath_ctx);
if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
xpath_obj->nodesetval == NULL)
goto cont;
- for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
- xmlNodePtr node;
+ xmlNodeSetPtr xml_interfaces = xpath_obj->nodesetval;
+
+ for (j = 0; j < xml_interfaces->nodeNr; ++j) {
char *path = NULL;
+ char *address = NULL;
+ xmlNodePtr xml_interface;
- node = xpath_obj->nodesetval->nodeTab[j];
- if (!node) continue;
- path = (char *) xmlGetProp (node, (xmlChar *) "dev");
- if (!path) continue;
+ xml_interface = xml_interfaces->nodeTab[j];
+ if (!xml_interface) continue;
+ xmlNodePtr child = NULL;
+
+ for (child = xml_interface->children; child; child = child->next) {
+ if (child->type != XML_ELEMENT_NODE) continue;
+
+ if (xmlStrEqual(child->name, (const xmlChar *) "target")) {
+ path = (char *) xmlGetProp (child, (const xmlChar *) "dev");
+ if (!path) continue;
+ } else if (xmlStrEqual(child->name, (const xmlChar *) "mac")) {
+ address = (char *) xmlGetProp (child, (const xmlChar *) "address");
+ if (!address) continue;
+ }
+ }
if (il_interface_devices &&
- ignore_device_match (il_interface_devices, name, path) != 0)
+ (ignore_device_match (il_interface_devices, name, path) != 0 ||
+ ignore_device_match (il_interface_devices, name, address) != 0))
goto cont3;
- add_interface_device (dom, path);
- cont3:
- if (path) xmlFree (path);
+ add_interface_device (dom, path, address);
+ cont3:
+ if (path) xmlFree (path);
+ if (address) xmlFree (address);
}
cont:
if (xpath_obj) xmlXPathFreeObject (xpath_obj);
if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
if (xml_doc) xmlFreeDoc (xml_doc);
- if (xml) free (xml);
+ sfree (xml);
}
- free (domids);
+ sfree (domids);
}
return 0;
if (domains) {
for (i = 0; i < nr_domains; ++i)
virDomainFree (domains[i]);
- free (domains);
+ sfree (domains);
}
domains = NULL;
nr_domains = 0;
if (block_devices) {
for (i = 0; i < nr_block_devices; ++i)
- free (block_devices[i].path);
- free (block_devices);
+ sfree (block_devices[i].path);
+ sfree (block_devices);
}
block_devices = NULL;
nr_block_devices = 0;
new_ptr = malloc (new_size);
if (new_ptr == NULL) {
- free (path_copy);
+ sfree (path_copy);
return -1;
}
block_devices = new_ptr;
int i;
if (interface_devices) {
- for (i = 0; i < nr_interface_devices; ++i)
- free (interface_devices[i].path);
- free (interface_devices);
+ for (i = 0; i < nr_interface_devices; ++i) {
+ sfree (interface_devices[i].path);
+ sfree (interface_devices[i].address);
+ }
+ sfree (interface_devices);
}
interface_devices = NULL;
nr_interface_devices = 0;
}
static int
-add_interface_device (virDomainPtr dom, const char *path)
+add_interface_device (virDomainPtr dom, const char *path, const char *address)
{
struct interface_device *new_ptr;
int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
- char *path_copy;
+ char *path_copy, *address_copy;
path_copy = strdup (path);
if (!path_copy) return -1;
+ address_copy = strdup (address);
+ if (!address_copy) return -1;
+
if (interface_devices)
new_ptr = realloc (interface_devices, new_size);
else
new_ptr = malloc (new_size);
if (new_ptr == NULL) {
- free (path_copy);
+ sfree (path_copy);
+ sfree (address_copy);
return -1;
}
interface_devices = new_ptr;
interface_devices[nr_interface_devices].dom = dom;
interface_devices[nr_interface_devices].path = path_copy;
+ interface_devices[nr_interface_devices].address = address_copy;
return nr_interface_devices++;
}
@@ -645,121 +790,10 @@ ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
}
ssnprintf (name, n, "%s:%s", domname, devpath);
r = ignorelist_match (il, name);
- free (name);
+ sfree (name);
return r;
}
-static void
-init_value_list (value_list_t *vl, time_t t, virDomainPtr dom)
-{
- int i, n;
- const char *name;
- char uuid[VIR_UUID_STRING_BUFLEN];
- char *host_ptr;
- size_t host_len;
-
- vl->time = t;
- vl->interval = interval_g;
-
- sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
-
- vl->host[0] = '\0';
- host_ptr = vl->host;
- host_len = sizeof (vl->host);
-
- /* Construct the hostname field according to HostnameFormat. */
- for (i = 0; i < HF_MAX_FIELDS; ++i) {
- if (hostname_format[i] == hf_none)
- continue;
-
- n = DATA_MAX_NAME_LEN - strlen (vl->host) - 2;
-
- if (i > 0 && n >= 1) {
- strncat (vl->host, ":", 1);
- n--;
- }
-
- switch (hostname_format[i]) {
- case hf_none: break;
- case hf_hostname:
- strncat (vl->host, hostname_g, n);
- break;
- case hf_name:
- name = virDomainGetName (dom);
- if (name)
- strncat (vl->host, name, n);
- break;
- case hf_uuid:
- if (virDomainGetUUIDString (dom, uuid) == 0)
- strncat (vl->host, uuid, n);
- break;
- }
- }
-
- vl->host[sizeof (vl->host) - 1] = '\0';
-} /* void init_value_list */
-
-static void
-cpu_submit (unsigned long long cpu_time,
- time_t t,
- virDomainPtr dom, const char *type)
-{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
-
- init_value_list (&vl, t, dom);
-
- values[0].counter = cpu_time;
-
- vl.values = values;
- vl.values_len = 1;
-
- sstrncpy (vl.type, type, sizeof (vl.type));
-
- plugin_dispatch_values (&vl);
-}
-
-static void
-vcpu_submit (counter_t cpu_time,
- time_t t,
- virDomainPtr dom, int vcpu_nr, const char *type)
-{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
-
- init_value_list (&vl, t, dom);
-
- values[0].counter = cpu_time;
- vl.values = values;
- vl.values_len = 1;
-
- sstrncpy (vl.type, type, sizeof (vl.type));
- ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
-
- plugin_dispatch_values (&vl);
-}
-
-static void
-submit_counter2 (const char *type, counter_t v0, counter_t v1,
- time_t t,
- virDomainPtr dom, const char *devname)
-{
- value_t values[2];
- value_list_t vl = VALUE_LIST_INIT;
-
- init_value_list (&vl, t, dom);
-
- values[0].counter = v0;
- values[1].counter = v1;
- vl.values = values;
- vl.values_len = 2;
-
- sstrncpy (vl.type, type, sizeof (vl.type));
- sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
-
- plugin_dispatch_values (&vl);
-} /* void submit_counter2 */
-
static int
lv_shutdown (void)
{
diff --git a/src/logfile.c b/src/logfile.c
index 6d0f6e07826f2eb5391a64bc93db72e642948362..60fb5d9202ecfc5e5d9ddc2252820732e5586433 100644 (file)
--- a/src/logfile.c
+++ b/src/logfile.c
return 0;
} /* int logfile_config (const char *, const char *) */
-static void logfile_print (const char *msg, int severity, time_t timestamp_time)
+static void logfile_print (const char *msg, int severity,
+ cdtime_t timestamp_time)
{
FILE *fh;
int do_close = 0;
@@ -126,7 +127,8 @@ static void logfile_print (const char *msg, int severity, time_t timestamp_time)
if (print_timestamp)
{
- localtime_r (×tamp_time, ×tamp_tm);
+ time_t tt = CDTIME_T_TO_TIME_T (timestamp_time);
+ localtime_r (&tt, ×tamp_tm);
strftime (timestamp_str, sizeof (timestamp_str), "%Y-%m-%d %H:%M:%S",
×tamp_tm);
if (severity > log_level)
return;
- logfile_print (msg, severity, time (NULL));
+ logfile_print (msg, severity, cdtime ());
} /* void logfile_log (int, const char *) */
static int logfile_notification (const notification_t *n,
buf[sizeof (buf) - 1] = '\0';
logfile_print (buf, LOG_INFO,
- (n->time > 0) ? n->time : time (NULL));
+ (n->time != 0) ? n->time : cdtime ());
return (0);
} /* int logfile_notification */
diff --git a/src/lpar.c b/src/lpar.c
--- /dev/null
+++ b/src/lpar.c
@@ -0,0 +1,273 @@
+/**
+ * collectd - src/lpar.c
+ * Copyright (C) 2010 Aurélien Reynaud
+ *
+ * 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:
+ * Aurélien Reynaud <collectd at wattapower.net>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <sys/protosw.h>
+#include <libperfstat.h>
+#include <sys/utsname.h>
+
+/* XINTFRAC was defined in libperfstat.h somewhere between AIX 5.3 and 6.1 */
+#ifndef XINTFRAC
+# include <sys/systemcfg.h>
+# define XINTFRAC ((double)(_system_configuration.Xint) / \
+ (double)(_system_configuration.Xfrac))
+#endif
+
+#define CLOCKTICKS_TO_TICKS(cticks) ((cticks) / XINTFRAC)
+
+static const char *config_keys[] =
+{
+ "CpuPoolStats",
+ "ReportBySerial"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static _Bool pool_stats = 0;
+static _Bool report_by_serial = 0;
+#if PERFSTAT_SUPPORTS_DONATION
+static _Bool donate_flag = 0;
+#endif
+static char serial[SYS_NMLN];
+
+static perfstat_partition_total_t lparstats_old;
+
+static int lpar_config (const char *key, const char *value)
+{
+ if (strcasecmp ("CpuPoolStats", key) == 0)
+ {
+ if (IS_TRUE (value))
+ pool_stats = 1;
+ else
+ pool_stats = 0;
+ }
+ else if (strcasecmp ("ReportBySerial", key) == 0)
+ {
+ if (IS_TRUE (value))
+ report_by_serial = 1;
+ else
+ report_by_serial = 0;
+ }
+ else
+ {
+ return (-1);
+ }
+
+ return (0);
+} /* int lpar_config */
+
+static int lpar_init (void)
+{
+ int status;
+
+ /* Retrieve the initial metrics. Returns the number of structures filled. */
+ status = perfstat_partition_total (/* name = */ NULL, /* (must be NULL) */
+ &lparstats_old, sizeof (perfstat_partition_total_t),
+ /* number = */ 1 /* (must be 1) */);
+ if (status != 1)
+ {
+ char errbuf[1024];
+ ERROR ("lpar plugin: perfstat_partition_total failed: %s (%i)",
+ sstrerror (errno, errbuf, sizeof (errbuf)),
+ status);
+ return (-1);
+ }
+
+#if PERFSTAT_SUPPORTS_DONATION
+ if (!lparstats_old.type.b.shared_enabled
+ && lparstats_old.type.b.donate_enabled)
+ {
+ donate_flag = 1;
+ }
+#endif
+
+ if (pool_stats && !lparstats_old.type.b.pool_util_authority)
+ {
+ WARNING ("lpar plugin: This partition does not have pool authority. "
+ "Disabling CPU pool statistics collection.");
+ pool_stats = 0;
+ }
+
+ return (0);
+} /* int lpar_init */
+
+static void lpar_submit (const char *type_instance, double value)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = (gauge_t)value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ if (report_by_serial)
+ {
+ sstrncpy (vl.host, serial, sizeof (vl.host));
+ sstrncpy (vl.plugin_instance, hostname_g, sizeof (vl.plugin));
+ }
+ else
+ {
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ }
+ sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
+ sstrncpy (vl.type, "vcpu", sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* void lpar_submit */
+
+static int lpar_read (void)
+{
+ perfstat_partition_total_t lparstats;
+ int status;
+ struct utsname name;
+ u_longlong_t ticks;
+ u_longlong_t user_ticks, syst_ticks, wait_ticks, idle_ticks;
+ u_longlong_t consumed_ticks;
+ double entitled_proc_capacity;
+
+ /* An LPAR has the same serial number as the physical system it is currently
+ running on. It is a convenient way of tracking LPARs as they are moved
+ from chassis to chassis through Live Partition Mobility (LPM). */
+ if (uname (&name) != 0)
+ {
+ ERROR ("lpar plugin: uname failed.");
+ return (-1);
+ }
+ sstrncpy (serial, name.machine, sizeof (serial));
+
+ /* Retrieve the current metrics. Returns the number of structures filled. */
+ status = perfstat_partition_total (/* name = */ NULL, /* (must be NULL) */
+ &lparstats, sizeof (perfstat_partition_total_t),
+ /* number = */ 1 /* (must be 1) */);
+ if (status != 1)
+ {
+ char errbuf[1024];
+ ERROR ("lpar plugin: perfstat_partition_total failed: %s (%i)",
+ sstrerror (errno, errbuf, sizeof (errbuf)),
+ status);
+ return (-1);
+ }
+
+ /* Number of ticks since we last run. */
+ ticks = lparstats.timebase_last - lparstats_old.timebase_last;
+ if (ticks == 0)
+ {
+ /* The stats have not been updated. Return now to avoid
+ * dividing by zero */
+ return (0);
+ }
+
+ /*
+ * On a shared partition, we're "entitled" to a certain amount of
+ * processing power, for example 250/100 of a physical CPU. Processing
+ * capacity not used by the partition may be assigned to a different
+ * partition by the hypervisor, so "idle" is hopefully a very small
+ * number.
+ *
+ * A dedicated partition may donate its CPUs to another partition and
+ * may steal ticks from somewhere else (another partition or maybe the
+ * shared pool, I don't know --octo).
+ */
+
+ /* entitled_proc_capacity is in 1/100th of a CPU */
+ entitled_proc_capacity = 0.01 * ((double) lparstats.entitled_proc_capacity);
+ lpar_submit ("entitled", entitled_proc_capacity);
+
+ /* The number of ticks actually spent in the various states */
+ user_ticks = lparstats.puser - lparstats_old.puser;
+ syst_ticks = lparstats.psys - lparstats_old.psys;
+ wait_ticks = lparstats.pwait - lparstats_old.pwait;
+ idle_ticks = lparstats.pidle - lparstats_old.pidle;
+ consumed_ticks = user_ticks + syst_ticks + wait_ticks + idle_ticks;
+
+ lpar_submit ("user", (double) user_ticks / (double) ticks);
+ lpar_submit ("system", (double) syst_ticks / (double) ticks);
+ lpar_submit ("wait", (double) wait_ticks / (double) ticks);
+ lpar_submit ("idle", (double) idle_ticks / (double) ticks);
+
+#if PERFSTAT_SUPPORTS_DONATION
+ if (donate_flag)
+ {
+ /* donated => ticks given to another partition
+ * stolen => ticks received from another partition */
+ u_longlong_t idle_donated_ticks, busy_donated_ticks;
+ u_longlong_t idle_stolen_ticks, busy_stolen_ticks;
+
+ /* FYI: PURR == Processor Utilization of Resources Register
+ * SPURR == Scaled PURR */
+ idle_donated_ticks = lparstats.idle_donated_purr - lparstats_old.idle_donated_purr;
+ busy_donated_ticks = lparstats.busy_donated_purr - lparstats_old.busy_donated_purr;
+ idle_stolen_ticks = lparstats.idle_stolen_purr - lparstats_old.idle_stolen_purr;
+ busy_stolen_ticks = lparstats.busy_stolen_purr - lparstats_old.busy_stolen_purr;
+
+ lpar_submit ("idle_donated", (double) idle_donated_ticks / (double) ticks);
+ lpar_submit ("busy_donated", (double) busy_donated_ticks / (double) ticks);
+ lpar_submit ("idle_stolen", (double) idle_stolen_ticks / (double) ticks);
+ lpar_submit ("busy_stolen", (double) busy_stolen_ticks / (double) ticks);
+
+ /* Donated ticks will be accounted for as stolen ticks in other LPARs */
+ consumed_ticks += idle_stolen_ticks + busy_stolen_ticks;
+ }
+#endif
+
+ lpar_submit ("consumed", (double) consumed_ticks / (double) ticks);
+
+ if (pool_stats)
+ {
+ char typinst[DATA_MAX_NAME_LEN];
+ u_longlong_t pool_idle_cticks;
+ double pool_idle_cpus;
+ double pool_busy_cpus;
+
+ /* We're calculating "busy" from "idle" and the total number of
+ * CPUs, because the "busy" member didn't exist in early versions
+ * of libperfstat. It was added somewhere between AIX 5.3 ML5 and ML9. */
+ pool_idle_cticks = lparstats.pool_idle_time - lparstats_old.pool_idle_time;
+ pool_idle_cpus = CLOCKTICKS_TO_TICKS ((double) pool_idle_cticks) / (double) ticks;
+ pool_busy_cpus = ((double) lparstats.phys_cpus_pool) - pool_idle_cpus;
+ if (pool_busy_cpus < 0.0)
+ pool_busy_cpus = 0.0;
+
+ ssnprintf (typinst, sizeof (typinst), "pool-%X-busy", lparstats.pool_id);
+ lpar_submit (typinst, pool_busy_cpus);
+
+ ssnprintf (typinst, sizeof (typinst), "pool-%X-idle", lparstats.pool_id);
+ lpar_submit (typinst, pool_idle_cpus);
+ }
+
+ memcpy (&lparstats_old, &lparstats, sizeof (lparstats_old));
+
+ return (0);
+} /* int lpar_read */
+
+void module_register (void)
+{
+ plugin_register_config ("lpar", lpar_config,
+ config_keys, config_keys_num);
+ plugin_register_init ("lpar", lpar_init);
+ plugin_register_read ("lpar", lpar_read);
+} /* void module_register */
+
+/* vim: set sw=8 noet : */
+
diff --git a/src/match_timediff.c b/src/match_timediff.c
index 4ac944afe3dfb58f45b9df2ecea2e1300d5cadec..2e2741550c46e63882fd162d31caf8264cbfce21 100644 (file)
--- a/src/match_timediff.c
+++ b/src/match_timediff.c
typedef struct mt_match_s mt_match_t;
struct mt_match_s
{
- time_t future;
- time_t past;
+ cdtime_t future;
+ cdtime_t past;
};
/*
* internal helper functions
*/
-static int mt_config_add_time_t (time_t *ret_value, /* {{{ */
- oconfig_item_t *ci)
-{
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
- {
- ERROR ("timediff match: `%s' needs exactly one numeric argument.",
- ci->key);
- return (-1);
- }
-
- *ret_value = (time_t) ci->values[0].value.number;
-
- return (0);
-} /* }}} int mt_config_add_time_t */
-
static int mt_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
{
mt_match_t *m;
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Future", child->key) == 0)
- status = mt_config_add_time_t (&m->future, child);
+ status = cf_util_get_cdtime (child, &m->future);
else if (strcasecmp ("Past", child->key) == 0)
- status = mt_config_add_time_t (&m->past, child);
+ status = cf_util_get_cdtime (child, &m->past);
else
{
ERROR ("timediff match: The `%s' configuration option is not "
notification_meta_t __attribute__((unused)) **meta, void **user_data)
{
mt_match_t *m;
- time_t now;
+ cdtime_t now;
if ((user_data == NULL) || (*user_data == NULL))
return (-1);
m = *user_data;
- now = time (NULL);
+ now = cdtime ();
if (m->future != 0)
{
diff --git a/src/memcachec.c b/src/memcachec.c
index d066501cdcba73afb56363dae167b9dd78353e10..8f51e22f01dd3c2d728d0cbc0a8e2cc61fba99e1 100644 (file)
--- a/src/memcachec.c
+++ b/src/memcachec.c
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcachec", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
diff --git a/src/memcached.c b/src/memcached.c
index 348591fd160b79c0f64308732698e79ec9ab4789..8b4a8fc1b9a2495fb966442ff96ffad386787f5a 100644 (file)
--- a/src/memcached.c
+++ b/src/memcached.c
p.events = POLLIN | POLLERR | POLLHUP;
p.revents = 0;
- status = poll (&p, /* nfds = */ 1, /* timeout = */ 1000 * interval_g);
+ status = poll (&p, /* nfds = */ 1,
+ /* timeout = */ CDTIME_T_TO_MS (interval_g));
if (status <= 0)
{
if (status == 0)
{
- ERROR ("memcached: poll(2) timed out after %i seconds.", interval_g);
+ ERROR ("memcached: poll(2) timed out after %.3f seconds.",
+ CDTIME_T_TO_DOUBLE (interval_g));
}
else
{
vl.values = values;
vl.values_len = 2;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
sstrncpy (vl.type, type, sizeof (vl.type));
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
sstrncpy (vl.type, type, sizeof (vl.type));
vl.values = values;
vl.values_len = 2;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
sstrncpy (vl.type, type, sizeof (vl.type));
diff --git a/src/modbus.c b/src/modbus.c
index adab0d0fe8e0756641a509b0c39b6373c44735b4..3824097c5a43b57e34c170eb4782ff756d8524a7 100644 (file)
--- a/src/modbus.c
+++ b/src/modbus.c
char node[NI_MAXHOST];
/* char service[NI_MAXSERV]; */
int port;
- int interval;
+ cdtime_t interval;
mb_slave_t *slaves;
size_t slaves_num;
status = -1;
}
else if (strcasecmp ("Interval", child->key) == 0)
- status = cf_util_get_int (child, &host->interval);
+ status = cf_util_get_cdtime (child, &host->interval);
else if (strcasecmp ("Slave", child->key) == 0)
/* Don't set status: Gracefully continue if a slave fails. */
mb_config_add_slave (host, child);
{
user_data_t ud;
char name[1024];
- struct timespec interval;
+ struct timespec interval = { 0, 0 };
ud.data = host;
ud.free_func = host_free;
ssnprintf (name, sizeof (name), "modbus-%s", host->host);
- interval.tv_nsec = 0;
- if (host->interval > 0)
- interval.tv_sec = host->interval;
- else
- interval.tv_sec = 0;
+ CDTIME_T_TO_TIMESPEC (host->interval, &interval);
plugin_register_complex_read (/* group = */ NULL, name,
- mb_read, (interval.tv_sec > 0) ? &interval : NULL, &ud);
+ /* callback = */ mb_read,
+ /* interval = */ (host->interval > 0) ? &interval : NULL,
+ &ud);
}
else
{
diff --git a/src/mysql.c b/src/mysql.c
index c7b796b18d79d5c92dcc34cacba287c4a0db26ea..1ca3b484ce6d2ebadc490196ed64260140c7d18c 100644 (file)
--- a/src/mysql.c
+++ b/src/mysql.c
struct mysql_database_s /* {{{ */
{
- /* instance == NULL => legacy mode */
char *instance;
char *host;
char *user;
char *socket;
int port;
- int master_stats;
- int slave_stats;
+ _Bool master_stats;
+ _Bool slave_stats;
- int slave_notif;
- int slave_io_running;
- int slave_sql_running;
+ _Bool slave_notif;
+ _Bool slave_io_running;
+ _Bool slave_sql_running;
MYSQL *con;
int state;
* </Database>
* </Plugin>
*/
-
-static int mysql_config_set_string (char **ret_string, /* {{{ */
- oconfig_item_t *ci)
-{
- char *string;
-
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- WARNING ("mysql plugin: The `%s' config option "
- "needs exactly one string argument.", ci->key);
- return (-1);
- }
-
- string = strdup (ci->values[0].value.string);
- if (string == NULL)
- {
- ERROR ("mysql plugin: strdup failed.");
- return (-1);
- }
-
- if (*ret_string != NULL)
- free (*ret_string);
- *ret_string = string;
-
- return (0);
-} /* }}} int mysql_config_set_string */
-
-static int mysql_config_set_int (int *ret_int, /* {{{ */
- oconfig_item_t *ci)
-{
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
- {
- WARNING ("mysql plugin: The `%s' config option "
- "needs exactly one string argument.", ci->key);
- return (-1);
- }
-
- *ret_int = ci->values[0].value.number;
-
- return (0);
-} /* }}} int mysql_config_set_int */
-
-static int mysql_config_set_boolean (int *ret_boolean, /* {{{ */
- oconfig_item_t *ci)
-{
- int status = 0;
-
- if (ci->values_num != 1)
- status = -1;
-
- if (status == 0)
- {
- if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
- *ret_boolean = ci->values[0].value.boolean;
- else if (ci->values[0].type == OCONFIG_TYPE_STRING)
- {
- if (IS_TRUE (ci->values[0].value.string))
- *ret_boolean = 1;
- else if (IS_FALSE (ci->values[0].value.string))
- *ret_boolean = 0;
- else
- status = -1;
- }
- else
- status = -1;
- }
-
- if (status != 0)
- {
- WARNING ("mysql plugin: The `%s' config option "
- "needs exactly one boolean argument.", ci->key);
- return (-1);
- }
- return (0);
-} /* }}} mysql_config_set_boolean */
-
-static int mysql_config (oconfig_item_t *ci) /* {{{ */
+static int mysql_config_database (oconfig_item_t *ci) /* {{{ */
{
mysql_database_t *db;
- int plugin_block;
int status = 0;
int i;
db->slave_io_running = 1;
db->slave_sql_running = 1;
- plugin_block = 1;
- if (strcasecmp ("Plugin", ci->key) == 0)
- {
- db->instance = NULL;
- }
- else if (strcasecmp ("Database", ci->key) == 0)
- {
- plugin_block = 0;
- status = mysql_config_set_string (&db->instance, ci);
- if (status != 0)
- {
- sfree (db);
- return (status);
- }
- assert (db->instance != NULL);
- }
- else
+ status = cf_util_get_string (ci, &db->instance);
+ if (status != 0)
{
- ERROR ("mysql plugin: mysql_config: "
- "Invalid key: %s", ci->key);
- return (-1);
+ sfree (db);
+ return (status);
}
+ assert (db->instance != NULL);
/* Fill the `mysql_database_t' structure.. */
for (i = 0; i < ci->children_num; i++)
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Host", child->key) == 0)
- status = mysql_config_set_string (&db->host, child);
+ status = cf_util_get_string (child, &db->host);
else if (strcasecmp ("User", child->key) == 0)
- status = mysql_config_set_string (&db->user, child);
+ status = cf_util_get_string (child, &db->user);
else if (strcasecmp ("Password", child->key) == 0)
- status = mysql_config_set_string (&db->pass, child);
+ status = cf_util_get_string (child, &db->pass);
else if (strcasecmp ("Port", child->key) == 0)
- status = mysql_config_set_int (&db->port, child);
- else if (strcasecmp ("Socket", child->key) == 0)
- status = mysql_config_set_string (&db->socket, child);
- /* Check if we're currently handling the `Plugin' block. If so,
- * handle `Database' _blocks_, too. */
- else if ((plugin_block != 0)
- && (strcasecmp ("Database", child->key) == 0)
- && (child->children != NULL))
{
- /* If `plugin_block > 1', there has been at least one
- * `Database' block */
- plugin_block++;
- status = mysql_config (child);
+ status = cf_util_get_port_number (child);
+ if (status > 0)
+ {
+ db->port = status;
+ status = 0;
+ }
}
- /* Now handle ordinary `Database' options (without children) */
- else if ((strcasecmp ("Database", child->key) == 0)
- && (child->children == NULL))
- status = mysql_config_set_string (&db->database, child);
+ else if (strcasecmp ("Socket", child->key) == 0)
+ status = cf_util_get_string (child, &db->socket);
+ else if (strcasecmp ("Database", child->key) == 0)
+ status = cf_util_get_string (child, &db->database);
else if (strcasecmp ("MasterStats", child->key) == 0)
- status = mysql_config_set_boolean (&db->master_stats, child);
+ status = cf_util_get_boolean (child, &db->master_stats);
else if (strcasecmp ("SlaveStats", child->key) == 0)
- status = mysql_config_set_boolean (&db->slave_stats, child);
+ status = cf_util_get_boolean (child, &db->slave_stats);
else if (strcasecmp ("SlaveNotifications", child->key) == 0)
- status = mysql_config_set_boolean (&db->slave_notif, child);
+ status = cf_util_get_boolean (child, &db->slave_notif);
else
{
WARNING ("mysql plugin: Option `%s' not allowed here.", child->key);
break;
}
- /* Check if there were any `Database' blocks. */
- if (plugin_block > 1)
- {
- /* There were connection blocks. Don't use any legacy stuff. */
- if ((db->host != NULL)
- || (db->user != NULL)
- || (db->pass != NULL)
- || (db->database != NULL)
- || (db->socket != NULL)
- || (db->port != 0))
- {
- WARNING ("mysql plugin: At least one <Database> "
- "block has been found. The legacy "
- "configuration will be ignored.");
- }
- mysql_database_free (db);
- return (0);
- }
- else if (plugin_block != 0)
- {
- WARNING ("mysql plugin: You're using the legacy "
- "configuration options. Please consider "
- "updating your configuration!");
- }
-
- /* Check that all necessary options have been given. */
- while (status == 0)
- {
- /* Zero is allowed and automatically handled by
- * `mysql_real_connect'. */
- if ((db->port < 0) || (db->port > 65535))
- {
- ERROR ("mysql plugin: Database %s: Port number out "
- "of range: %i",
- (db->instance != NULL)
- ? db->instance
- : "<legacy>",
- db->port);
- status = -1;
- }
- break;
- } /* while (status == 0) */
-
/* If all went well, register this database for reading */
if (status == 0)
{
return (-1);
}
+ return (0);
+} /* }}} int mysql_config_database */
+
+static int mysql_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ if (ci == NULL)
+ return (EINVAL);
+
+ /* Fill the `mysql_database_t' structure.. */
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Database", child->key) == 0)
+ mysql_config_database (child);
+ else
+ WARNING ("mysql plugin: Option \"%s\" not allowed here.",
+ child->key);
+ }
+
return (0);
} /* }}} int mysql_config */
int err;
if ((err = mysql_ping (db->con)) != 0)
{
- WARNING ("mysql_ping failed for %s: %s",
- (db->instance != NULL)
- ? db->instance
- : "<legacy>",
+ /* Assured by "mysql_config_database" */
+ assert (db->instance != NULL);
+ WARNING ("mysql_ping failed for instance \"%s\": %s",
+ db->instance,
mysql_error (db->con));
db->state = 0;
}
static void set_host (mysql_database_t *db, char *buf, size_t buflen)
{
- /* XXX legacy mode - use hostname_g */
- if (db->instance == NULL)
+ if ((db->host == NULL)
+ || (strcmp ("", db->host) == 0)
+ || (strcmp ("localhost", db->host) == 0))
sstrncpy (buf, hostname_g, buflen);
else
- {
- if ((db->host == NULL)
- || (strcmp ("", db->host) == 0)
- || (strcmp ("localhost", db->host) == 0))
- sstrncpy (buf, hostname_g, buflen);
- else
- sstrncpy (buf, db->host, buflen);
- }
-}
-
-static void set_plugin_instance (mysql_database_t *db,
- char *buf, size_t buflen)
-{
- /* XXX legacy mode - no plugin_instance */
- if (db->instance == NULL)
- sstrncpy (buf, "", buflen);
- else
- sstrncpy (buf, db->instance, buflen);
-}
+ sstrncpy (buf, db->host, buflen);
+} /* void set_host */
static void submit (const char *type, const char *type_instance,
value_t *values, size_t values_len, mysql_database_t *db)
set_host (db, vl.host, sizeof (vl.host));
sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
- set_plugin_instance (db, vl.plugin_instance, sizeof (vl.plugin_instance));
+
+ /* Assured by "mysql_config_database" */
+ assert (db->instance != NULL);
+ sstrncpy (vl.plugin_instance, db->instance, sizeof (vl.plugin_instance));
sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
} /* void gauge_submit */
-static void qcache_submit (counter_t hits, counter_t inserts,
- counter_t not_cached, counter_t lowmem_prunes,
- gauge_t queries_in_cache, mysql_database_t *db)
+static void derive_submit (const char *type, const char *type_instance,
+ derive_t value, mysql_database_t *db)
{
- value_t values[5];
-
- values[0].counter = hits;
- values[1].counter = inserts;
- values[2].counter = not_cached;
- values[3].counter = lowmem_prunes;
- values[4].gauge = queries_in_cache;
-
- submit ("mysql_qcache", NULL, values, STATIC_ARRAY_SIZE (values), db);
-} /* void qcache_submit */
-
-static void threads_submit (gauge_t running, gauge_t connected, gauge_t cached,
- counter_t created, mysql_database_t *db)
-{
- value_t values[4];
-
- values[0].gauge = running;
- values[1].gauge = connected;
- values[2].gauge = cached;
- values[3].counter = created;
+ value_t values[1];
- submit ("mysql_threads", NULL, values, STATIC_ARRAY_SIZE (values), db);
-} /* void threads_submit */
+ values[0].derive = value;
+ submit (type, type_instance, values, STATIC_ARRAY_SIZE (values), db);
+} /* void derive_submit */
static void traffic_submit (counter_t rx, counter_t tx, mysql_database_t *db)
{
if (db->slave_notif)
{
- notification_t n = { 0, time (NULL), "", "",
+ notification_t n = { 0, cdtime (), "", "",
"mysql", "", "time_offset", "", NULL };
char *io, *sql;
sql = row[SLAVE_SQL_RUNNING_IDX];
set_host (db, n.host, sizeof (n.host));
- set_plugin_instance (db,
- n.plugin_instance, sizeof (n.plugin_instance));
+
+ /* Assured by "mysql_config_database" */
+ assert (db->instance != NULL);
+ sstrncpy (n.plugin_instance, db->instance, sizeof (n.plugin_instance));
if (((io == NULL) || (strcasecmp (io, "yes") != 0))
&& (db->slave_io_running))
char *query;
int field_num;
- unsigned long long qcache_hits = 0ULL;
- unsigned long long qcache_inserts = 0ULL;
- unsigned long long qcache_not_cached = 0ULL;
- unsigned long long qcache_lowmem_prunes = 0ULL;
- int qcache_queries_in_cache = -1;
+ derive_t qcache_hits = 0;
+ derive_t qcache_inserts = 0;
+ derive_t qcache_not_cached = 0;
+ derive_t qcache_lowmem_prunes = 0;
+ gauge_t qcache_queries_in_cache = NAN;
- int threads_running = -1;
- int threads_connected = -1;
- int threads_cached = -1;
- unsigned long long threads_created = 0ULL;
+ gauge_t threads_running = NAN;
+ gauge_t threads_connected = NAN;
+ gauge_t threads_cached = NAN;
+ derive_t threads_created = 0;
unsigned long long traffic_incoming = 0ULL;
unsigned long long traffic_outgoing = 0ULL;
strlen ("Qcache_")) == 0)
{
if (strcmp (key, "Qcache_hits") == 0)
- qcache_hits = val;
+ qcache_hits = (derive_t) val;
else if (strcmp (key, "Qcache_inserts") == 0)
- qcache_inserts = val;
+ qcache_inserts = (derive_t) val;
else if (strcmp (key, "Qcache_not_cached") == 0)
- qcache_not_cached = val;
+ qcache_not_cached = (derive_t) val;
else if (strcmp (key, "Qcache_lowmem_prunes") == 0)
- qcache_lowmem_prunes = val;
+ qcache_lowmem_prunes = (derive_t) val;
else if (strcmp (key, "Qcache_queries_in_cache") == 0)
- qcache_queries_in_cache = (int) val;
+ qcache_queries_in_cache = (gauge_t) val;
}
else if (strncmp (key, "Bytes_",
strlen ("Bytes_")) == 0)
strlen ("Threads_")) == 0)
{
if (strcmp (key, "Threads_running") == 0)
- threads_running = (int) val;
+ threads_running = (gauge_t) val;
else if (strcmp (key, "Threads_connected") == 0)
- threads_connected = (int) val;
+ threads_connected = (gauge_t) val;
else if (strcmp (key, "Threads_cached") == 0)
- threads_cached = (int) val;
+ threads_cached = (gauge_t) val;
else if (strcmp (key, "Threads_created") == 0)
- threads_created = val;
+ threads_created = (derive_t) val;
}
else if (strncmp (key, "Table_locks_",
strlen ("Table_locks_")) == 0)
}
mysql_free_result (res); res = NULL;
- if ((qcache_hits != 0ULL)
- || (qcache_inserts != 0ULL)
- || (qcache_not_cached != 0ULL)
- || (qcache_lowmem_prunes != 0ULL))
- qcache_submit (qcache_hits, qcache_inserts, qcache_not_cached,
- qcache_lowmem_prunes, qcache_queries_in_cache, db);
+ if ((qcache_hits != 0)
+ || (qcache_inserts != 0)
+ || (qcache_not_cached != 0)
+ || (qcache_lowmem_prunes != 0))
+ {
+ derive_submit ("cache_result", "qcache-hits",
+ qcache_hits, db);
+ derive_submit ("cache_result", "qcache-inserts",
+ qcache_inserts, db);
+ derive_submit ("cache_result", "qcache-not_cached",
+ qcache_not_cached, db);
+ derive_submit ("cache_result", "qcache-prunes",
+ qcache_lowmem_prunes, db);
+
+ gauge_submit ("cache_size", "qcache",
+ qcache_queries_in_cache, db);
+ }
- if (threads_created != 0ULL)
- threads_submit (threads_running, threads_connected,
- threads_cached, threads_created, db);
+ if (threads_created != 0)
+ {
+ gauge_submit ("threads", "running",
+ threads_running, db);
+ gauge_submit ("threads", "connected",
+ threads_connected, db);
+ gauge_submit ("threads", "cached",
+ threads_cached, db);
+
+ derive_submit ("total_threads", "created",
+ threads_created, db);
+ }
traffic_submit (traffic_incoming, traffic_outgoing, db);
diff --git a/src/netapp.c b/src/netapp.c
index a4e03c6e67c3c7988f7e2a3295edf53b9cb0c0cb..5d100a69ca5f0eb23d5149a4f426becb6dfbd6b1 100644 (file)
--- a/src/netapp.c
+++ b/src/netapp.c
struct cna_interval_s
{
- time_t interval;
- time_t last_read;
+ cdtime_t interval;
+ cdtime_t last_read;
};
typedef struct cna_interval_s cna_interval_t;
cna_interval_t interval;
na_elem_t *query;
- time_t timestamp;
+ cdtime_t timestamp;
uint64_t name_cache_hit;
uint64_t name_cache_miss;
uint64_t find_dir_hit;
typedef struct disk_s {
char *name;
uint32_t flags;
- time_t timestamp;
+ cdtime_t timestamp;
uint64_t disk_busy;
uint64_t base_for_disk_busy;
double disk_busy_percent;
struct data_volume_perf_s {
char *name;
uint32_t flags;
- time_t timestamp;
+ cdtime_t timestamp;
uint64_t read_bytes;
uint64_t write_bytes;
int port;
char *username;
char *password;
- int interval;
+ cdtime_t interval;
na_server_t *srv;
cfg_wafl_t *cfg_wafl;
const char *plugin_inst,
const char *type, const char *type_inst,
value_t *values, int values_len,
- time_t timestamp, int interval)
+ cdtime_t timestamp, cdtime_t interval)
{
value_list_t vl = VALUE_LIST_INIT;
static int submit_two_counters (const char *host, const char *plugin_inst, /* {{{ */
const char *type, const char *type_inst, counter_t val0, counter_t val1,
- time_t timestamp, int interval)
+ cdtime_t timestamp, cdtime_t interval)
{
value_t values[2];
@@ -607,7 +607,8 @@ static int submit_two_counters (const char *host, const char *plugin_inst, /* {{
} /* }}} int submit_two_counters */
static int submit_counter (const char *host, const char *plugin_inst, /* {{{ */
- const char *type, const char *type_inst, counter_t counter, time_t timestamp, int interval)
+ const char *type, const char *type_inst, counter_t counter,
+ cdtime_t timestamp, cdtime_t interval)
{
value_t v;
static int submit_two_gauge (const char *host, const char *plugin_inst, /* {{{ */
const char *type, const char *type_inst, gauge_t val0, gauge_t val1,
- time_t timestamp, int interval)
+ cdtime_t timestamp, cdtime_t interval)
{
value_t values[2];
@@ -631,7 +632,8 @@ static int submit_two_gauge (const char *host, const char *plugin_inst, /* {{{ *
} /* }}} int submit_two_gauge */
static int submit_double (const char *host, const char *plugin_inst, /* {{{ */
- const char *type, const char *type_inst, double d, time_t timestamp, int interval)
+ const char *type, const char *type_inst, double d,
+ cdtime_t timestamp, cdtime_t interval)
{
value_t v;
uint64_t new_misses,
uint64_t old_hits,
uint64_t old_misses,
- time_t timestamp,
- int interval)
+ cdtime_t timestamp,
+ cdtime_t interval)
{
value_t v;
return (0);
} /* }}} int submit_volume_perf_data */
+static cdtime_t cna_child_get_cdtime (na_elem_t *data) /* {{{ */
+{
+ time_t t;
+
+ t = (time_t) na_child_get_uint64 (data, "timestamp", /* default = */ 0);
+
+ return (TIME_T_TO_CDTIME_T (t));
+} /* }}} cdtime_t cna_child_get_cdtime */
+
+
/*
* Query functions
*
memset (&perf_data, 0, sizeof (perf_data));
- perf_data.timestamp = (time_t) na_child_get_uint64 (data, "timestamp", 0);
+ perf_data.timestamp = cna_child_get_cdtime (data);
instances = na_elem_child(na_elem_child (data, "instances"), "instance-data");
if (instances == NULL)
{
na_elem_t *data;
int status;
- time_t now;
+ cdtime_t now;
if (host == NULL)
return (EINVAL);
if (host->cfg_wafl == NULL)
return (0);
- now = time (NULL);
+ now = cdtime ();
if ((host->cfg_wafl->interval.interval + host->cfg_wafl->interval.last_read) > now)
return (0);
/* Data corresponding to <Disks /> */
static int cna_handle_disk_data (const char *hostname, /* {{{ */
- cfg_disk_t *cfg_disk, na_elem_t *data, int interval)
+ cfg_disk_t *cfg_disk, na_elem_t *data, cdtime_t interval)
{
- time_t timestamp;
+ cdtime_t timestamp;
na_elem_t *instances;
na_elem_t *instance;
na_elem_iter_t instance_iter;
if ((cfg_disk == NULL) || (data == NULL))
return (EINVAL);
- timestamp = (time_t) na_child_get_uint64(data, "timestamp", 0);
+ timestamp = cna_child_get_cdtime (data);
instances = na_elem_child (data, "instances");
if (instances == NULL)
{
na_elem_t *data;
int status;
- time_t now;
+ cdtime_t now;
if (host == NULL)
return (EINVAL);
if (host->cfg_disk == NULL)
return (0);
- now = time (NULL);
+ now = cdtime ();
if ((host->cfg_disk->interval.interval + host->cfg_disk->interval.last_read) > now)
return (0);
/* Data corresponding to <VolumePerf /> */
static int cna_handle_volume_perf_data (const char *hostname, /* {{{ */
- cfg_volume_perf_t *cvp, na_elem_t *data, int interval)
+ cfg_volume_perf_t *cvp, na_elem_t *data, cdtime_t interval)
{
- time_t timestamp;
+ cdtime_t timestamp;
na_elem_t *elem_instances;
na_elem_iter_t iter_instances;
na_elem_t *elem_instance;
- timestamp = (time_t) na_child_get_uint64(data, "timestamp", 0);
+ timestamp = cna_child_get_cdtime (data);
elem_instances = na_elem_child(data, "instances");
if (elem_instances == NULL)
{
na_elem_t *data;
int status;
- time_t now;
+ cdtime_t now;
if (host == NULL)
return (EINVAL);
if (host->cfg_volume_perf == NULL)
return (0);
- now = time (NULL);
+ now = cdtime ();
if ((host->cfg_volume_perf->interval.interval + host->cfg_volume_perf->interval.last_read) > now)
return (0);
notification_t n;
memset (&n, 0, sizeof (&n));
- n.time = time (NULL);
+ n.time = cdtime ();
sstrncpy (n.host, hostname, sizeof (n.host));
sstrncpy (n.plugin, "netapp", sizeof (n.plugin));
sstrncpy (n.plugin_instance, v->name, sizeof (n.plugin_instance));
{
na_elem_t *data;
int status;
- time_t now;
+ cdtime_t now;
if (host == NULL)
return (EINVAL);
if (host->cfg_volume_usage == NULL)
return (0);
- now = time (NULL);
+ now = cdtime ();
if ((host->cfg_volume_usage->interval.interval + host->cfg_volume_usage->interval.last_read) > now)
return (0);
uint32_t counter_flags = 0;
const char *instance;
- time_t timestamp;
+ cdtime_t timestamp;
- timestamp = (time_t) na_child_get_uint64 (data, "timestamp", 0);
+ timestamp = cna_child_get_cdtime (data);
instances = na_elem_child(na_elem_child (data, "instances"), "instance-data");
if (instances == NULL)
{
na_elem_t *data;
int status;
- time_t now;
+ cdtime_t now;
if (host == NULL)
return (EINVAL);
if (host->cfg_system == NULL)
return (0);
- now = time (NULL);
+ now = cdtime ();
if ((host->cfg_system->interval.interval + host->cfg_system->interval.last_read) > now)
return (0);
static int cna_config_get_interval (const oconfig_item_t *ci, /* {{{ */
cna_interval_t *out_interval)
{
- time_t tmp;
-
- if ((ci == NULL) || (out_interval == NULL))
- return (EINVAL);
-
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
- {
- WARNING ("netapp plugin: The `Interval' option needs exactly one numeric argument.");
- return (-1);
- }
+ cdtime_t tmp = 0;
+ int status;
- tmp = (time_t) (ci->values[0].value.number + .5);
- if (tmp < 1)
- {
- WARNING ("netapp plugin: The `Interval' option needs a positive integer argument.");
- return (-1);
- }
+ status = cf_util_get_cdtime (ci, &tmp);
+ if (status != 0)
+ return (status);
out_interval->interval = tmp;
out_interval->last_read = 0;
} else if (!strcasecmp(item->key, "Password")) {
status = cf_util_get_string (item, &host->password);
} else if (!strcasecmp(item->key, "Interval")) {
- if (item->values_num != 1 || item->values[0].type != OCONFIG_TYPE_NUMBER || item->values[0].value.number != (int) item->values[0].value.number || item->values[0].value.number < 2) {
- WARNING("netapp plugin: \"Interval\" of host %s needs exactly one integer argument.", ci->values[0].value.string);
- continue;
- }
- host->interval = item->values[0].value.number;
+ status = cf_util_get_cdtime (item, &host->interval);
} else if (!strcasecmp(item->key, "WAFL")) {
cna_config_wafl(host, item);
} else if (!strcasecmp(item->key, "Disks")) {
ssnprintf (cb_name, sizeof (cb_name), "netapp-%s", host->name);
- memset (&interval, 0, sizeof (interval));
- interval.tv_sec = host->interval;
+ CDTIME_T_TO_TIMESPEC (host->interval, &interval);
memset (&ud, 0, sizeof (ud));
ud.data = host;
diff --git a/src/network.c b/src/network.c
index 412b457bcf522028b8e8a9a82ed37697e86fbe58..7a1fcf7fd2bc9c3a6734a1e5ada0f2a68b5cef90 100644 (file)
--- a/src/network.c
+++ b/src/network.c
* Private variables
*/
static int network_config_ttl = 0;
-static size_t network_config_packet_size = 1024;
+static size_t network_config_packet_size = 1452;
static int network_config_forward = 0;
static int network_config_stats = 0;
/* This is a value we already sent. Don't allow it to be received again in
* order to avoid looping. */
if ((status == 0) && (time_sent >= ((uint64_t) vl->time)))
- return (false);
+ return (0);
- return (true);
+ return (1);
} /* }}} _Bool check_receive_okay */
static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
{
- _Bool received = false;
+ _Bool received = 0;
int status;
if (network_config_forward != 0)
- return (true);
+ return (1);
if (vl->meta == NULL)
- return (true);
+ return (1);
status = meta_data_get_boolean (vl->meta, "network:received", &received);
if (status == -ENOENT)
- return (true);
+ return (1);
else if (status != 0)
{
ERROR ("network plugin: check_send_okay: meta_data_get_boolean failed "
"with status %i.", status);
- return (true);
+ return (1);
}
/* By default, only *send* value lists that were not *received* by the
return (-ENOMEM);
}
- status = meta_data_add_boolean (vl->meta, "network:received", true);
+ status = meta_data_add_boolean (vl->meta, "network:received", 1);
if (status != 0)
{
ERROR ("network plugin: meta_data_add_boolean failed.");
&tmp);
if (status == 0)
{
- vl.time = (time_t) tmp;
- n.time = (time_t) tmp;
+ vl.time = TIME_T_TO_CDTIME_T (tmp);
+ n.time = TIME_T_TO_CDTIME_T (tmp);
+ }
+ }
+ else if (pkg_type == TYPE_TIME_HR)
+ {
+ uint64_t tmp = 0;
+ status = parse_part_number (&buffer, &buffer_size,
+ &tmp);
+ if (status == 0)
+ {
+ vl.time = (cdtime_t) tmp;
+ n.time = (cdtime_t) tmp;
}
}
else if (pkg_type == TYPE_INTERVAL)
status = parse_part_number (&buffer, &buffer_size,
&tmp);
if (status == 0)
- vl.interval = (int) tmp;
+ vl.interval = TIME_T_TO_CDTIME_T (tmp);
+ }
+ else if (pkg_type == TYPE_INTERVAL_HR)
+ {
+ uint64_t tmp = 0;
+ status = parse_part_number (&buffer, &buffer_size,
+ &tmp);
+ if (status == 0)
+ vl.interval = (cdtime_t) tmp;
}
else if (pkg_type == TYPE_HOST)
{
if (vl_def->time != vl->time)
{
- if (write_part_number (&buffer, &buffer_size, TYPE_TIME,
+ if (write_part_number (&buffer, &buffer_size, TYPE_TIME_HR,
(uint64_t) vl->time))
return (-1);
vl_def->time = vl->time;
if (vl_def->interval != vl->interval)
{
- if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL,
+ if (write_part_number (&buffer, &buffer_size, TYPE_INTERVAL_HR,
(uint64_t) vl->interval))
return (-1);
vl_def->interval = vl->interval;
network_config_set_boolean (child, &network_config_forward);
else if (strcasecmp ("ReportStats", child->key) == 0)
network_config_set_boolean (child, &network_config_stats);
- else if (strcasecmp ("CacheFlush", child->key) == 0)
- /* no op for backwards compatibility only */;
else
{
WARNING ("network plugin: Option `%s' is not allowed here.",
memset (buffer, '\0', sizeof (buffer));
-
- status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME,
+ status = write_part_number (&buffer_ptr, &buffer_free, TYPE_TIME_HR,
(uint64_t) n->time);
if (status != 0)
return (-1);
static int network_init (void)
{
- static _Bool have_init = false;
+ static _Bool have_init = 0;
/* Check if we were already initialized. If so, just return - there's
* nothing more to do (for now, that is). */
if (have_init)
return (0);
- have_init = true;
+ have_init = 1;
#if HAVE_LIBGCRYPT
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
* just send the buffer if `flush' is called - if the requested value was in
* there, good. If not, well, then there is nothing to flush.. -octo
*/
-static int network_flush (int timeout,
- const char __attribute__((unused)) *identifier,
- user_data_t __attribute__((unused)) *user_data)
+static int network_flush (__attribute__((unused)) cdtime_t timeout,
+ __attribute__((unused)) const char *identifier,
+ __attribute__((unused)) user_data_t *user_data)
{
pthread_mutex_lock (&send_buffer_lock);
diff --git a/src/network.h b/src/network.h
index 777616c4725cc75ddb13f9844e5c833aa81e7e35..1b354561ec7e8a2ab6e7a29cb1f6106445cca28f 100644 (file)
--- a/src/network.h
+++ b/src/network.h
#define TYPE_HOST 0x0000
#define TYPE_TIME 0x0001
+#define TYPE_TIME_HR 0x0008
#define TYPE_PLUGIN 0x0002
#define TYPE_PLUGIN_INSTANCE 0x0003
#define TYPE_TYPE 0x0004
#define TYPE_TYPE_INSTANCE 0x0005
#define TYPE_VALUES 0x0006
#define TYPE_INTERVAL 0x0007
+#define TYPE_INTERVAL_HR 0x0009
/* Types to transmit notifications */
#define TYPE_MESSAGE 0x0100
diff --git a/src/nginx.c b/src/nginx.c
index 697684277a153911fdc43474cdc74bdab5b62d1e..36d3d8d2bed85f9de5867f9f381f0102e85f51c0 100644 (file)
--- a/src/nginx.c
+++ b/src/nginx.c
static CURL *curl = NULL;
-#define ABUFFER_SIZE 16384
-static char nginx_buffer[ABUFFER_SIZE];
-static int nginx_buffer_len = 0;
-static char nginx_curl_error[CURL_ERROR_SIZE];
+static char nginx_buffer[16384];
+static size_t nginx_buffer_len = 0;
+static char nginx_curl_error[CURL_ERROR_SIZE];
static const char *config_keys[] =
{
{
size_t len = size * nmemb;
- if ((nginx_buffer_len + len) >= ABUFFER_SIZE)
+ /* Check if the data fits into the memory. If not, truncate it. */
+ if ((nginx_buffer_len + len) >= sizeof (nginx_buffer))
{
- len = (ABUFFER_SIZE - 1) - nginx_buffer_len;
+ assert (sizeof (nginx_buffer) > nginx_buffer_len);
+ len = (sizeof (nginx_buffer) - 1) - nginx_buffer_len;
}
if (len <= 0)
return (len);
- memcpy (nginx_buffer + nginx_buffer_len, (char *) buf, len);
+ memcpy (&nginx_buffer[nginx_buffer_len], buf, len);
nginx_buffer_len += len;
- nginx_buffer[nginx_buffer_len] = '\0';
+ nginx_buffer[nginx_buffer_len] = 0;
return (len);
}
diff --git a/src/notify_email.c b/src/notify_email.c
index 0aed27f12bb2ac8b41b5fa4e80d586e0c71f8bca..da6894a3db4dc8d0de24fbde2408ff03f194f47a 100644 (file)
--- a/src/notify_email.c
+++ b/src/notify_email.c
{
smtp_recipient_t recipient;
+ time_t tt;
struct tm timestamp_tm;
char timestamp_str[64];
(email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject,
severity, n->host);
- localtime_r (&n->time, ×tamp_tm);
+ tt = CDTIME_T_TO_TIME_T (n->time);
+ localtime_r (&tt, ×tamp_tm);
strftime (timestamp_str, sizeof (timestamp_str), "%Y-%m-%d %H:%M:%S",
×tamp_tm);
timestamp_str[sizeof (timestamp_str) - 1] = '\0';
diff --git a/src/onewire.c b/src/onewire.c
index 462458c73d626d097915501ce1c08221daa5245c..09a6bf0926154369c3fe75e408a3c79c9b194cfe 100644 (file)
--- a/src/onewire.c
+++ b/src/onewire.c
static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features);
static char *device_g = NULL;
-static int ow_interval = 0;
+static cdtime_t ow_interval = 0;
static const char *config_keys[] =
{
}
else if (strcasecmp ("Interval", key) == 0)
{
- int tmp;
- tmp = atoi (value);
- if (tmp > 0)
- ow_interval = tmp;
+ double tmp;
+ tmp = atof (value);
+ if (tmp > 0.0)
+ ow_interval = DOUBLE_TO_CDTIME_T (tmp);
else
ERROR ("onewire plugin: Invalid `Interval' setting: %s", value);
}
return (1);
}
- memset (&cb_interval, 0, sizeof (cb_interval));
- if (ow_interval > 0)
- cb_interval.tv_sec = (time_t) ow_interval;
+ CDTIME_T_TO_TIMESPEC (ow_interval, &cb_interval);
plugin_register_complex_read (/* group = */ NULL, "onewire", cow_read,
- &cb_interval, /* user data = */ NULL);
+ (ow_interval != 0) ? &cb_interval : NULL,
+ /* user data = */ NULL);
plugin_register_shutdown ("onewire", cow_shutdown);
return (0);
diff --git a/src/oracle.c b/src/oracle.c
index 3fe21254ab33f08391ec7c45c6c26216ec074816..03567494f227cd281e41d528fbbee7fc67823620 100644 (file)
--- a/src/oracle.c
+++ b/src/oracle.c
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Query", child->key) == 0)
udb_query_create (&queries, &queries_num, child,
- /* callback = */ NULL, /* legacy mode = */ 0);
+ /* callback = */ NULL);
else if (strcasecmp ("Database", child->key) == 0)
o_config_add_database (child);
else
status = udb_query_prepare_result (q, prep_area, hostname_g,
/* plugin = */ "oracle", db->name, column_names, column_num,
- /* interval = */ -1);
+ /* interval = */ 0);
if (status != 0)
{
ERROR ("oracle plugin: o_read_database_query (%s, %s): "
diff --git a/src/perl.c b/src/perl.c
index a2f5da299bf92ae9679d3fd69b478f691540e3e4..f8a482275d89bde294344222b060294cdaa8b3e6 100644 (file)
--- a/src/perl.c
+++ b/src/perl.c
#include "configfile.h"
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
+
#include <EXTERN.h>
#include <perl.h>
{ "", NULL }
};
-struct {
- char name[64];
- int *var;
-} g_integers[] =
-{
- { "Collectd::interval_g", &interval_g },
- { "", NULL }
-};
-
/*
* Helper functions for data type conversion.
*/
}
if (NULL != (tmp = hv_fetch (hash, "time", 4, 0)))
- vl->time = (time_t)SvIV (*tmp);
+ {
+ double t = SvNV (*tmp);
+ vl->time = DOUBLE_TO_CDTIME_T (t);
+ }
if (NULL != (tmp = hv_fetch (hash, "interval", 8, 0)))
- vl->interval = SvIV (*tmp);
+ {
+ double t = SvNV (*tmp);
+ vl->interval = DOUBLE_TO_CDTIME_T (t);
+ }
if (NULL != (tmp = hv_fetch (hash, "host", 4, 0)))
sstrncpy (vl->host, SvPV_nolen (*tmp), sizeof (vl->host));
n->severity = NOTIF_FAILURE;
if (NULL != (tmp = hv_fetch (hash, "time", 4, 0)))
- n->time = (time_t)SvIV (*tmp);
+ {
+ double t = SvNV (*tmp);
+ n->time = DOUBLE_TO_CDTIME_T (t);
+ }
else
- n->time = time (NULL);
+ n->time = cdtime ();
if (NULL != (tmp = hv_fetch (hash, "message", 7, 0)))
sstrncpy (n->message, SvPV_nolen (*tmp), sizeof (n->message));
return -1;
if (0 != vl->time)
- if (NULL == hv_store (hash, "time", 4, newSViv (vl->time), 0))
+ {
+ double t = CDTIME_T_TO_DOUBLE (vl->time);
+ if (NULL == hv_store (hash, "time", 4, newSVnv (t), 0))
return -1;
+ }
- if (NULL == hv_store (hash, "interval", 8, newSViv (vl->interval), 0))
- return -1;
+ {
+ double t = CDTIME_T_TO_DOUBLE (vl->interval);
+ if (NULL == hv_store (hash, "interval", 8, newSVnv (t), 0))
+ return -1;
+ }
if ('\0' != vl->host[0])
if (NULL == hv_store (hash, "host", 4, newSVpv (vl->host, 0), 0))
return -1;
if (0 != n->time)
- if (NULL == hv_store (hash, "time", 4, newSViv (n->time), 0))
+ {
+ double t = CDTIME_T_TO_DOUBLE (n->time);
+ if (NULL == hv_store (hash, "time", 4, newSVnv (t), 0))
return -1;
+ }
if ('\0' != *n->message)
if (NULL == hv_store (hash, "message", 7, newSVpv (n->message, 0), 0))
XPUSHs (sv_2mortal (newRV_noinc ((SV *)notif)));
}
else if (PLUGIN_FLUSH == type) {
+ cdtime_t timeout;
+
/*
* $_[0] = $timeout;
* $_[1] = $identifier;
*/
- XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
+ timeout = va_arg (ap, cdtime_t);
+
+ XPUSHs (sv_2mortal (newSVnv (CDTIME_T_TO_DOUBLE (timeout))));
XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
}
static XS (Collectd_plugin_dispatch_values)
{
SV *values = NULL;
- int values_idx = 0;
int ret = 0;
dXSARGS;
- if (2 == items) {
- log_warn ("Collectd::plugin_dispatch_values with two arguments "
- "is deprecated - pass the type through values->{type}.");
- values_idx = 1;
- }
- else if (1 != items) {
+ if (1 != items) {
log_err ("Usage: Collectd::plugin_dispatch_values(values)");
XSRETURN_EMPTY;
}
log_debug ("Collectd::plugin_dispatch_values: values=\"%s\"",
- SvPV_nolen (ST (values_idx)));
+ SvPV_nolen (ST (/* stack index = */ 0)));
- values = ST (values_idx);
+ values = ST (/* stack index = */ 0);
+ /* Make sure the argument is a hash reference. */
if (! (SvROK (values) && (SVt_PVHV == SvTYPE (SvRV (values))))) {
log_err ("Collectd::plugin_dispatch_values: Invalid values.");
XSRETURN_EMPTY;
}
- if (((2 == items) && (NULL == ST (0))) || (NULL == values))
- XSRETURN_EMPTY;
-
- if ((2 == items) && (NULL == hv_store ((HV *)SvRV (values), "type", 4,
- newSVsv (ST (0)), 0))) {
- log_err ("Collectd::plugin_dispatch_values: Could not store type.");
+ if (NULL == values)
XSRETURN_EMPTY;
- }
ret = pplugin_dispatch_values (aTHX_ (HV *)SvRV (values));
return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
} /* static int perl_notify (const notification_t *) */
-static int perl_flush (int timeout, const char *identifier,
+static int perl_flush (cdtime_t timeout, const char *identifier,
user_data_t __attribute__((unused)) *user_data)
{
dTHX;
return 0;
} /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
-static int g_iv_get (pTHX_ SV *var, MAGIC *mg)
+static int g_interval_get (pTHX_ SV *var, MAGIC *mg)
{
- int *iv = (int *)mg->mg_ptr;
- sv_setiv (var, *iv);
+ cdtime_t *interval = (cdtime_t *)mg->mg_ptr;
+ double nv;
+
+ nv = CDTIME_T_TO_DOUBLE (*interval);
+
+ sv_setnv (var, nv);
return 0;
-} /* static int g_iv_get (pTHX_ SV *, MAGIC *) */
+} /* static int g_interval_get (pTHX_ SV *, MAGIC *) */
-static int g_iv_set (pTHX_ SV *var, MAGIC *mg)
+static int g_interval_set (pTHX_ SV *var, MAGIC *mg)
{
- int *iv = (int *)mg->mg_ptr;
- *iv = (int)SvIV (var);
+ cdtime_t *interval = (cdtime_t *)mg->mg_ptr;
+ double nv;
+
+ nv = (double)SvNV (var);
+
+ *interval = DOUBLE_TO_CDTIME_T (nv);
return 0;
-} /* static int g_iv_set (pTHX_ SV *, MAGIC *) */
+} /* static int g_interval_set (pTHX_ SV *, MAGIC *) */
static MGVTBL g_pv_vtbl = {
g_pv_get, g_pv_set, NULL, NULL, NULL, NULL, NULL
, NULL
#endif
};
-static MGVTBL g_iv_vtbl = {
- g_iv_get, g_iv_set, NULL, NULL, NULL, NULL, NULL
+static MGVTBL g_interval_vtbl = {
+ g_interval_get, g_interval_set, NULL, NULL, NULL, NULL, NULL
#if HAVE_PERL_STRUCT_MGVTBL_SVT_LOCAL
, NULL
#endif
g_strings[i].var, 0);
}
- /* global integers */
- for (i = 0; '\0' != g_integers[i].name[0]; ++i) {
- tmp = get_sv (g_integers[i].name, 1);
- sv_magicext (tmp, NULL, PERL_MAGIC_ext, &g_iv_vtbl,
- (char *)g_integers[i].var, 0);
- }
+ tmp = get_sv ("Collectd::interval_g", /* create = */ 1);
+ sv_magicext (tmp, NULL, /* how = */ PERL_MAGIC_ext,
+ /* vtbl = */ &g_interval_vtbl,
+ /* name = */ (char *) &interval_g, /* namelen = */ 0);
+
return;
} /* static void xs_init (pTHX) */
diff --git a/src/plugin.c b/src/plugin.c
index af894d54724c804a0bed9ae512b74fd533f9a18d..e32c8f9c900faa3f7bd36b91296b3091287e05c2 100644 (file)
--- a/src/plugin.c
+++ b/src/plugin.c
/**
* collectd - src/plugin.c
- * Copyright (C) 2005-2009 Florian octo Forster
+ * Copyright (C) 2005-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
* Sebastian Harl <sh at tokkee.org>
**/
static llist_t *list_init;
static llist_t *list_write;
static llist_t *list_flush;
+static llist_t *list_missing;
static llist_t *list_shutdown;
static llist_t *list_log;
static llist_t *list_notification;
while (read_loop != 0)
{
read_func_t *rf;
- struct timeval now;
+ cdtime_t now;
int status;
int rf_type;
int rc;
{
struct timespec abstime;
- gettimeofday (&now, /* timezone = */ NULL);
+ now = cdtime ();
- abstime.tv_sec = now.tv_sec + interval_g;
- abstime.tv_nsec = 1000 * now.tv_usec;
+ CDTIME_T_TO_TIMESPEC (now + interval_g, &abstime);
pthread_mutex_lock (&read_lock);
pthread_cond_timedwait (&read_cond, &read_lock,
if ((rf->rf_interval.tv_sec == 0) && (rf->rf_interval.tv_nsec == 0))
{
- gettimeofday (&now, /* timezone = */ NULL);
+ now = cdtime ();
- rf->rf_interval.tv_sec = interval_g;
- rf->rf_interval.tv_nsec = 0;
+ CDTIME_T_TO_TIMESPEC (interval_g, &rf->rf_interval);
rf->rf_effective_interval = rf->rf_interval;
- rf->rf_next_read.tv_sec = now.tv_sec;
- rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
+ CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
}
/* sleep until this entry is due,
}
/* update the ``next read due'' field */
- gettimeofday (&now, /* timezone = */ NULL);
+ now = cdtime ();
DEBUG ("plugin_read_thread: Effective interval of the "
"%s plugin is %i.%09i.",
NORMALIZE_TIMESPEC (rf->rf_next_read);
/* Check, if `rf_next_read' is in the past. */
- if ((rf->rf_next_read.tv_sec < now.tv_sec)
- || ((rf->rf_next_read.tv_sec == now.tv_sec)
- && (rf->rf_next_read.tv_nsec < (1000 * now.tv_usec))))
+ if (TIMESPEC_TO_CDTIME_T (&rf->rf_next_read) < now)
{
/* `rf_next_read' is in the past. Insert `now'
* so this value doesn't trail off into the
* past too much. */
- rf->rf_next_read.tv_sec = now.tv_sec;
- rf->rf_next_read.tv_nsec = 1000 * now.tv_usec;
+ CDTIME_T_TO_TIMESPEC (now, &rf->rf_next_read);
}
DEBUG ("plugin_read_thread: Next read of the %s plugin at %i.%09i.",
(void *) callback, ud));
} /* int plugin_register_flush */
+int plugin_register_missing (const char *name,
+ plugin_missing_cb callback, user_data_t *ud)
+{
+ return (create_register_callback (&list_missing, name,
+ (void *) callback, ud));
+} /* int plugin_register_missing */
+
int plugin_register_shutdown (char *name,
int (*callback) (void))
{
return (plugin_unregister (list_flush, name));
}
+int plugin_unregister_missing (const char *name)
+{
+ return (plugin_unregister (list_missing, name));
+}
+
int plugin_unregister_shutdown (const char *name)
{
return (plugin_unregister (list_shutdown, name));
return (status);
} /* }}} int plugin_write */
-int plugin_flush (const char *plugin, int timeout, const char *identifier)
+int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier)
{
llentry_t *le;
destroy_read_heap ();
- plugin_flush (/* plugin = */ NULL, /* timeout = */ -1,
+ plugin_flush (/* plugin = */ NULL,
+ /* timeout = */ 0,
/* identifier = */ NULL);
le = NULL;
* the real free function when registering the write callback. This way
* the data isn't freed twice. */
destroy_all_callbacks (&list_flush);
+ destroy_all_callbacks (&list_missing);
destroy_all_callbacks (&list_write);
destroy_all_callbacks (&list_notification);
destroy_all_callbacks (&list_log);
} /* void plugin_shutdown_all */
+int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */
+{
+ llentry_t *le;
+
+ if (list_missing == NULL)
+ return (0);
+
+ le = llist_head (list_missing);
+ while (le != NULL)
+ {
+ callback_func_t *cf;
+ plugin_missing_cb callback;
+ int status;
+
+ cf = le->value;
+ callback = cf->cf_callback;
+
+ status = (*callback) (vl);
+ if (status != 0)
+ {
+ if (status < 0)
+ {
+ ERROR ("plugin_dispatch_missing: Callback function \"%s\" "
+ "failed with status %i.",
+ le->key, status);
+ return (status);
+ }
+ else
+ {
+ return (0);
+ }
+ }
+
+ le = le->next;
+ }
+ return (0);
+} /* int }}} plugin_dispatch_missing */
+
int plugin_dispatch_values (value_list_t *vl)
{
int status;
}
if (vl->time == 0)
- vl->time = time (NULL);
+ vl->time = cdtime ();
if (vl->interval <= 0)
vl->interval = interval_g;
- DEBUG ("plugin_dispatch_values: time = %u; interval = %i; "
+ DEBUG ("plugin_dispatch_values: time = %.3f; interval = %.3f; "
"host = %s; "
"plugin = %s; plugin_instance = %s; "
"type = %s; type_instance = %s;",
- (unsigned int) vl->time, vl->interval,
+ CDTIME_T_TO_DOUBLE (vl->time),
+ CDTIME_T_TO_DOUBLE (vl->interval),
vl->host,
vl->plugin, vl->plugin_instance,
vl->type, vl->type_instance);
/* Possible TODO: Add flap detection here */
DEBUG ("plugin_dispatch_notification: severity = %i; message = %s; "
- "time = %u; host = %s;",
+ "time = %.3f; host = %s;",
notif->severity, notif->message,
- (unsigned int) notif->time, notif->host);
+ CDTIME_T_TO_DOUBLE (notif->time), notif->host);
/* Nobody cares for notifications */
if (list_notification == NULL)
}
case NM_TYPE_BOOLEAN:
{
- meta->nm_value.nm_boolean = *((bool *) value);
+ meta->nm_value.nm_boolean = *((_Bool *) value);
break;
}
default:
int plugin_notification_meta_add_boolean (notification_t *n,
const char *name,
- bool value)
+ _Bool value)
{
return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
}
diff --git a/src/plugin.h b/src/plugin.h
index 8b9449ee1dd64ec76436446bbbbaa9edd38a898b..bc873b08c939bc892982b944c62f9085f80f199a 100644 (file)
--- a/src/plugin.h
+++ b/src/plugin.h
#define PLUGIN_H
/**
* collectd - src/plugin.h
- * Copyright (C) 2005-2008 Florian octo Forster
+ * Copyright (C) 2005-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
* Sebastian Harl <sh at tokkee.org>
**/
#include "collectd.h"
#include "configfile.h"
#include "meta_data.h"
+#include "utils_time.h"
#define PLUGIN_FLAGS_GLOBAL 0x0001
{
value_t *values;
int values_len;
- time_t time;
- int interval;
+ cdtime_t time;
+ cdtime_t interval;
char host[DATA_MAX_NAME_LEN];
char plugin[DATA_MAX_NAME_LEN];
char plugin_instance[DATA_MAX_NAME_LEN];
int64_t nm_signed_int;
uint64_t nm_unsigned_int;
double nm_double;
- bool nm_boolean;
+ _Bool nm_boolean;
} nm_value;
struct notification_meta_s *next;
} notification_meta_t;
typedef struct notification_s
{
int severity;
- time_t time;
+ cdtime_t time;
char message[NOTIF_MAX_MSG_LEN];
char host[DATA_MAX_NAME_LEN];
char plugin[DATA_MAX_NAME_LEN];
typedef int (*plugin_read_cb) (user_data_t *);
typedef int (*plugin_write_cb) (const data_set_t *, const value_list_t *,
user_data_t *);
-typedef int (*plugin_flush_cb) (int timeout, const char *identifier,
+typedef int (*plugin_flush_cb) (cdtime_t timeout, const char *identifier,
user_data_t *);
+/* "missing" callback. Returns less than zero on failure, zero if other
+ * callbacks should be called, greater than zero if no more callbacks should be
+ * called. */
+typedef int (*plugin_missing_cb) (const value_list_t *);
typedef void (*plugin_log_cb) (int severity, const char *message,
user_data_t *);
typedef int (*plugin_shutdown_cb) (void);
int plugin_write (const char *plugin,
const data_set_t *ds, const value_list_t *vl);
-int plugin_flush (const char *plugin, int timeout, const char *identifier);
+int plugin_flush (const char *plugin, cdtime_t timeout, const char *identifier);
/*
* The `plugin_register_*' functions are used to make `config', `init',
plugin_write_cb callback, user_data_t *user_data);
int plugin_register_flush (const char *name,
plugin_flush_cb callback, user_data_t *user_data);
+int plugin_register_missing (const char *name,
+ plugin_missing_cb callback, user_data_t *user_data);
int plugin_register_shutdown (char *name,
plugin_shutdown_cb callback);
int plugin_register_data_set (const data_set_t *ds);
int plugin_unregister_read_group (const char *group);
int plugin_unregister_write (const char *name);
int plugin_unregister_flush (const char *name);
+int plugin_unregister_missing (const char *name);
int plugin_unregister_shutdown (const char *name);
int plugin_unregister_data_set (const char *name);
int plugin_unregister_log (const char *name);
* function.
*/
int plugin_dispatch_values (value_list_t *vl);
+int plugin_dispatch_missing (const value_list_t *vl);
int plugin_dispatch_notification (const notification_t *notif);
double value);
int plugin_notification_meta_add_boolean (notification_t *n,
const char *name,
- bool value);
+ _Bool value);
int plugin_notification_meta_copy (notification_t *dst,
const notification_t *src);
diff --git a/src/postgresql.c b/src/postgresql.c
index dd53cb4fd2b018fd11dd18a8d1c5788b7cc95a04..a8812e2158327bf86153689894e8eada7e620022 100644 (file)
--- a/src/postgresql.c
+++ b/src/postgresql.c
udb_query_t **queries;
size_t queries_num;
- int interval;
+ cdtime_t interval;
char *host;
char *port;
params[i] = db->user;
break;
case C_PSQL_PARAM_INTERVAL:
- ssnprintf (interval, sizeof (interval), "%i",
- db->interval > 0 ? db->interval : interval_g);
+ ssnprintf (interval, sizeof (interval), "%.3f",
+ (db->interval > 0)
+ ? CDTIME_T_TO_DOUBLE (db->interval) : interval_g);
params[i] = interval;
break;
default:
return 0;
} /* config_set_s */
-static int config_set_i (char *name, int *var,
- const oconfig_item_t *ci, int min)
-{
- int value;
-
- if ((0 != ci->children_num) || (1 != ci->values_num)
- || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) {
- log_err ("%s expects a single number argument.", name);
- return 1;
- }
-
- value = (int)ci->values[0].value.number;
-
- if (value < min) {
- log_err ("%s expects a number greater or equal to %i.", name, min);
- return 1;
- }
-
- *var = value;
- return 0;
-} /* config_set_s */
-
static int config_query_param_add (udb_query_t *q, oconfig_item_t *ci)
{
c_psql_user_data_t *data;
c_psql_database_t *db;
char cb_name[DATA_MAX_NAME_LEN];
- struct timespec cb_interval;
+ struct timespec cb_interval = { 0, 0 };
user_data_t ud;
int i;
udb_query_pick_from_list (c, queries, queries_num,
&db->queries, &db->queries_num);
else if (0 == strcasecmp (c->key, "Interval"))
- config_set_i ("Interval", &db->interval, c, /* min = */ 1);
+ cf_util_get_cdtime (c, &db->interval);
else
log_warn ("Ignoring unknown config key \"%s\".", c->key);
}
ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->database);
- memset (&cb_interval, 0, sizeof (cb_interval));
- if (db->interval > 0)
- cb_interval.tv_sec = (time_t)db->interval;
+ CDTIME_T_TO_TIMESPEC (db->interval, &cb_interval);
plugin_register_complex_read ("postgresql", cb_name, c_psql_read,
- /* interval = */ &cb_interval, &ud);
+ /* interval = */ (db->interval > 0) ? &cb_interval : NULL,
+ &ud);
return 0;
} /* c_psql_config_database */
if (0 == strcasecmp (c->key, "Query"))
udb_query_create (&queries, &queries_num, c,
- /* callback = */ config_query_callback,
- /* legacy mode = */ 1);
+ /* callback = */ config_query_callback);
else if (0 == strcasecmp (c->key, "Database"))
c_psql_config_database (c);
else
diff --git a/src/powerdns.c b/src/powerdns.c
index 29f6bca502c7b48be0ecbadd2bc4befabf337885..a1b23555bec080592a261f91e1d6e02ae769bd6a 100644 (file)
--- a/src/powerdns.c
+++ b/src/powerdns.c
struct sockaddr_un sa_unix;
+ struct timeval stv_timeout;
+ cdtime_t cdt_timeout;
+
sd = socket (PF_UNIX, item->socktype, 0);
if (sd < 0)
{
break;
}
- struct timeval timeout;
- timeout.tv_sec=2;
- if (timeout.tv_sec < interval_g * 3 / 4)
- timeout.tv_sec = interval_g * 3 / 4;
- timeout.tv_usec=0;
- status = setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof (timeout));
+ cdt_timeout = interval_g * 3 / 4;
+ if (cdt_timeout < TIME_T_TO_CDTIME_T (2))
+ cdt_timeout = TIME_T_TO_CDTIME_T (2);
+
+ CDTIME_T_TO_TIMEVAL (cdt_timeout, &stv_timeout);
+
+ status = setsockopt (sd, SOL_SOCKET, SO_RCVTIMEO, &stv_timeout, sizeof (stv_timeout));
if (status != 0)
{
FUNC_ERROR ("setsockopt");
diff --git a/src/python.c b/src/python.c
index c056b5bf076ebee47b4490ff033a204dbf8f922e..eed0591d395aed66ba373d3b02b208e65912adf3 100644 (file)
--- a/src/python.c
+++ b/src/python.c
@@ -435,8 +435,8 @@ static int cpy_write_callback(const data_set_t *ds, const value_list_t *value_li
sstrncpy(v->data.type_instance, value_list->type_instance, sizeof(v->data.type_instance));
sstrncpy(v->data.plugin, value_list->plugin, sizeof(v->data.plugin));
sstrncpy(v->data.plugin_instance, value_list->plugin_instance, sizeof(v->data.plugin_instance));
- v->data.time = value_list->time;
- v->interval = value_list->interval;
+ v->data.time = CDTIME_T_TO_DOUBLE(value_list->time);
+ v->interval = CDTIME_T_TO_DOUBLE(value_list->interval);
Py_CLEAR(v->values);
v->values = list;
Py_CLEAR(v->meta);
@@ -465,7 +465,7 @@ static int cpy_notification_callback(const notification_t *notification, user_da
sstrncpy(n->data.type_instance, notification->type_instance, sizeof(n->data.type_instance));
sstrncpy(n->data.plugin, notification->plugin, sizeof(n->data.plugin));
sstrncpy(n->data.plugin_instance, notification->plugin_instance, sizeof(n->data.plugin_instance));
- n->data.time = notification->time;
+ n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
sstrncpy(n->message, notification->message, sizeof(n->message));
n->severity = notification->severity;
ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data, (void *) 0); /* New reference. */
diff --git a/src/pyvalues.c b/src/pyvalues.c
index cc7e296c020e0a7df6706f432a374371caeb7219..36a717e9bfec401b54d8e2b629f110a01a303d7a 100644 (file)
--- a/src/pyvalues.c
+++ b/src/pyvalues.c
if (self->time != 0) {
CPY_STRCAT(&ret, l_time);
- tmp = PyInt_FromLong(self->time);
+ tmp = PyFloat_FromDouble(self->time);
CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
CPY_STRCAT_AND_DEL(&ret, tmp);
}
@@ -351,14 +351,13 @@ static PyObject *Values_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
static int Values_init(PyObject *s, PyObject *args, PyObject *kwds) {
Values *self = (Values *) s;
- int interval = 0;
- double time = 0;
+ double interval = 0, time = 0;
PyObject *values = NULL, *meta = NULL, *tmp;
const char *type = "", *plugin_instance = "", *type_instance = "", *plugin = "", *host = "";
static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
"plugin", "host", "time", "interval", "meta", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
NULL, &plugin, NULL, &host, &time, &interval, &meta))
return -1;
@@ -485,8 +484,7 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
value_t *value;
value_list_t value_list = VALUE_LIST_INIT;
PyObject *values = self->values, *meta = self->meta;
- double time = self->data.time;
- int interval = self->interval;
+ double time = self->data.time, interval = self->interval;
const char *host = self->data.host;
const char *plugin = self->data.plugin;
const char *plugin_instance = self->data.plugin_instance;
@@ -495,7 +493,7 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {"type", "values", "plugin_instance", "type_instance",
"plugin", "host", "time", "interval", "meta", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
NULL, &plugin, NULL, &host, &time, &interval, &meta))
return NULL;
@@ -559,8 +557,8 @@ static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
value_list.values = value;
value_list.meta = cpy_build_meta(meta);
value_list.values_len = size;
- value_list.time = time;
- value_list.interval = interval;
+ value_list.time = DOUBLE_TO_CDTIME_T(time);
+ value_list.interval = DOUBLE_TO_CDTIME_T(interval);
sstrncpy(value_list.host, host, sizeof(value_list.host));
sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
value_t *value;
value_list_t value_list = VALUE_LIST_INIT;
PyObject *values = self->values, *meta = self->meta;
- double time = self->data.time;
- int interval = self->interval;
+ double time = self->data.time, interval = self->interval;
const char *host = self->data.host;
const char *plugin = self->data.plugin;
const char *plugin_instance = self->data.plugin_instance;
static char *kwlist[] = {"destination", "type", "values", "plugin_instance", "type_instance",
"plugin", "host", "time", "interval", "meta", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetdiO", kwlist,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etOetetetetddO", kwlist,
NULL, &type, &values, NULL, &plugin_instance, NULL, &type_instance,
NULL, &plugin, NULL, &host, &time, &interval, &meta))
return NULL;
}
value_list.values = value;
value_list.values_len = size;
- value_list.time = time;
- value_list.interval = interval;
+ value_list.time = DOUBLE_TO_CDTIME_T(time);
+ value_list.interval = DOUBLE_TO_CDTIME_T(interval);
sstrncpy(value_list.host, host, sizeof(value_list.host));
sstrncpy(value_list.plugin, plugin, sizeof(value_list.plugin));
sstrncpy(value_list.plugin_instance, plugin_instance, sizeof(value_list.plugin_instance));
ret = cpy_common_repr(s);
if (self->interval != 0) {
CPY_STRCAT(&ret, l_interval);
- tmp = PyInt_FromLong(self->interval);
+ tmp = PyFloat_FromDouble(self->interval);
CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
CPY_STRCAT_AND_DEL(&ret, tmp);
}
@@ -864,7 +861,7 @@ static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObj
return NULL;
}
- notification.time = t;
+ notification.time = DOUBLE_TO_CDTIME_T(t);
notification.severity = severity;
sstrncpy(notification.message, message, sizeof(notification.message));
sstrncpy(notification.host, host, sizeof(notification.host));
@@ -873,8 +870,8 @@ static PyObject *Notification_dispatch(Notification *self, PyObject *args, PyObj
sstrncpy(notification.type, type, sizeof(notification.type));
sstrncpy(notification.type_instance, type_instance, sizeof(notification.type_instance));
notification.meta = NULL;
- if (notification.time < 1)
- notification.time = time(0);
+ if (notification.time == 0)
+ notification.time = cdtime();
if (notification.host[0] == 0)
sstrncpy(notification.host, hostname_g, sizeof(notification.host));
if (notification.plugin[0] == 0)
diff --git a/src/redis.c b/src/redis.c
--- /dev/null
+++ b/src/redis.c
@@ -0,0 +1,311 @@
+/**
+ * collectd - src/redis.c, based on src/memcached.c
+ * Copyright (C) 2010 Andrés J. Díaz <ajdiaz@connectical.com>
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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:
+ * Andrés J. Díaz <ajdiaz@connectical.com>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <pthread.h>
+#include <credis.h>
+
+#define REDIS_DEF_HOST "localhost"
+#define REDIS_DEF_PORT 6379
+#define REDIS_DEF_TIMEOUT 2000
+#define MAX_REDIS_NODE_NAME 64
+
+/* Redis plugin configuration example:
+ *
+ * <Plugin redis>
+ * <Node "mynode">
+ * Host "localhost"
+ * Port "6379"
+ * Timeout 2000
+ * </Node>
+ * </Plugin>
+ */
+
+struct redis_node_s;
+typedef struct redis_node_s redis_node_t;
+struct redis_node_s
+{
+ char name[MAX_REDIS_NODE_NAME];
+ char host[HOST_NAME_MAX];
+ int port;
+ int timeout;
+
+ redis_node_t *next;
+};
+
+static redis_node_t *nodes_head = NULL;
+
+static int redis_node_add (const redis_node_t *rn) /* {{{ */
+{
+ redis_node_t *rn_copy;
+ redis_node_t *rn_ptr;
+
+ /* Check for duplicates first */
+ for (rn_ptr = nodes_head; rn_ptr != NULL; rn_ptr = rn_ptr->next)
+ if (strcmp (rn->name, rn_ptr->name) == 0)
+ break;
+
+ if (rn_ptr != NULL)
+ {
+ ERROR ("redis plugin: A node with the name `%s' already exists.",
+ rn->name);
+ return (-1);
+ }
+
+ rn_copy = malloc (sizeof (*rn_copy));
+ if (rn_copy == NULL)
+ {
+ ERROR ("redis plugin: malloc failed adding redis_node to the tree.");
+ return (-1);
+ }
+
+ memcpy (rn_copy, rn, sizeof (*rn_copy));
+ rn_copy->next = NULL;
+
+ DEBUG ("redis plugin: Adding node \"%s\".", rn->name);
+
+ if (nodes_head == NULL)
+ nodes_head = rn_copy;
+ else
+ {
+ rn_ptr = nodes_head;
+ while (rn_ptr->next != NULL)
+ rn_ptr = rn_ptr->next;
+ rn_ptr->next = rn_copy;
+ }
+
+ return (0);
+} /* }}} */
+
+static int redis_config_node (oconfig_item_t *ci) /* {{{ */
+{
+ redis_node_t rn;
+ int i;
+ int status;
+
+ memset (&rn, 0, sizeof (rn));
+ sstrncpy (rn.host, REDIS_DEF_HOST, sizeof (rn.host));
+ rn.port = REDIS_DEF_PORT;
+ rn.timeout = REDIS_DEF_TIMEOUT;
+
+ status = cf_util_get_string_buffer (ci, rn.name, sizeof (rn.name));
+ if (status != 0)
+ return (status);
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+
+ if (strcasecmp ("Host", option->key) == 0)
+ status = cf_util_get_string_buffer (option, rn.host, sizeof (rn.host));
+ else if (strcasecmp ("Port", option->key) == 0)
+ {
+ status = cf_util_get_port_number (option);
+ if (status > 0)
+ {
+ rn.port = status;
+ status = 0;
+ }
+ }
+ else if (strcasecmp ("Timeout", option->key) == 0)
+ status = cf_util_get_int (option, &rn.timeout);
+ else
+ WARNING ("redis plugin: Option `%s' not allowed inside a `Node' "
+ "block. I'll ignore this option.", option->key);
+
+ if (status != 0)
+ break;
+ }
+
+ if (status != 0)
+ return (status);
+
+ return (redis_node_add (&rn));
+} /* }}} int redis_config_node */
+
+static int redis_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+
+ if (strcasecmp ("Node", option->key) == 0)
+ redis_config_node (option);
+ else
+ WARNING ("redis plugin: Option `%s' not allowed in redis"
+ " configuration. It will be ignored.", option->key);
+ }
+
+ if (nodes_head == NULL)
+ {
+ ERROR ("redis plugin: No valid node configuration could be found.");
+ return (ENOENT);
+ }
+
+ return (0);
+} /* }}} */
+
+ __attribute__ ((nonnull(2)))
+static void redis_submit_g (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, "redis", 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);
+} /* }}} */
+
+ __attribute__ ((nonnull(2)))
+static void redis_submit_c (char *plugin_instance,
+ const char *type, const char *type_instance,
+ counter_t value) /* {{{ */
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].counter = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "redis", 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);
+} /* }}} */
+
+static int redis_init (void) /* {{{ */
+{
+ redis_node_t rn = { "default", REDIS_DEF_HOST, REDIS_DEF_PORT,
+ REDIS_DEF_TIMEOUT, /* next = */ NULL };
+
+ if (nodes_head == NULL)
+ redis_node_add (&rn);
+
+ return (0);
+} /* }}} int redis_init */
+
+static int redis_read (void) /* {{{ */
+{
+ redis_node_t *rn;
+
+ for (rn = nodes_head; rn != NULL; rn = rn->next)
+ {
+ REDIS rh;
+ REDIS_INFO info;
+
+ int status;
+
+ DEBUG ("redis plugin: querying info from node `%s' (%s:%d).", rn->name, rn->host, rn->port);
+
+ rh = credis_connect (rn->host, rn->port, rn->timeout);
+ if (rh == NULL)
+ {
+ ERROR ("redis plugin: unable to connect to node `%s' (%s:%d).", rn->name, rn->host, rn->port);
+ continue;
+ }
+
+ memset (&info, 0, sizeof (info));
+ status = credis_info (rh, &info);
+ if (status != 0)
+ {
+ WARNING ("redis plugin: unable to get info from node `%s'.", rn->name);
+ credis_close (rh);
+ continue;
+ }
+
+ /* typedef struct _cr_info {
+ * char redis_version[CREDIS_VERSION_STRING_SIZE];
+ * int bgsave_in_progress;
+ * int connected_clients;
+ * int connected_slaves;
+ * unsigned int used_memory;
+ * long long changes_since_last_save;
+ * int last_save_time;
+ * long long total_connections_received;
+ * long long total_commands_processed;
+ * int uptime_in_seconds;
+ * int uptime_in_days;
+ * int role;
+ * } REDIS_INFO; */
+
+ DEBUG ("redis plugin: received info from node `%s': connected_clients = %d; "
+ "connected_slaves = %d; used_memory = %lu; changes_since_last_save = %lld; "
+ "bgsave_in_progress = %d; total_connections_received = %lld; "
+ "total_commands_processed = %lld; uptime_in_seconds = %ld", rn->name,
+ info.connected_clients, info.connected_slaves, info.used_memory,
+ info.changes_since_last_save, info.bgsave_in_progress,
+ info.total_connections_received, info.total_commands_processed,
+ info.uptime_in_seconds);
+
+ redis_submit_g (rn->name, "current_connections", "clients", info.connected_clients);
+ redis_submit_g (rn->name, "current_connections", "slaves", info.connected_slaves);
+ redis_submit_g (rn->name, "memory", "used", info.used_memory);
+ redis_submit_g (rn->name, "volatile_changes", NULL, info.changes_since_last_save);
+ redis_submit_c (rn->name, "total_connections", NULL, info.total_connections_received);
+ redis_submit_c (rn->name, "total_operations", NULL, info.total_commands_processed);
+
+ credis_close (rh);
+ }
+
+ return 0;
+}
+/* }}} */
+
+void module_register (void) /* {{{ */
+{
+ plugin_register_complex_config ("redis", redis_config);
+ plugin_register_init ("redis", redis_init);
+ plugin_register_read ("redis", redis_read);
+ /* TODO: plugin_register_write: one redis list per value id with
+ * X elements */
+}
+/* }}} */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/rrdcached.c b/src/rrdcached.c
index 34e860ba6dc72ccff994e7dc999ca79682292c63..fb7eb79e8ec50eca5ab5d9273ff349d9fb5dd4cf 100644 (file)
--- a/src/rrdcached.c
+++ b/src/rrdcached.c
int offset;
int status;
int i;
+ time_t t;
assert (0 == strcmp (ds->type, vl->type));
memset (buffer, '\0', buffer_len);
- status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ t = CDTIME_T_TO_TIME_T (vl->time);
+ status = ssnprintf (buffer, buffer_len, "%lu", (unsigned long) t);
if ((status < 1) || (status >= buffer_len))
return (-1);
offset = status;
diff --git a/src/rrdtool.c b/src/rrdtool.c
index 4655b96ee77c79a74dca16f9f412bd2df55d3cd7..b366a9c64166eeeae135f700b069e81578cac28a 100644 (file)
--- a/src/rrdtool.c
+++ b/src/rrdtool.c
*/
struct rrd_cache_s
{
- int values_num;
- char **values;
- time_t first_value;
- time_t last_value;
- int random_variation;
+ int values_num;
+ char **values;
+ cdtime_t first_value;
+ cdtime_t last_value;
+ int64_t random_variation;
enum
{
FLAG_NONE = 0x00,
/* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
* ALWAYS lock `cache_lock' first! */
-static int cache_timeout = 0;
-static int cache_flush_timeout = 0;
-static int random_timeout = 1;
-static time_t cache_flush_last;
+static cdtime_t cache_timeout = 0;
+static cdtime_t cache_flush_timeout = 0;
+static cdtime_t random_timeout = TIME_T_TO_CDTIME_T (1);
+static cdtime_t cache_flush_last;
static c_avl_tree_t *cache = NULL;
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
{
int offset;
int status;
+ time_t tt;
int i;
memset (buffer, '\0', buffer_len);
- status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ tt = CDTIME_T_TO_TIME_T (vl->time);
+ status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) tt);
if ((status < 1) || (status >= buffer_len))
return (-1);
offset = status;
pthread_mutex_lock (&queue_lock);
/* Wait for values to arrive */
- while (true)
+ while (42)
{
struct timespec ts_wait;
&ts_wait);
if (status == ETIMEDOUT)
break;
- } /* while (true) */
+ } /* while (42) */
/* XXX: If you need to lock both, cache_lock and queue_lock, at
* the same time, ALWAYS lock `cache_lock' first! */
return (0);
} /* int rrd_queue_dequeue */
-static void rrd_cache_flush (int timeout)
+/* XXX: You must hold "cache_lock" when calling this function! */
+static void rrd_cache_flush (cdtime_t timeout)
{
rrd_cache_t *rc;
- time_t now;
+ cdtime_t now;
char **keys = NULL;
int keys_num = 0;
c_avl_iterator_t *iter;
int i;
- DEBUG ("rrdtool plugin: Flushing cache, timeout = %i", timeout);
+ DEBUG ("rrdtool plugin: Flushing cache, timeout = %.3f",
+ CDTIME_T_TO_DOUBLE (timeout));
- now = time (NULL);
+ now = cdtime ();
+ timeout = TIME_T_TO_CDTIME_T (timeout);
/* Build a list of entries to be flushed */
iter = c_avl_get_iterator (cache);
{
if (rc->flags != FLAG_NONE)
continue;
- else if ((now - rc->first_value) < timeout)
+ /* timeout == 0 => flush everything */
+ else if ((timeout != 0)
+ && ((now - rc->first_value) < timeout))
continue;
else if (rc->values_num > 0)
{
cache_flush_last = now;
} /* void rrd_cache_flush */
-static int rrd_cache_flush_identifier (int timeout, const char *identifier)
+static int rrd_cache_flush_identifier (cdtime_t timeout,
+ const char *identifier)
{
rrd_cache_t *rc;
- time_t now;
+ cdtime_t now;
int status;
char key[2048];
return (0);
}
- now = time (NULL);
+ now = cdtime ();
if (datadir == NULL)
snprintf (key, sizeof (key), "%s.rrd",
return (status);
} /* int rrd_cache_flush_identifier */
+static int64_t rrd_get_random_variation (void)
+{
+ double dbl_timeout;
+ cdtime_t ctm_timeout;
+ double rand_fact;
+ _Bool negative;
+ int64_t ret;
+
+ if (random_timeout <= 0)
+ return (0);
+
+ /* Assure that "cache_timeout + random_variation" is never negative. */
+ if (random_timeout > cache_timeout)
+ {
+ INFO ("rrdtool plugin: Adjusting \"RandomTimeout\" to %.3f seconds.",
+ CDTIME_T_TO_DOUBLE (cache_timeout));
+ random_timeout = cache_timeout;
+ }
+
+ /* This seems a bit complicated, but "random_timeout" is likely larger than
+ * RAND_MAX, so we can't simply use modulo here. */
+ dbl_timeout = CDTIME_T_TO_DOUBLE (random_timeout);
+ rand_fact = ((double) random ())
+ / ((double) RAND_MAX);
+ negative = (_Bool) (random () % 2);
+
+ ctm_timeout = DOUBLE_TO_CDTIME_T (dbl_timeout * rand_fact);
+
+ ret = (int64_t) ctm_timeout;
+ if (negative)
+ ret *= -1;
+
+ return (ret);
+} /* int64_t rrd_get_random_variation */
+
static int rrd_cache_insert (const char *filename,
- const char *value, time_t value_time)
+ const char *value, cdtime_t value_time)
{
rrd_cache_t *rc = NULL;
int new_rc = 0;
if (rc == NULL)
{
- rc = (rrd_cache_t *) malloc (sizeof (rrd_cache_t));
+ rc = malloc (sizeof (*rc));
if (rc == NULL)
return (-1);
rc->values_num = 0;
rc->values = NULL;
rc->first_value = 0;
rc->last_value = 0;
- rc->random_variation = 0;
+ rc->random_variation = rrd_get_random_variation ();
rc->flags = FLAG_NONE;
new_rc = 1;
}
if (rc->last_value >= value_time)
{
pthread_mutex_unlock (&cache_lock);
- DEBUG ("rrdtool plugin: (rc->last_value = %u) >= (value_time = %u)",
- (unsigned int) rc->last_value,
- (unsigned int) value_time);
+ DEBUG ("rrdtool plugin: (rc->last_value = %"PRIu64") "
+ ">= (value_time = %"PRIu64")",
+ rc->last_value, value_time);
return (-1);
}
}
DEBUG ("rrdtool plugin: rrd_cache_insert: file = %s; "
- "values_num = %i; age = %lu;",
+ "values_num = %i; age = %.3f;",
filename, rc->values_num,
- (unsigned long)(rc->last_value - rc->first_value));
+ CDTIME_T_TO_DOUBLE (rc->last_value - rc->first_value));
- if ((rc->last_value + rc->random_variation - rc->first_value) >= cache_timeout)
+ if ((rc->last_value - rc->first_value) >= (cache_timeout + rc->random_variation))
{
/* XXX: If you need to lock both, cache_lock and queue_lock, at
* the same time, ALWAYS lock `cache_lock' first! */
if (status == 0)
rc->flags = FLAG_QUEUED;
- /* Update the jitter value. Negative values are
- * slightly preferred. */
- if (random_timeout > 0)
- {
- rc->random_variation = (rand () % (2 * random_timeout))
- - random_timeout;
- }
- else
- {
- rc->random_variation = 0;
- }
+ rc->random_variation = rrd_get_random_variation ();
}
else
{
}
if ((cache_timeout > 0) &&
- ((time (NULL) - cache_flush_last) > cache_flush_timeout))
+ ((cdtime () - cache_flush_last) > cache_flush_timeout))
rrd_cache_flush (cache_flush_timeout);
pthread_mutex_unlock (&cache_lock);
return (status);
} /* int rrd_write */
-static int rrd_flush (int timeout, const char *identifier,
- user_data_t __attribute__((unused)) *user_data)
+static int rrd_flush (cdtime_t timeout, const char *identifier,
+ __attribute__((unused)) user_data_t *user_data)
{
pthread_mutex_lock (&cache_lock);
{
if (strcasecmp ("CacheTimeout", key) == 0)
{
- int tmp = atoi (value);
+ double tmp = atof (value);
if (tmp < 0)
{
fprintf (stderr, "rrdtool: `CacheTimeout' must "
"be greater than 0.\n");
return (1);
}
- cache_timeout = tmp;
+ cache_timeout = DOUBLE_TO_CDTIME_T (tmp);
}
else if (strcasecmp ("CacheFlush", key) == 0)
{
}
else if (strcasecmp ("RandomTimeout", key) == 0)
{
- int tmp;
+ double tmp;
- tmp = atoi (value);
- if (tmp < 0)
+ tmp = atof (value);
+ if (tmp < 0.0)
{
fprintf (stderr, "rrdtool: `RandomTimeout' must "
"be greater than or equal to zero.\n");
}
else
{
- random_timeout = tmp;
+ random_timeout = DOUBLE_TO_CDTIME_T (tmp);
}
}
else
static int rrd_shutdown (void)
{
pthread_mutex_lock (&cache_lock);
- rrd_cache_flush (-1);
+ rrd_cache_flush (0);
pthread_mutex_unlock (&cache_lock);
pthread_mutex_lock (&queue_lock);
rrdcreate_config.heartbeat = 2 * rrdcreate_config.stepsize;
if ((rrdcreate_config.heartbeat > 0)
- && (rrdcreate_config.heartbeat < interval_g))
+ && (rrdcreate_config.heartbeat < CDTIME_T_TO_TIME_T (interval_g)))
WARNING ("rrdtool plugin: Your `heartbeat' is "
"smaller than your `interval'. This will "
"likely cause problems.");
else if ((rrdcreate_config.stepsize > 0)
- && (rrdcreate_config.stepsize < interval_g))
+ && (rrdcreate_config.stepsize < CDTIME_T_TO_TIME_T (interval_g)))
WARNING ("rrdtool plugin: Your `stepsize' is "
"smaller than your `interval'. This will "
"create needlessly big RRD-files.");
return (-1);
}
- cache_flush_last = time (NULL);
- if (cache_timeout < 2)
+ cache_flush_last = cdtime ();
+ if (cache_timeout == 0)
{
- cache_timeout = 0;
cache_flush_timeout = 0;
}
else if (cache_flush_timeout < cache_timeout)
diff --git a/src/snmp.c b/src/snmp.c
index 1c2828c1fb2469494e84aafebb6a77d01fadcde9..54bcf67242170ea93c6cdc070a5a81a8196ed067 100644 (file)
--- a/src/snmp.c
+++ b/src/snmp.c
int version;
void *sess_handle;
c_complain_t complaint;
- uint32_t interval;
+ cdtime_t interval;
data_definition_t **data_list;
int data_list_len;
};
* +-> csnmp_config_add_host_community
* +-> csnmp_config_add_host_version
* +-> csnmp_config_add_host_collect
- * +-> csnmp_config_add_host_interval
*/
static void call_snmp_init_once (void)
{
return (0);
} /* int csnmp_config_add_host_collect */
-static int csnmp_config_add_host_interval (host_definition_t *hd, oconfig_item_t *ci)
-{
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
- {
- WARNING ("snmp plugin: The `Interval' config option needs exactly one number argument.");
- return (-1);
- }
-
- hd->interval = ci->values[0].value.number >= 0
- ? (uint32_t) ci->values[0].value.number
- : 0;
-
- return (0);
-} /* int csnmp_config_add_host_interval */
-
static int csnmp_config_add_host (oconfig_item_t *ci)
{
host_definition_t *hd;
else if (strcasecmp ("Collect", option->key) == 0)
csnmp_config_add_host_collect (hd, option);
else if (strcasecmp ("Interval", option->key) == 0)
- csnmp_config_add_host_interval (hd, option);
+ cf_util_get_cdtime (option, &hd->interval);
else
{
WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
cb_data.data = hd;
cb_data.free_func = csnmp_host_definition_destroy;
- memset (&cb_interval, 0, sizeof (cb_interval));
- if (hd->interval != 0)
- cb_interval.tv_sec = (time_t) hd->interval;
+ CDTIME_T_TO_TIMESPEC (hd->interval, &cb_interval);
status = plugin_register_complex_read (/* group = */ NULL, cb_name,
csnmp_read_host, /* interval = */ &cb_interval,
@@ -1529,8 +1510,8 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
static int csnmp_read_host (user_data_t *ud)
{
host_definition_t *host;
- time_t time_start;
- time_t time_end;
+ cdtime_t time_start;
+ cdtime_t time_end;
int status;
int success;
int i;
if (host->interval == 0)
host->interval = interval_g;
- time_start = time (NULL);
- DEBUG ("snmp plugin: csnmp_read_host (%s) started at %u;", host->name,
- (unsigned int) time_start);
+ time_start = cdtime ();
if (host->sess_handle == NULL)
csnmp_host_open_session (host);
success++;
}
- time_end = time (NULL);
- DEBUG ("snmp plugin: csnmp_read_host (%s) finished at %u;", host->name,
- (unsigned int) time_end);
- if ((uint32_t) (time_end - time_start) > host->interval)
+ time_end = cdtime ();
+ if ((time_end - time_start) > host->interval)
{
- WARNING ("snmp plugin: Host `%s' should be queried every %"PRIu32
- " seconds, but reading all values takes %u seconds.",
- host->name, host->interval, (unsigned int) (time_end - time_start));
+ WARNING ("snmp plugin: Host `%s' should be queried every %.3f "
+ "seconds, but reading all values takes %.3f seconds.",
+ host->name,
+ CDTIME_T_TO_DOUBLE (host->interval),
+ CDTIME_T_TO_DOUBLE (time_end - time_start));
}
if (success == 0)
diff --git a/src/swap.c b/src/swap.c
index 46ba6652953726ce0b7d90aecea2345f681ec64b..2025533eae298ee59048913eb4f69e2b466ad5ab 100644 (file)
--- a/src/swap.c
+++ b/src/swap.c
static kstat_t *ksp;
/* #endif HAVE_LIBKSTAT */
-#elif HAVE_SWAPCTL
-/* No global variables */
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
+static derive_t pagesize;
/* #endif HAVE_SWAPCTL */
#elif defined(VM_SWAPUSAGE)
ksp = NULL;
/* #endif HAVE_LIBKSTAT */
-#elif HAVE_SWAPCTL
- /* No init stuff */
+#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
+ /* getpagesize(3C) tells me this does not fail.. */
+ pagesize = (derive_t) getpagesize ();
/* #endif HAVE_SWAPCTL */
#elif defined(VM_SWAPUSAGE)
/* #endif HAVE_LIBKSTAT */
#elif HAVE_SWAPCTL
+ #if HAVE_SWAPCTL_TWO_ARGS
+ swaptbl_t *s;
+ char strtab[255];
+ int swap_num;
+ int status;
+ int i;
+
+ derive_t avail = 0;
+ derive_t total = 0;
+
+ swap_num = swapctl (SC_GETNSWP, NULL);
+ if (swap_num < 0)
+ {
+ ERROR ("swap plugin: swapctl (SC_GETNSWP) failed with status %i.",
+ swap_num);
+ return (-1);
+ }
+ else if (swap_num == 0)
+ return (0);
+
+ s = (swaptbl_t *) smalloc (swap_num * sizeof (swapent_t) + sizeof (struct swaptable));
+ if (s == NULL)
+ {
+ ERROR ("swap plugin: smalloc failed.");
+ return (-1);
+ }
+ /* Initialize string pointers. We have them share the same buffer as we don't care
+ * about the device's name, only its size. This saves memory and alloc/free ops */
+ for (i = 0; i < (swap_num + 1); i++) {
+ s->swt_ent[i].ste_path = strtab;
+ }
+ s->swt_n = swap_num + 1;
+ status = swapctl (SC_LIST, s);
+ if (status != swap_num)
+ {
+ ERROR ("swap plugin: swapctl (SC_LIST) failed with status %i.",
+ status);
+ sfree (s);
+ return (-1);
+ }
+
+ for (i = 0; i < swap_num; i++)
+ {
+ if ((s->swt_ent[i].ste_flags & ST_INDEL) != 0)
+ continue;
+
+ avail += ((derive_t) s->swt_ent[i].ste_free)
+ * pagesize;
+ total += ((derive_t) s->swt_ent[i].ste_pages)
+ * pagesize;
+ }
+
+ if (total < avail)
+ {
+ ERROR ("swap plugin: Total swap space (%"PRIi64") "
+ "is less than free swap space (%"PRIi64").",
+ total, avail);
+ sfree (s);
+ return (-1);
+ }
+
+ swap_submit ("used", total - avail, DS_TYPE_GAUGE);
+ swap_submit ("free", avail, DS_TYPE_GAUGE);
+
+ sfree (s);
+ /* #endif HAVE_SWAPCTL_TWO_ARGS */
+ #elif HAVE_SWAPCTL_THREE_ARGS
+
struct swapent *swap_entries;
int swap_num;
int status;
derive_t used = 0;
derive_t total = 0;
- /*
- * XXX: This is the syntax for the *BSD `swapctl', which has the
- * following prototype:
- * swapctl (int cmd, void *arg, int misc);
- *
- * HP-UX and Solaris (and possibly other UNIXes) provide `swapctl',
- * too, but with the following prototype:
- * swapctl (int cmd, void *arg);
- *
- * Solaris is usually handled in the KSTAT case above. For other UNIXes
- * a separate case for the other version of `swapctl' may be necessary.
- */
swap_num = swapctl (SWAP_NSWAP, NULL, 0);
if (swap_num < 0)
{
swap_submit ("free", total - used, DS_TYPE_GAUGE);
sfree (swap_entries);
+ #endif /* HAVE_SWAPCTL_THREE_ARGS */
/* #endif HAVE_SWAPCTL */
#elif defined(VM_SWAPUSAGE)
index 96598afd76fd53500948e34dda8bf516726e4371..cb68048b6a8f7c042cdd37bbf7dc3c77a24bd754 100644 (file)
/* Initialize the structure. */
memset (&n, 0, sizeof (n));
n.severity = data->severity;
- n.time = time (NULL);
+ n.time = cdtime ();
sstrncpy (n.message, data->message, sizeof (n.message));
sstrncpy (n.host, vl->host, sizeof (n.host));
sstrncpy (n.plugin, vl->plugin, sizeof (n.plugin));
diff --git a/src/target_scale.c b/src/target_scale.c
index 29fecdfd7b5818479437659982226c993934a63d..af224f109d6bb8de19066b8c472a6557d6058d3e 100644 (file)
--- a/src/target_scale.c
+++ b/src/target_scale.c
{
difference = curr_counter - prev_counter;
}
- rate = ((double) difference) / ((double) vl->interval);
+ rate = ((double) difference) / CDTIME_T_TO_DOUBLE (vl->interval);
/* Modify the rate. */
if (!isnan (data->factor))
rate += data->offset;
/* Calculate the internal counter. */
- int_fraction += (rate * ((double) vl->interval));
+ int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
difference = (uint64_t) int_fraction;
int_fraction -= ((double) difference);
int_counter += difference;
/* Calcualte the rate */
difference = curr_derive - prev_derive;
- rate = ((double) difference) / ((double) vl->interval);
+ rate = ((double) difference) / CDTIME_T_TO_DOUBLE (vl->interval);
/* Modify the rate. */
if (!isnan (data->factor))
rate += data->offset;
/* Calculate the internal derive. */
- int_fraction += (rate * ((double) vl->interval));
+ int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
if (int_fraction < 0.0) /* handle negative integer rounding correctly */
difference = ((int64_t) int_fraction) - 1;
else
@@ -263,7 +263,7 @@ static int ts_invoke_absolute (const data_set_t *ds, value_list_t *vl, /* {{{ */
if (status != 0)
int_fraction = 0.0;
- rate = ((double) curr_absolute) / ((double) vl->interval);
+ rate = ((double) curr_absolute) / CDTIME_T_TO_DOUBLE (vl->interval);
/* Modify the rate. */
if (!isnan (data->factor))
@@ -272,7 +272,7 @@ static int ts_invoke_absolute (const data_set_t *ds, value_list_t *vl, /* {{{ */
rate += data->offset;
/* Calculate the new absolute. */
- int_fraction += (rate * ((double) vl->interval));
+ int_fraction += (rate * CDTIME_T_TO_DOUBLE (vl->interval));
curr_absolute = (uint64_t) int_fraction;
int_fraction -= ((double) curr_absolute);
diff --git a/src/target_v5upgrade.c b/src/target_v5upgrade.c
--- /dev/null
+++ b/src/target_v5upgrade.c
@@ -0,0 +1,472 @@
+/**
+ * collectd - src/target_set.c
+ * Copyright (C) 2008-2010 Florian Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; only version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "filter_chain.h"
+
+static void v5_swap_instances (value_list_t *vl) /* {{{ */
+{
+ char tmp[DATA_MAX_NAME_LEN];
+
+ assert (sizeof (tmp) == sizeof (vl->plugin_instance));
+ assert (sizeof (tmp) == sizeof (vl->type_instance));
+
+ memcpy (tmp, vl->plugin_instance, sizeof (tmp));
+ memcpy (vl->plugin_instance, vl->type_instance, sizeof (tmp));
+ memcpy (vl->type_instance, tmp, sizeof (tmp));
+} /* }}} void v5_swap_instances */
+
+/*
+ * Df type
+ *
+ * By default, the "df" plugin of version 4.* uses the "df" type and puts the
+ * mount point in the type instance. Detect this behavior and convert the type
+ * to "df_complex". This can be selected in versions 4.9 and 4.10 by setting
+ * the "ReportReserved" option of the "df" plugin.
+ */
+static int v5_df (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_value;
+
+ /* Can't upgrade if both instances have been set. */
+ if ((vl->plugin_instance[0] != 0)
+ && (vl->type_instance[0] != 0))
+ return (FC_TARGET_CONTINUE);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &new_value;
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Move the mount point name to the plugin instance */
+ if (new_vl.plugin_instance[0] == 0)
+ v5_swap_instances (&new_vl);
+
+ /* Change the type to "df_complex" */
+ sstrncpy (new_vl.type, "df_complex", sizeof (new_vl.type));
+
+ /* Dispatch two new value lists instead of this one */
+ new_vl.values[0].gauge = vl->values[0].gauge;
+ sstrncpy (new_vl.type_instance, "used", sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].gauge = vl->values[1].gauge;
+ sstrncpy (new_vl.type_instance, "free", sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_df */
+
+/*
+ * Interface plugin
+ *
+ * 4.* stores the interface in the type instance and leaves the plugin
+ * instance empty. If this is the case, put the interface name into the plugin
+ * instance and clear the type instance.
+ */
+static int v5_interface (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ if ((vl->plugin_instance[0] != 0) || (vl->type_instance[0] == 0))
+ return (FC_TARGET_CONTINUE);
+
+ v5_swap_instances (vl);
+ return (FC_TARGET_CONTINUE);
+} /* }}} int v5_interface */
+
+/*
+ * MySQL query cache
+ *
+ * 4.* uses the "mysql_qcache" type which mixes different types of
+ * information. In 5.* this has been broken up.
+ */
+static int v5_mysql_qcache (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_value;
+
+ if (vl->values_len != 5)
+ return (FC_TARGET_STOP);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &new_value;
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Change the type to "cache_result" */
+ sstrncpy (new_vl.type, "cache_result", sizeof (new_vl.type));
+
+ /* Dispatch new value lists instead of this one */
+ new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+ sstrncpy (new_vl.type_instance, "qcache-hits",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].derive = (derive_t) vl->values[1].counter;
+ sstrncpy (new_vl.type_instance, "qcache-inserts",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].derive = (derive_t) vl->values[2].counter;
+ sstrncpy (new_vl.type_instance, "qcache-not_cached",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].derive = (derive_t) vl->values[3].counter;
+ sstrncpy (new_vl.type_instance, "qcache-prunes",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ /* The last data source is a gauge value, so we have to use a different type
+ * here. */
+ new_vl.values[0].gauge = vl->values[4].gauge;
+ sstrncpy (new_vl.type, "cache_size", sizeof (new_vl.type));
+ sstrncpy (new_vl.type_instance, "qcache",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_mysql_qcache */
+
+/*
+ * MySQL thread count
+ *
+ * 4.* uses the "mysql_threads" type which mixes different types of
+ * information. In 5.* this has been broken up.
+ */
+static int v5_mysql_threads (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_value;
+
+ if (vl->values_len != 4)
+ return (FC_TARGET_STOP);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &new_value;
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Change the type to "threads" */
+ sstrncpy (new_vl.type, "threads", sizeof (new_vl.type));
+
+ /* Dispatch new value lists instead of this one */
+ new_vl.values[0].gauge = vl->values[0].gauge;
+ sstrncpy (new_vl.type_instance, "running",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].gauge = vl->values[1].gauge;
+ sstrncpy (new_vl.type_instance, "connected",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].gauge = vl->values[2].gauge;
+ sstrncpy (new_vl.type_instance, "cached",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ /* The last data source is a counter value, so we have to use a different
+ * type here. */
+ new_vl.values[0].derive = (derive_t) vl->values[3].counter;
+ sstrncpy (new_vl.type, "total_threads", sizeof (new_vl.type));
+ sstrncpy (new_vl.type_instance, "created",
+ sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_mysql_threads */
+
+/*
+ * ZFS ARC hit and miss counters
+ *
+ * 4.* uses the flawed "arc_counts" type. In 5.* this has been replaced by the
+ * more generic "cache_result" type.
+ */
+static int v5_zfs_arc_counts (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_value;
+ _Bool is_hits;
+
+ if (vl->values_len != 4)
+ return (FC_TARGET_STOP);
+
+ if (strcmp ("hits", vl->type_instance) == 0)
+ is_hits = 1;
+ else if (strcmp ("misses", vl->type_instance) == 0)
+ is_hits = 0;
+ else
+ return (FC_TARGET_STOP);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &new_value;
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Change the type to "cache_result" */
+ sstrncpy (new_vl.type, "cache_result", sizeof (new_vl.type));
+
+ /* Dispatch new value lists instead of this one */
+ new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+ ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+ "demand_data-%s",
+ is_hits ? "hit" : "miss");
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].derive = (derive_t) vl->values[1].counter;
+ ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+ "demand_metadata-%s",
+ is_hits ? "hit" : "miss");
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].derive = (derive_t) vl->values[2].counter;
+ ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+ "prefetch_data-%s",
+ is_hits ? "hit" : "miss");
+ plugin_dispatch_values (&new_vl);
+
+ new_vl.values[0].derive = (derive_t) vl->values[3].counter;
+ ssnprintf (new_vl.type_instance, sizeof (new_vl.type_instance),
+ "prefetch_metadata-%s",
+ is_hits ? "hit" : "miss");
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_counts */
+
+/*
+ * ZFS ARC L2 bytes
+ *
+ * "arc_l2_bytes" -> "io_octets-L2".
+ */
+static int v5_zfs_arc_l2_bytes (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_values[2];
+
+ if (vl->values_len != 2)
+ return (FC_TARGET_STOP);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = new_values;
+ new_vl.values_len = 2;
+ new_vl.meta = NULL;
+
+ /* Change the type/-instance to "io_octets-L2" */
+ sstrncpy (new_vl.type, "io_octets", sizeof (new_vl.type));
+ sstrncpy (new_vl.type_instance, "L2", sizeof (new_vl.type_instance));
+
+ /* Copy the actual values. */
+ new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+ new_vl.values[1].derive = (derive_t) vl->values[1].counter;
+
+ /* Dispatch new value lists instead of this one */
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_l2_bytes */
+
+/*
+ * ZFS ARC L2 cache size
+ *
+ * 4.* uses a separate type for this. 5.* uses the generic "cache_size" type
+ * instead.
+ */
+static int v5_zfs_arc_l2_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_value;
+
+ if (vl->values_len != 1)
+ return (FC_TARGET_STOP);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &new_value;
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ new_vl.values[0].gauge = (gauge_t) vl->values[0].gauge;
+
+ /* Change the type to "cache_size" */
+ sstrncpy (new_vl.type, "cache_size", sizeof (new_vl.type));
+
+ /* Adapt the type instance */
+ sstrncpy (new_vl.type_instance, "L2", sizeof (new_vl.type_instance));
+
+ /* Dispatch new value lists instead of this one */
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_l2_size */
+
+/*
+ * ZFS ARC ratio
+ *
+ * "arc_ratio-L1" -> "cache_ratio-arc"
+ * "arc_ratio-L2" -> "cache_ratio-L2"
+ */
+static int v5_zfs_arc_ratio (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_value;
+
+ if (vl->values_len != 1)
+ return (FC_TARGET_STOP);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &new_value;
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ new_vl.values[0].gauge = (gauge_t) vl->values[0].gauge;
+
+ /* Change the type to "cache_ratio" */
+ sstrncpy (new_vl.type, "cache_ratio", sizeof (new_vl.type));
+
+ /* Adapt the type instance */
+ if (strcmp ("L1", vl->type_instance) == 0)
+ sstrncpy (new_vl.type_instance, "arc", sizeof (new_vl.type_instance));
+
+ /* Dispatch new value lists instead of this one */
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_ratio */
+
+/*
+ * ZFS ARC size
+ *
+ * 4.* uses the "arc_size" type with four data sources. In 5.* this has been
+ * replaces with the "cache_size" type and static data has been removed.
+ */
+static int v5_zfs_arc_size (const data_set_t *ds, value_list_t *vl) /* {{{ */
+{
+ value_list_t new_vl;
+ value_t new_value;
+
+ if (vl->values_len != 4)
+ return (FC_TARGET_STOP);
+
+ /* Copy everything: Time, interval, host, ... */
+ memcpy (&new_vl, vl, sizeof (new_vl));
+
+ /* Reset data we can't simply copy */
+ new_vl.values = &new_value;
+ new_vl.values_len = 1;
+ new_vl.meta = NULL;
+
+ /* Change the type to "cache_size" */
+ sstrncpy (new_vl.type, "cache_size", sizeof (new_vl.type));
+
+ /* Dispatch new value lists instead of this one */
+ new_vl.values[0].derive = (derive_t) vl->values[0].counter;
+ sstrncpy (new_vl.type_instance, "arc", sizeof (new_vl.type_instance));
+ plugin_dispatch_values (&new_vl);
+
+ /* Abort processing */
+ return (FC_TARGET_STOP);
+} /* }}} int v5_zfs_arc_size */
+
+static int v5_destroy (void **user_data) /* {{{ */
+{
+ return (0);
+} /* }}} int v5_destroy */
+
+static int v5_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+{
+ *user_data = NULL;
+ return (0);
+} /* }}} int v5_create */
+
+static int v5_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */
+ notification_meta_t __attribute__((unused)) **meta,
+ void __attribute__((unused)) **user_data)
+{
+ if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
+ return (-EINVAL);
+
+ if (strcmp ("df", vl->type) == 0)
+ return (v5_df (ds, vl));
+ else if (strcmp ("interface", vl->plugin) == 0)
+ return (v5_interface (ds, vl));
+ else if (strcmp ("mysql_qcache", vl->type) == 0)
+ return (v5_mysql_qcache (ds, vl));
+ else if (strcmp ("mysql_threads", vl->type) == 0)
+ return (v5_mysql_threads (ds, vl));
+ else if (strcmp ("arc_counts", vl->type) == 0)
+ return (v5_zfs_arc_counts (ds, vl));
+ else if (strcmp ("arc_l2_bytes", vl->type) == 0)
+ return (v5_zfs_arc_l2_bytes (ds, vl));
+ else if (strcmp ("arc_l2_size", vl->type) == 0)
+ return (v5_zfs_arc_l2_size (ds, vl));
+ else if (strcmp ("arc_ratio", vl->type) == 0)
+ return (v5_zfs_arc_ratio (ds, vl));
+ else if (strcmp ("arc_size", vl->type) == 0)
+ return (v5_zfs_arc_size (ds, vl));
+
+ return (FC_TARGET_CONTINUE);
+} /* }}} int v5_invoke */
+
+void module_register (void)
+{
+ target_proc_t tproc;
+
+ memset (&tproc, 0, sizeof (tproc));
+ tproc.create = v5_create;
+ tproc.destroy = v5_destroy;
+ tproc.invoke = v5_invoke;
+ fc_register_target ("v5upgrade", tproc);
+} /* module_register */
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
+
diff --git a/src/ted.c b/src/ted.c
index 8dc00e5a161ad928883b086d100a451e48d1db6f..bf519bbee53ec38c34ddae669c707523e2fbf617 100644 (file)
--- a/src/ted.c
+++ b/src/ted.c
values[0].gauge = value;
- vl.time = time (NULL);
vl.values = values;
vl.values_len = 1;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
diff --git a/src/thermal.c b/src/thermal.c
index b9d07bf5ce22fcacd55f5dcac729e4ad665b12d5..0ad0d90a04377126132e35cad77e4d592a844a1d 100644 (file)
--- a/src/thermal.c
+++ b/src/thermal.c
# error "This module is for Linux only."
#endif
+static const char *config_keys[] = {
+ "Device",
+ "IgnoreSelected",
+ "ForceUseProcfs"
+};
+
const char *const dirname_sysfs = "/sys/class/thermal";
const char *const dirname_procfs = "/proc/acpi/thermal_zone";
-static char force_procfs = 0;
+static _Bool force_procfs = 0;
static ignorelist_t *device_list;
-static value_list_t vl_temp_template = VALUE_LIST_STATIC;
-static value_list_t vl_state_template = VALUE_LIST_STATIC;
enum dev_type {
TEMP = 0,
static void thermal_submit (const char *plugin_instance, enum dev_type dt,
gauge_t value)
{
- value_list_t vl = (dt == TEMP) ? vl_temp_template : vl_state_template;
- value_t vt;
+ value_list_t vl = VALUE_LIST_INIT;
+ value_t v;
- vt.gauge = value;
+ v.gauge = value;
+ vl.values = &v;
- vl.values = &vt;
sstrncpy (vl.plugin, "thermal", sizeof(vl.plugin));
- sstrncpy (vl.plugin_instance, plugin_instance,
- sizeof(vl.plugin_instance));
- sstrncpy (vl.type, (dt == TEMP) ? "temperature" : "gauge",
+ if (plugin_instance != NULL)
+ sstrncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type,
+ (dt == TEMP) ? "temperature" : "gauge",
sizeof (vl.type));
plugin_dispatch_values (&vl);
char filename[256];
char data[1024];
int len;
- int ok = 0;
+ _Bool success = 0;
if (device_list && ignorelist_match (device_list, name))
return -1;
if (endptr == data + len && errno == 0) {
thermal_submit(name, TEMP, temp);
- ++ok;
+ success = 1;
}
}
@@ -107,11 +113,11 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
if (endptr == data + len && errno == 0) {
thermal_submit(name, COOLING_DEV, state);
- ++ok;
+ success = 1;
}
}
- return ok ? 0 : -1;
+ return (success ? 0 : -1);
}
static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
@@ -141,17 +147,17 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
&& (! strncmp(data, str_temp, sizeof(str_temp)-1))) {
char *endptr = NULL;
double temp;
- double celsius, add;
+ double factor, add;
if (data[--len] == 'C') {
add = 0;
- celsius = 1;
+ factor = 1.0;
} else if (data[len] == 'F') {
add = -32;
- celsius = 5/9;
+ factor = 5.0/9.0;
} else if (data[len] == 'K') {
add = -273.15;
- celsius = 1;
+ factor = 1.0;
} else
return -1;
++len;
errno = 0;
- temp = (strtod (data + len, &endptr) + add) * celsius;
+ temp = (strtod (data + len, &endptr) + add) * factor;
if (endptr != data + len && errno == 0) {
thermal_submit(name, TEMP, temp);
@@ -175,12 +181,6 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
return -1;
}
-static const char *config_keys[] = {
- "Device",
- "IgnoreSelected",
- "ForceUseProcfs"
-};
-
static int thermal_config (const char *key, const char *value)
{
if (device_list == NULL)
ret = plugin_register_read ("thermal", thermal_procfs_read);
}
- if (!ret) {
- vl_temp_template.values_len = 1;
- vl_temp_template.interval = interval_g;
- sstrncpy (vl_temp_template.host, hostname_g,
- sizeof(vl_temp_template.host));
- sstrncpy (vl_temp_template.plugin, "thermal",
- sizeof(vl_temp_template.plugin));
- sstrncpy (vl_temp_template.type_instance, "temperature",
- sizeof(vl_temp_template.type_instance));
-
- vl_state_template = vl_temp_template;
- sstrncpy (vl_state_template.type_instance, "cooling_state",
- sizeof(vl_state_template.type_instance));
- }
-
return ret;
}
diff --git a/src/types.db b/src/types.db
index ad542402952f33c23c1419866114520ae1971e21..0484983294ba523ff5b167c2c6f78e87c59dab7d 100644 (file)
--- a/src/types.db
+++ b/src/types.db
ath_stat value:COUNTER:0:4294967295
bitrate value:GAUGE:0:4294967295
bytes value:GAUGE:0:U
+cache_operation value:DERIVE:0:U
cache_ratio value:GAUGE:0:100
-cache_result value:COUNTER:0:4294967295
+cache_result value:DERIVE:0:U
cache_size value:GAUGE:0:4294967295
charge value:GAUGE:0:U
compression uncompressed:COUNTER:0:U, compressed:COUNTER:0:U
cpufreq value:GAUGE:0:U
cpu value:COUNTER:0:4294967295
current value:GAUGE:U:U
+current_connections value:GAUGE:0:U
+current_sessions value:GAUGE:0:U
delay seconds:GAUGE:-1000000:1000000
derive value:DERIVE:0:U
df used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
mysql_locks value:COUNTER:0:U
mysql_log_position value:COUNTER:0:4294967295
mysql_octets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-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
nginx_connections value:GAUGE:0:U
nginx_requests value:COUNTER:0:134217728
ps_state value:GAUGE:0:65535
ps_vm value:GAUGE:0:9223372036854775807
queue_length value:GAUGE:0:U
-response_time value:GAUGE:0:U
records count:GAUGE:0:U
+requests value:GAUGE:0:U
+response_time value:GAUGE:0:U
route_etx value:GAUGE:0:U
route_metric value:GAUGE:0:U
routes value:GAUGE:0:U
timeleft timeleft:GAUGE:0:3600
time_offset seconds:GAUGE:-1000000:1000000
total_bytes value:DERIVE:0:U
+total_connections value:DERIVE:0:U
+total_operations value:DERIVE:0:U
total_requests value:DERIVE:0:U
+total_sessions value:DERIVE:0:U
+total_threads value:DERIVE:0:U
total_time_in_ms value:DERIVE:0:U
total_values value:DERIVE:0:U
uptime value:GAUGE:0:4294967295
users users:GAUGE:0:65535
+vcpu value:GAUGE:0:U
virt_cpu_total ns:COUNTER:0:256000000000
virt_vcpu ns:COUNTER:0:1000000000
vmpage_action value:COUNTER:0:4294967295
vmpage_faults minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807
vmpage_io in:COUNTER:0:4294967295, out:COUNTER:0:4294967295
vmpage_number value:GAUGE:0:4294967295
+volatile_changes value:GAUGE:0:U
voltage_threshold value:GAUGE:U:U, threshold:GAUGE:U:U
voltage value:GAUGE:U:U
vs_memory value:GAUGE:0:9223372036854775807
diff --git a/src/unixsock.c b/src/unixsock.c
index 0b897482c9d956547d74be3f905f9d9941b157be..6de1395662161a66aaacafa389efa1e680583bf9 100644 (file)
--- a/src/unixsock.c
+++ b/src/unixsock.c
{
"SocketFile",
"SocketGroup",
- "SocketPerms"
+ "SocketPerms",
+ "DeleteSocket"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
static char *sock_file = NULL;
static char *sock_group = NULL;
static int sock_perms = S_IRWXU | S_IRWXG;
+static _Bool delete_socket = 0;
static pthread_t listen_thread = (pthread_t) 0;
sa.sun_family = AF_UNIX;
sstrncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
sizeof (sa.sun_path));
- /* unlink (sa.sun_path); */
DEBUG ("unixsock plugin: socket path = %s", sa.sun_path);
+ if (delete_socket)
+ {
+ errno = 0;
+ status = unlink (sa.sun_path);
+ if ((status != 0) && (errno != ENOENT))
+ {
+ char errbuf[1024];
+ WARNING ("unixsock plugin: Deleting socket file \"%s\" failed: %s",
+ sa.sun_path,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ }
+ else if (status == 0)
+ {
+ INFO ("unixsock plugin: Successfully deleted socket file \"%s\".",
+ sa.sun_path);
+ }
+ }
+
status = bind (sock_fd, (struct sockaddr *) &sa, sizeof (sa));
if (status != 0)
{
{
sock_perms = (int) strtol (val, NULL, 8);
}
+ else if (strcasecmp (key, "DeleteSocket") == 0)
+ {
+ if (IS_TRUE (val))
+ delete_socket = 1;
+ else
+ delete_socket = 0;
+ }
else
{
return (-1);
diff --git a/src/utils_cache.c b/src/utils_cache.c
index aeb662d55bc09e63c18ae856ac182aa04fc6b369..7e1dcf758af50785e0cb5551989a91e2c38373ec 100644 (file)
--- a/src/utils_cache.c
+++ b/src/utils_cache.c
/**
* collectd - src/utils_cache.c
- * Copyright (C) 2007,2008 Florian octo Forster
+ * Copyright (C) 2007-2010 Florian octo Forster
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
**/
#include "collectd.h"
value_t *values_raw;
/* Time contained in the package
* (for calculating rates) */
- time_t last_time;
+ cdtime_t last_time;
/* Time according to the local clock
* (for purging old entries) */
- time_t last_update;
+ cdtime_t last_update;
/* Interval in which the data is collected
* (for purding old entries) */
- int interval;
+ cdtime_t interval;
int state;
int hits;
sfree (ce);
} /* void cache_free */
+__attribute__((unused))
static int uc_send_notification (const char *name)
{
cache_entry_t *ce = NULL;
* acquiring the lock takes and we will use this time later to decide
* whether or not the state is OKAY.
*/
- n.time = time (NULL);
+ n.time = cdtime ();
status = c_avl_get (cache_tree, name, (void *) &ce);
if (status != 0)
}
ssnprintf (n.message, sizeof (n.message),
- "%s has not been updated for %i seconds.", name,
- (int) (n.time - ce->last_update));
+ "%s has not been updated for %.3f seconds.", name,
+ CDTIME_T_TO_DOUBLE (n.time - ce->last_update));
pthread_mutex_unlock (&cache_lock);
ce->values_gauge[i] = NAN;
if (vl->interval > 0)
ce->values_gauge[i] = ((double) vl->values[i].absolute)
- / ((double) vl->interval);
+ / CDTIME_T_TO_DOUBLE (vl->interval);
ce->values_raw[i].absolute = vl->values[i].absolute;
break;
uc_check_range (ds, ce);
ce->last_time = vl->time;
- ce->last_update = time (NULL);
+ ce->last_update = cdtime ();
ce->interval = vl->interval;
ce->state = STATE_OKAY;
int uc_check_timeout (void)
{
- time_t now;
+ cdtime_t now;
cache_entry_t *ce;
char **keys = NULL;
+ cdtime_t *keys_time = NULL;
+ cdtime_t *keys_interval = NULL;
int keys_len = 0;
char *key;
c_avl_iterator_t *iter;
+
+ int status;
int i;
pthread_mutex_lock (&cache_lock);
- now = time (NULL);
+ now = cdtime ();
/* Build a list of entries to be flushed */
iter = c_avl_get_iterator (cache_tree);
while (c_avl_iterator_next (iter, (void *) &key, (void *) &ce) == 0)
{
- /* If entry has not been updated, add to `keys' array */
- if ((now - ce->last_update) >= (timeout_g * ce->interval))
- {
- char **tmp;
-
- tmp = (char **) realloc ((void *) keys,
- (keys_len + 1) * sizeof (char *));
- if (tmp == NULL)
- {
- ERROR ("uc_check_timeout: realloc failed.");
- c_avl_iterator_destroy (iter);
- sfree (keys);
- pthread_mutex_unlock (&cache_lock);
- return (-1);
- }
-
- keys = tmp;
- keys[keys_len] = strdup (key);
- if (keys[keys_len] == NULL)
- {
- ERROR ("uc_check_timeout: strdup failed.");
- continue;
- }
- keys_len++;
- }
- } /* while (c_avl_iterator_next) */
+ char **tmp;
+ cdtime_t *tmp_time;
- ce = NULL;
-
- for (i = 0; i < keys_len; i++)
- {
- int status;
-
- status = ut_check_interesting (keys[i]);
+ /* If the entry is fresh enough, continue. */
+ if ((now - ce->last_update) < (ce->interval * timeout_g))
+ continue;
- if (status < 0)
+ /* If entry has not been updated, add to `keys' array */
+ tmp = (char **) realloc ((void *) keys,
+ (keys_len + 1) * sizeof (char *));
+ if (tmp == NULL)
{
- ERROR ("uc_check_timeout: ut_check_interesting failed.");
- sfree (keys[i]);
+ ERROR ("uc_check_timeout: realloc failed.");
continue;
}
- else if (status == 0) /* ``service'' is uninteresting */
+ keys = tmp;
+
+ tmp_time = realloc (keys_time, (keys_len + 1) * sizeof (*keys_time));
+ if (tmp_time == NULL)
{
- DEBUG ("uc_check_timeout: %s is missing but ``uninteresting''",
- keys[i]);
- ce = NULL;
- status = c_avl_remove (cache_tree, keys[i],
- (void *) &key, (void *) &ce);
- if (status != 0)
- {
- ERROR ("uc_check_timeout: c_avl_remove (%s) failed.", keys[i]);
- }
- sfree (keys[i]);
- sfree (key);
- if (ce != NULL)
- cache_free (ce);
+ ERROR ("uc_check_timeout: realloc failed.");
continue;
}
+ keys_time = tmp_time;
- /* If we get here, the value is ``interesting''. Query the record from the
- * cache and update the state field. */
- if (c_avl_get (cache_tree, keys[i], (void *) &ce) != 0)
+ tmp_time = realloc (keys_interval, (keys_len + 1) * sizeof (*keys_interval));
+ if (tmp_time == NULL)
{
- ERROR ("uc_check_timeout: cannot get data for %s from cache", keys[i]);
- /* Do not free `keys[i]' so a notification is sent further down. */
+ ERROR ("uc_check_timeout: realloc failed.");
continue;
}
- assert (ce != NULL);
+ keys_interval = tmp_time;
- if (status == 2) /* persist */
+ keys[keys_len] = strdup (key);
+ if (keys[keys_len] == NULL)
{
- DEBUG ("uc_check_timeout: %s is missing, sending notification.",
- keys[i]);
- ce->state = STATE_MISSING;
- /* Do not free `keys[i]' so a notification is sent further down. */
- }
- else if (status == 1) /* do not persist */
- {
- if (ce->state == STATE_MISSING)
- {
- DEBUG ("uc_check_timeout: %s is missing but "
- "notification has already been sent.",
- keys[i]);
- /* Set `keys[i]' to NULL to no notification is sent. */
- sfree (keys[i]);
- }
- else /* (ce->state != STATE_MISSING) */
- {
- DEBUG ("uc_check_timeout: %s is missing, sending one notification.",
- keys[i]);
- ce->state = STATE_MISSING;
- /* Do not free `keys[i]' so a notification is sent further down. */
- }
- }
- else
- {
- WARNING ("uc_check_timeout: ut_check_interesting (%s) returned "
- "invalid status %i.",
- keys[i], status);
- sfree (keys[i]);
+ ERROR ("uc_check_timeout: strdup failed.");
+ continue;
}
+ keys_time[keys_len] = ce->last_time;
+ keys_interval[keys_len] = ce->interval;
- /* Make really sure the next iteration doesn't work with this pointer.
- * There have been too many bugs in the past.. :/ -- octo */
- ce = NULL;
- } /* for (keys[i]) */
+ keys_len++;
+ } /* while (c_avl_iterator_next) */
c_avl_iterator_destroy (iter);
-
pthread_mutex_unlock (&cache_lock);
+ if (keys_len == 0)
+ return (0);
+
+ /* Call the "missing" callback for each value. Do this before removing the
+ * value from the cache, so that callbacks can still access the data stored,
+ * including plugin specific meta data, rates, history, …. This must be done
+ * without holding the lock, otherwise we will run into a deadlock if a
+ * plugin calls the cache interface. */
+ for (i = 0; i < keys_len; i++)
+ {
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = NULL;
+ vl.values_len = 0;
+ vl.meta = NULL;
+
+ status = parse_identifier_vl (keys[i], &vl);
+ if (status != 0)
+ {
+ ERROR ("uc_check_timeout: parse_identifier_vl (\"%s\") failed.", keys[i]);
+ cache_free (ce);
+ continue;
+ }
+
+ vl.time = keys_time[i];
+ vl.interval = keys_interval[i];
+
+ plugin_dispatch_missing (&vl);
+ } /* for (i = 0; i < keys_len; i++) */
+
+ /* Now actually remove all the values from the cache. We don't re-evaluate
+ * the timestamp again, so in theory it is possible we remove a value after
+ * it is updated here. */
+ pthread_mutex_lock (&cache_lock);
for (i = 0; i < keys_len; i++)
{
- if (keys[i] == NULL)
+ key = NULL;
+ ce = NULL;
+
+ status = c_avl_remove (cache_tree, keys[i],
+ (void *) &key, (void *) &ce);
+ if (status != 0)
+ {
+ ERROR ("uc_check_timeout: c_avl_remove (\"%s\") failed.", keys[i]);
+ sfree (keys[i]);
continue;
+ }
- uc_send_notification (keys[i]);
sfree (keys[i]);
- }
+ sfree (key);
+ cache_free (ce);
+ } /* for (i = 0; i < keys_len; i++) */
+ pthread_mutex_unlock (&cache_lock);
sfree (keys);
+ sfree (keys_time);
+ sfree (keys_interval);
return (0);
} /* int uc_check_timeout */
char name[6 * DATA_MAX_NAME_LEN];
cache_entry_t *ce = NULL;
int send_okay_notification = 0;
- time_t update_delay = 0;
+ cdtime_t update_delay = 0;
notification_t n;
int status;
int i;
if (ce->last_time >= vl->time)
{
pthread_mutex_unlock (&cache_lock);
- NOTICE ("uc_update: Value too old: name = %s; value time = %u; "
- "last cache update = %u;",
- name, (unsigned int) vl->time, (unsigned int) ce->last_time);
+ NOTICE ("uc_update: Value too old: name = %s; value time = %.3f; "
+ "last cache update = %.3f;",
+ name,
+ CDTIME_T_TO_DOUBLE (vl->time),
+ CDTIME_T_TO_DOUBLE (ce->last_time));
return (-1);
}
{
send_okay_notification = 1;
ce->state = STATE_OKAY;
- update_delay = time (NULL) - ce->last_update;
+ update_delay = cdtime () - ce->last_update;
}
for (i = 0; i < ds->ds_num; i++)
}
ce->values_gauge[i] = ((double) diff)
- / ((double) (vl->time - ce->last_time));
+ / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
ce->values_raw[i].counter = vl->values[i].counter;
}
break;
diff = vl->values[i].derive - ce->values_raw[i].derive;
ce->values_gauge[i] = ((double) diff)
- / ((double) (vl->time - ce->last_time));
+ / (CDTIME_T_TO_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));
+ / (CDTIME_T_TO_DOUBLE (vl->time - ce->last_time));
ce->values_raw[i].absolute = vl->values[i].absolute;
break;
uc_check_range (ds, ce);
ce->last_time = vl->time;
- ce->last_update = time (NULL);
+ ce->last_update = cdtime ();
ce->interval = vl->interval;
pthread_mutex_unlock (&cache_lock);
return (ret);
} /* gauge_t *uc_get_rate */
-int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number)
+int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
{
c_avl_iterator_t *iter;
char *key;
cache_entry_t *value;
char **names = NULL;
- time_t *times = NULL;
+ cdtime_t *times = NULL;
size_t number = 0;
int status = 0;
if (ret_times != NULL)
{
- time_t *tmp_times;
+ cdtime_t *tmp_times;
- tmp_times = (time_t *) realloc (times, sizeof (time_t) * (number + 1));
+ tmp_times = (cdtime_t *) realloc (times, sizeof (cdtime_t) * (number + 1));
if (tmp_times == NULL)
{
status = -1;
diff --git a/src/utils_cache.h b/src/utils_cache.h
index f8059ecaf077dda6924122e3dc6452b4babfb282..87f93c0ed378ca0bcefed6f89cdcbd72053291f9 100644 (file)
--- a/src/utils_cache.h
+++ b/src/utils_cache.h
int uc_get_rate_by_name (const char *name, gauge_t **ret_values, size_t *ret_values_num);
gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl);
-int uc_get_names (char ***ret_names, time_t **ret_times, size_t *ret_number);
+int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number);
int uc_get_state (const data_set_t *ds, const value_list_t *vl);
int uc_set_state (const data_set_t *ds, const value_list_t *vl, int state);
diff --git a/src/utils_cmd_flush.c b/src/utils_cmd_flush.c
index 0e7b350f581f02f07ccaf234c1ec0c225011b33d..3584f3b71a3c82bd73ec85cd55201422f8a8e1f8 100644 (file)
--- a/src/utils_cmd_flush.c
+++ b/src/utils_cmd_flush.c
int success = 0;
int error = 0;
- int timeout = -1;
+ double timeout = 0.0;
char **plugins = NULL;
int plugins_num = 0;
char **identifiers = NULL;
errno = 0;
endptr = NULL;
- timeout = strtol (opt_value, &endptr, 0);
+ timeout = strtod (opt_value, &endptr);
- if ((endptr == opt_value) || (errno != 0))
+ if ((endptr == opt_value) || (errno != 0) || (!isfinite (timeout)))
{
print_to_socket (fh, "-1 Invalid value for option `timeout': "
"%s\n", opt_value);
sfree (identifiers);
return (-1);
}
- else if (timeout <= 0)
- timeout = -1;
+ else if (timeout < 0.0)
+ {
+ timeout = 0.0;
+ }
}
else
{
int status;
identifier = identifiers[j];
- status = plugin_flush (plugin, timeout, identifier);
+ status = plugin_flush (plugin,
+ DOUBLE_TO_CDTIME_T (timeout),
+ identifier);
if (status == 0)
success++;
else
index 4ca9646de8155a71b1a2b076cabf9b74ef5de002..ef66af56c408d8ae1ab300386875c7d57fe93189 100644 (file)
--- a/src/utils_cmd_listval.c
+++ b/src/utils_cmd_listval.c
{
char *command;
char **names = NULL;
- time_t *times = NULL;
+ cdtime_t *times = NULL;
size_t number = 0;
size_t i;
int status;
print_to_socket (fh, "%i Value%s found\n",
(int) number, (number == 1) ? "" : "s");
for (i = 0; i < number; i++)
- print_to_socket (fh, "%u %s\n", (unsigned int) times[i], names[i]);
+ print_to_socket (fh, "%.3f %s\n", CDTIME_T_TO_DOUBLE (times[i]),
+ names[i]);
free_everything_and_return (0);
} /* int handle_listval */
diff --git a/src/utils_cmd_putval.c b/src/utils_cmd_putval.c
index ec2b5f876795b53f2faec5c5ddc6104d7c0679a3..dd43337ee01390eb3c703a5d8c473bc93eb7ea90 100644 (file)
--- a/src/utils_cmd_putval.c
+++ b/src/utils_cmd_putval.c
if (strcasecmp ("interval", key) == 0)
{
- int tmp;
+ double tmp;
char *endptr;
endptr = NULL;
errno = 0;
- tmp = strtol (value, &endptr, 0);
+ tmp = strtod (value, &endptr);
if ((errno == 0) && (endptr != NULL)
- && (endptr != value) && (tmp > 0))
- vl->interval = tmp;
+ && (endptr != value) && (tmp > 0.0))
+ vl->interval = DOUBLE_TO_CDTIME_T (tmp);
}
else
return (1);
return (0);
} /* int handle_putval */
+int create_putval (char *ret, size_t ret_len, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl)
+{
+ char buffer_ident[6 * DATA_MAX_NAME_LEN];
+ char buffer_values[1024];
+ int status;
+
+ status = FORMAT_VL (buffer_ident, sizeof (buffer_ident), vl);
+ if (status != 0)
+ return (status);
+ escape_string (buffer_ident, sizeof (buffer_ident));
+
+ status = format_values (buffer_values, sizeof (buffer_values),
+ ds, vl, /* store rates = */ 0);
+ if (status != 0)
+ return (status);
+ escape_string (buffer_values, sizeof (buffer_values));
+
+ ssnprintf (ret, ret_len,
+ "PUTVAL %s interval=%.3f %s",
+ buffer_ident,
+ (vl->interval > 0)
+ ? CDTIME_T_TO_DOUBLE (vl->interval)
+ : CDTIME_T_TO_DOUBLE (interval_g),
+ buffer_values);
+
+ return (0);
+} /* }}} int create_putval */
diff --git a/src/utils_cmd_putval.h b/src/utils_cmd_putval.h
index 8460b13388488be5c1401a3ff23a57a3d6e4f4bb..9c92fd31c0caf6a0524ef595c60d3158051b73aa 100644 (file)
--- a/src/utils_cmd_putval.h
+++ b/src/utils_cmd_putval.h
#include <stdio.h>
+#include "plugin.h"
+
int handle_putval (FILE *fh, char *buffer);
+int create_putval (char *ret, size_t ret_len,
+ const data_set_t *ds, const value_list_t *vl);
+
#endif /* UTILS_CMD_PUTVAL_H */
diff --git a/src/utils_db_query.c b/src/utils_db_query.c
index 7d594d812a4e0bf2f0f1b9c3e936ec762f917e5a..dcac80764c665ca1dd98a456feea0cb2386692c4 100644 (file)
--- a/src/utils_db_query.c
+++ b/src/utils_db_query.c
char **values;
size_t values_num;
- /* Legacy data */
- int legacy_mode;
- size_t legacy_position;
- /* When in legacy mode:
- * - type/ds hold the format of the data
- * - instance_prefix is used as type-instance if non-NULL
- * - legacy_position holds the index of the column to use as value.
- */
-
udb_result_t *next;
}; /* }}} */
char *statement;
void *user_data;
- int legacy_mode;
-
unsigned int min_version;
unsigned int max_version;
char *plugin;
char *db_name;
- int interval;
+ cdtime_t interval;
udb_result_preparation_area_t *result_prep_areas;
}; /* }}} */
return (0);
} /* }}} int udb_config_set_uint */
-/*
- * Legacy result private functions
- */
-static void udb_legacy_result_finish_result (const udb_result_t const *r, /* {{{ */
- udb_result_preparation_area_t *prep_area)
-{
- if ((r == NULL) || (prep_area))
- return;
-
- assert (r->legacy_mode == 1);
-
- prep_area->ds = NULL;
-} /* }}} void udb_legacy_result_finish_result */
-
-static int udb_legacy_result_handle_result (udb_result_t *r, /* {{{ */
- udb_query_preparation_area_t *q_area,
- udb_result_preparation_area_t *r_area,
- const udb_query_t const *q, char **column_values)
-{
- value_list_t vl = VALUE_LIST_INIT;
- value_t value;
- char *value_str;
-
- assert (r->legacy_mode == 1);
- assert (r_area->ds != NULL);
- assert (r_area->ds->ds_num == 1);
-
- vl.values = &value;
- vl.values_len = 1;
-
- value_str = column_values[r->legacy_position];
- if (0 != parse_value (value_str, &vl.values[0], r_area->ds->ds[0].type))
- {
- ERROR ("db query utils: udb_legacy_result_handle_result: "
- "Parsing `%s' as %s failed.", value_str,
- DS_TYPE_TO_STRING (r_area->ds->ds[0].type));
- errno = EINVAL;
- return (-1);
- }
-
- if (q_area->interval > 0)
- vl.interval = q_area->interval;
-
- sstrncpy (vl.host, q_area->host, sizeof (vl.host));
- sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.type_instance));
- sstrncpy (vl.type, r->type, sizeof (vl.type));
-
- if (r->instance_prefix != NULL)
- sstrncpy (vl.type_instance, r->instance_prefix,
- sizeof (vl.type_instance));
-
- plugin_dispatch_values (&vl);
-
- return (0);
-} /* }}} int udb_legacy_result_handle_result */
-
-static int udb_legacy_result_prepare_result (const udb_result_t const *r, /* {{{ */
- udb_result_preparation_area_t *prep_area,
- char **column_names, size_t column_num)
-{
- if (r == NULL)
- return (-EINVAL);
-
- assert (r->legacy_mode == 1);
-
- /* Make sure previous preparations are cleaned up. */
- udb_legacy_result_finish_result (r, prep_area);
-
- if (r->legacy_position >= column_num)
- {
- ERROR ("db query utils: The legacy configuration specified (at least) "
- "%zu `Column's, but the query returned only %zu columns!",
- r->legacy_position + 1, column_num);
- return (-ENOENT);
- }
-
- /* Read `ds' and check number of values {{{ */
- prep_area->ds = plugin_get_ds (r->type);
- if (prep_area->ds == NULL)
- {
- ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not "
- "known by the daemon. See types.db(5) for details.",
- r->type);
- return (-1);
- }
-
- if (prep_area->ds->ds_num != 1)
- {
- ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
- "requires exactly %i values, but the legacy configuration "
- "requires exactly one!",
- r->type,
- prep_area->ds->ds_num);
- return (-1);
- }
- /* }}} */
-
- return (0);
-} /* }}} int udb_legacy_result_prepare_result */
-
-static int udb_legacy_result_create (const char *query_name, /* {{{ */
- udb_result_t **r_head, oconfig_item_t *ci, size_t position)
-{
- udb_result_t *r;
-
- if ((ci->values_num < 1) || (ci->values_num > 2)
- || (ci->values[0].type != OCONFIG_TYPE_STRING)
- || ((ci->values_num == 2)
- && (ci->values[1].type != OCONFIG_TYPE_STRING)))
- {
- WARNING ("db query utils: The `Column' block needs either one or two "
- "string arguments.");
- return (-1);
- }
-
- r = (udb_result_t *) malloc (sizeof (*r));
- if (r == NULL)
- {
- ERROR ("db query utils: malloc failed.");
- return (-1);
- }
- memset (r, 0, sizeof (*r));
-
- r->legacy_mode = 1;
- r->legacy_position = position;
-
- r->type = strdup (ci->values[0].value.string);
- if (r->type == NULL)
- {
- ERROR ("db query utils: strdup failed.");
- free (r);
- return (-1);
- }
-
- r->instance_prefix = NULL;
- if (ci->values_num == 2)
- {
- r->instance_prefix = strdup (ci->values[1].value.string);
- if (r->instance_prefix == NULL)
- {
- ERROR ("db query utils: strdup failed.");
- free (r->type);
- free (r);
- return (-1);
- }
- }
-
- /* If all went well, add this result to the list of results. */
- if (*r_head == NULL)
- {
- *r_head = r;
- }
- else
- {
- udb_result_t *last;
-
- last = *r_head;
- while (last->next != NULL)
- last = last->next;
-
- last->next = r;
- }
-
- return (0);
-} /* }}} int udb_legacy_result_create */
-
/*
* Result private functions
*/
size_t i;
assert (r != NULL);
- assert (r->legacy_mode == 0);
assert (r_area->ds != NULL);
assert (((size_t) r_area->ds->ds_num) == r->values_num);
if ((r == NULL) || (prep_area == NULL))
return;
- if (r->legacy_mode == 1)
- {
- udb_legacy_result_finish_result (r, prep_area);
- return;
- }
-
- assert (r->legacy_mode == 0);
-
prep_area->ds = NULL;
sfree (prep_area->instances_pos);
sfree (prep_area->values_pos);
assert (r && q_area && r_area);
- if (r->legacy_mode == 1)
- return (udb_legacy_result_handle_result (r, q_area, r_area,
- q, column_values));
-
- assert (r->legacy_mode == 0);
-
for (i = 0; i < r->instances_num; i++)
r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
if ((r == NULL) || (prep_area == NULL))
return (-EINVAL);
- if (r->legacy_mode == 1)
- return (udb_legacy_result_prepare_result (r, prep_area,
- column_names, column_num));
-
- assert (r->legacy_mode == 0);
-
#define BAIL_OUT(status) \
prep_area->ds = NULL; \
sfree (prep_area->instances_pos); \
*/
int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
size_t *ret_query_list_len, oconfig_item_t *ci,
- udb_query_create_callback_t cb, int legacy_mode)
+ udb_query_create_callback_t cb)
{
udb_query_t **query_list;
size_t query_list_len;
int status;
int i;
- size_t legacy_position;
-
if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
return (-EINVAL);
query_list = *ret_query_list;
return (-1);
}
memset (q, 0, sizeof (*q));
- q->legacy_mode = legacy_mode;
q->min_version = 0;
q->max_version = UINT_MAX;
- legacy_position = 0;
-
status = udb_config_set_string (&q->name, ci);
if (status != 0)
{
else if (strcasecmp ("MaxVersion", child->key) == 0)
status = udb_config_set_uint (&q->max_version, child);
- /* PostgreSQL compatibility code */
- else if ((strcasecmp ("Query", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `Query' option is "
- "deprecated. Please use `Statement' instead.",
- q->name);
- status = udb_config_set_string (&q->statement, child);
- }
- else if ((strcasecmp ("Column", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `Column' option is "
- "deprecated. Please use the new syntax instead.",
- q->name);
- status = udb_legacy_result_create (q->name, &q->results, child,
- legacy_position);
- legacy_position++;
- }
- else if ((strcasecmp ("MinPGVersion", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `MinPGVersion' option is "
- "deprecated. Please use `MinVersion' instead.",
- q->name);
- status = udb_config_set_uint (&q->min_version, child);
- }
- else if ((strcasecmp ("MaxPGVersion", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `MaxPGVersion' option is "
- "deprecated. Please use `MaxVersion' instead.",
- q->name);
- status = udb_config_set_uint (&q->max_version, child);
- }
-
/* Call custom callbacks */
else if (cb != NULL)
{
sfree (prep_area->plugin);
sfree (prep_area->db_name);
- prep_area->interval = -1;
+ prep_area->interval = 0;
for (r = q->results, r_area = prep_area->result_prep_areas;
r != NULL; r = r->next, r_area = r_area->next)
int udb_query_prepare_result (const udb_query_t const *q, /* {{{ */
udb_query_preparation_area_t *prep_area,
const char *host, const char *plugin, const char *db_name,
- char **column_names, size_t column_num, int interval)
+ char **column_names, size_t column_num, cdtime_t interval)
{
udb_result_preparation_area_t *r_area;
udb_result_t *r;
diff --git a/src/utils_db_query.h b/src/utils_db_query.h
index fa2b2885679c435245b836f4cbc4ccb01556c5db..727be03647714e8bc76f6b4d5403508eeca74616 100644 (file)
--- a/src/utils_db_query.h
+++ b/src/utils_db_query.h
*/
int udb_query_create (udb_query_t ***ret_query_list,
size_t *ret_query_list_len, oconfig_item_t *ci,
- udb_query_create_callback_t cb, int legacy_mode);
+ udb_query_create_callback_t cb);
void udb_query_free (udb_query_t **query_list, size_t query_list_len);
int udb_query_pick_from_list_by_name (const char *name,
int udb_query_prepare_result (const udb_query_t const *q,
udb_query_preparation_area_t *prep_area,
const char *host, const char *plugin, const char *db_name,
- char **column_names, size_t column_num, int interval);
+ char **column_names, size_t column_num, cdtime_t interval);
int udb_query_handle_result (const udb_query_t const *q,
udb_query_preparation_area_t *prep_area, char **column_values);
void udb_query_finish_result (const udb_query_t const *q,
diff --git a/src/utils_dns.c b/src/utils_dns.c
index 2348be24db05d55c5b1d6b6ad000ce8108594701..22c9b95994377f9ed1752d4192eb25c29a97b8e8 100644 (file)
--- a/src/utils_dns.c
+++ b/src/utils_dns.c
@@ -291,13 +291,18 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
off_t no = 0;
unsigned char c;
size_t len;
- assert(ns > 0);
+ static int loop_detect = 0;
+ if (loop_detect > 2)
+ return 4; /* compression loop */
+ if (ns <= 0)
+ return 4; /* probably compression loop */
do {
if ((*off) >= sz)
break;
c = *(buf + (*off));
if (c > 191) {
/* blasted compression */
+ int rc;
unsigned short s;
off_t ptr;
memcpy(&s, buf + (*off), sizeof(s));
@@ -305,18 +310,23 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
(*off) += sizeof(s);
/* Sanity check */
if ((*off) >= sz)
- return 1;
+ return 1; /* message too short */
ptr = s & 0x3FFF;
/* Make sure the pointer is inside this message */
if (ptr >= sz)
- return 2;
- return rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
+ return 2; /* bad compression ptr */
+ if (ptr < DNS_MSG_HDR_SZ)
+ return 2; /* bad compression ptr */
+ loop_detect++;
+ rc = rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no);
+ loop_detect--;
+ return rc;
} else if (c > RFC1035_MAXLABELSZ) {
/*
* "(The 10 and 01 combinations are reserved for future use.)"
*/
+ return 3; /* reserved label/compression flags */
break;
- return 3;
} else {
(*off)++;
len = (size_t) c;
@@ -324,15 +334,18 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
break;
if (len > (ns - 1))
len = ns - 1;
- if ((*off) + len > sz) /* message is too short */
- return 4;
+ if ((*off) + len > sz)
+ return 4; /* message is too short */
+ if (no + len + 1 > ns)
+ return 5; /* qname would overflow name buffer */
memcpy(name + no, buf + (*off), len);
(*off) += len;
no += len;
*(name + (no++)) = '.';
}
} while (c > 0);
- *(name + no - 1) = '\0';
+ if (no > 0)
+ *(name + no - 1) = '\0';
/* make sure we didn't allow someone to overflow the name buffer */
assert(no <= ns);
return 0;
uint16_t us;
off_t offset;
char *t;
- int x;
+ int status;
/* The DNS header is 12 bytes long */
- if (len < 12)
+ if (len < DNS_MSG_HDR_SZ)
return 0;
memcpy(&us, buf + 0, 2);
memcpy(&us, buf + 10, 2);
qh.arcount = ntohs(us);
- offset = 12;
+ offset = DNS_MSG_HDR_SZ;
memset(qh.qname, '\0', MAX_QNAME_SZ);
- x = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
- if (0 != x)
+ status = rfc1035NameUnpack(buf, len, &offset, qh.qname, MAX_QNAME_SZ);
+ if (status != 0)
+ {
+ INFO ("utils_dns: handle_dns: rfc1035NameUnpack failed "
+ "with status %i.", status);
return 0;
+ }
if ('\0' == qh.qname[0])
sstrncpy (qh.qname, ".", sizeof (qh.qname));
while ((t = strchr(qh.qname, '\n')))
@@ -647,10 +664,6 @@ void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr, const u_char *pkt
{
int status;
- DEBUG ("handle_pcap (udata = %p, hdr = %p, pkt = %p): hdr->caplen = %i\n",
- (void *) udata, (void *) hdr, (void *) pkt,
- hdr->caplen);
-
if (hdr->caplen < ETHER_HDR_LEN)
return;
@@ -684,7 +697,7 @@ void handle_pcap(u_char *udata, const struct pcap_pkthdr *hdr, const u_char *pkt
break;
default:
- ERROR ("handle_pcap: unsupported data link type %d\n",
+ ERROR ("handle_pcap: unsupported data link type %d",
pcap_datalink(pcap_obj));
status = 0;
break;
diff --git a/src/utils_dns.h b/src/utils_dns.h
index efc790319cebea5e3253cad748de71d4e8923aaa..56213afa18bc800035fafa88b149120edf266b4f 100644 (file)
--- a/src/utils_dns.h
+++ b/src/utils_dns.h
# include <pcap.h>
#endif
+#define DNS_MSG_HDR_SZ 12
+
#define T_MAX 65536
#define OP_MAX 16
#define C_MAX 65536
index ac88c0fa27c4f7ae4b50cd734d78f886a79482b3..65c886b6fc28239183be31d8a10a896ec5f7800c 100644 (file)
--- a/src/utils_format_json.c
+++ b/src/utils_format_json.c
BUFFER_ADD (",\"dsnames\":%s", temp);
BUFFER_ADD (",\"time\":%lu", (unsigned long) vl->time);
- BUFFER_ADD (",\"interval\":%i", vl->interval);
+ BUFFER_ADD (",\"interval\":%.3f", CDTIME_T_TO_DOUBLE (vl->interval));
#define BUFFER_ADD_KEYVAL(key, value) do { \
status = escape_string (temp, sizeof (temp), (value)); \
diff --git a/src/utils_rrdcreate.c b/src/utils_rrdcreate.c
index 66bb27e75dacf6ad6bce7f7f659cfd9e59bd211e..ce6443b7e5a47300e72fae2b2bb81d729ac3db41 100644 (file)
--- a/src/utils_rrdcreate.c
+++ b/src/utils_rrdcreate.c
return (-1);
}
- ss = (cfg->stepsize > 0) ? cfg->stepsize : vl->interval;
+ if (cfg->stepsize > 0)
+ ss = cfg->stepsize;
+ else
+ ss = (int) CDTIME_T_TO_TIME_T (vl->interval);
if (ss <= 0)
{
*ret = NULL;
status = ssnprintf (buffer, sizeof (buffer),
"DS:%s:%s:%i:%s:%s",
d->name, type,
- (cfg->heartbeat > 0) ? cfg->heartbeat : (2 * vl->interval),
+ (cfg->heartbeat > 0)
+ ? cfg->heartbeat
+ : (int) CDTIME_T_TO_TIME_T (2 * vl->interval),
min, max);
if ((status < 1) || ((size_t) status >= sizeof (buffer)))
break;
last_up = time (NULL) - 10;
ssnprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
- ssnprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
+ ssnprintf (last_up_str, sizeof (last_up_str), "%lu", (unsigned long) last_up);
new_argv[0] = "create";
new_argv[1] = (void *) filename;
char **ds_def;
int ds_num;
int status = 0;
+ time_t last_up;
+ int stepsize;
if (check_create_dir (filename))
return (-1);
memcpy (argv + ds_num, rra_def, rra_num * sizeof (char *));
argv[ds_num + rra_num] = NULL;
+ last_up = CDTIME_T_TO_TIME_T (vl->time);
+ if (last_up <= 10)
+ last_up = time (NULL);
+ last_up -= 10;
+
+ if (cfg->stepsize > 0)
+ stepsize = cfg->stepsize;
+ else
+ stepsize = (int) CDTIME_T_TO_TIME_T (vl->interval);
+
status = srrd_create (filename,
(cfg->stepsize > 0) ? cfg->stepsize : vl->interval,
- (vl->time > 10) ? (vl->time - 10) : vl->time,
+ last_up,
argc, (const char **) argv);
free (argv);
diff --git a/src/utils_threshold.c b/src/utils_threshold.c
index 090cc75206f9c47acdde32dc5c6821bca67201aa..99309b93b58b46ec84512cad69b087deba146a19 100644 (file)
--- a/src/utils_threshold.c
+++ b/src/utils_threshold.c
#define UT_FLAG_INVERT 0x01
#define UT_FLAG_PERSIST 0x02
#define UT_FLAG_PERCENTAGE 0x04
+#define UT_FLAG_INTERESTING 0x08
/* }}} */
/*
return (0);
} /* int ut_config_type_min */
-static int ut_config_type_invert (threshold_t *th, oconfig_item_t *ci)
-{
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
- {
- WARNING ("threshold values: The `Invert' option needs exactly one "
- "boolean argument.");
- return (-1);
- }
-
- if (ci->values[0].value.boolean)
- th->flags |= UT_FLAG_INVERT;
- else
- th->flags &= ~UT_FLAG_INVERT;
-
- return (0);
-} /* int ut_config_type_invert */
-
-static int ut_config_type_persist (threshold_t *th, oconfig_item_t *ci)
-{
- if ((ci->values_num != 1)
- || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
- {
- WARNING ("threshold values: The `Persist' option needs exactly one "
- "boolean argument.");
- return (-1);
- }
-
- if (ci->values[0].value.boolean)
- th->flags |= UT_FLAG_PERSIST;
- else
- th->flags &= ~UT_FLAG_PERSIST;
-
- 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_hits (threshold_t *th, oconfig_item_t *ci)
{
if ((ci->values_num != 1)
th.failure_max = NAN;
th.hits = 0;
th.hysteresis = 0;
+ th.flags = UT_FLAG_INTERESTING; /* interesting by default */
for (i = 0; i < ci->children_num; i++)
{
else if ((strcasecmp ("WarningMin", option->key) == 0)
|| (strcasecmp ("FailureMin", option->key) == 0))
status = ut_config_type_min (&th, option);
+ else if (strcasecmp ("Interesting", option->key) == 0)
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_INTERESTING);
else if (strcasecmp ("Invert", option->key) == 0)
- status = ut_config_type_invert (&th, option);
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_INVERT);
else if (strcasecmp ("Persist", option->key) == 0)
- status = ut_config_type_persist (&th, option);
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERSIST);
else if (strcasecmp ("Percentage", option->key) == 0)
- status = ut_config_type_percentage (&th, option);
+ status = cf_util_get_flag (option, &th.flags, UT_FLAG_PERCENTAGE);
else if (strcasecmp ("Hits", option->key) == 0)
status = ut_config_type_hits (&th, option);
else if (strcasecmp ("Hysteresis", option->key) == 0)
th.hits = 0;
th.hysteresis = 0;
+ th.flags = UT_FLAG_INTERESTING; /* interesting by default */
for (i = 0; i < ci->children_num; i++)
{
th = threshold_search (&vl);
if (th == NULL)
return (0);
+
+ if ((th->flags & UT_FLAG_INTERESTING) == 0)
+ return (0);
+
if ((th->flags & UT_FLAG_PERSIST) == 0)
return (1);
return (2);
diff --git a/src/utils_threshold.h b/src/utils_threshold.h
index 8aaf34c61af0175c18d3fa9f4ae3897d8b998e15..5955ca6ed79db1a124c33a46ea56e0f1e53e4860 100644 (file)
--- a/src/utils_threshold.h
+++ b/src/utils_threshold.h
gauge_t failure_min;
gauge_t failure_max;
gauge_t hysteresis;
- int flags;
+ unsigned int flags;
int hits;
struct threshold_s *next;
} threshold_t;
diff --git a/src/utils_time.c b/src/utils_time.c
--- /dev/null
+++ b/src/utils_time.c
@@ -0,0 +1,64 @@
+/**
+ * collectd - src/utils_time.h
+ * Copyright (C) 2010 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * 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 <ff at octo.it>
+ **/
+
+#include "collectd.h"
+#include "utils_time.h"
+#include "plugin.h"
+#include "common.h"
+
+#if HAVE_CLOCK_GETTIME
+cdtime_t cdtime (void) /* {{{ */
+{
+ int status;
+ struct timespec ts = { 0, 0 };
+
+ status = clock_gettime (CLOCK_REALTIME, &ts);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("cdtime: clock_gettime failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (0);
+ }
+
+ return (TIMESPEC_TO_CDTIME_T (&ts));
+} /* }}} cdtime_t cdtime */
+#else
+/* Work around for Mac OS X which doesn't have clock_gettime(2). *sigh* */
+cdtime_t cdtime (void) /* {{{ */
+{
+ int status;
+ struct timeval tv = { 0, 0 };
+
+ status = gettimeofday (&tv, /* struct timezone = */ NULL);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("cdtime: gettimeofday failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (0);
+ }
+
+ return (TIMEVAL_TO_CDTIME_T (&tv));
+} /* }}} cdtime_t cdtime */
+#endif
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_time.h b/src/utils_time.h
--- /dev/null
+++ b/src/utils_time.h
@@ -0,0 +1,70 @@
+/**
+ * collectd - src/utils_time.h
+ * Copyright (C) 2010 Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * 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 <ff at octo.it>
+ **/
+
+#ifndef UTILS_TIME_H
+#define UTILS_TIME_H 1
+
+#include "collectd.h"
+
+/*
+ * "cdtime_t" is a 64bit unsigned integer. The time is stored at a 2^-30 second
+ * resolution, i.e. the most significant 34 bit are used to store the time in
+ * seconds, the least significant bits store the sub-second part in something
+ * very close to nanoseconds. *The* big advantage of storing time in this
+ * manner is that comparing times and calculating differences is as simple as
+ * it is with "time_t", i.e. a simple integer comparison / subtraction works.
+ */
+/*
+ * cdtime_t is defined in "collectd.h" */
+/* typedef uint64_t cdtime_t; */
+
+/* 2^30 = 1073741824 */
+#define TIME_T_TO_CDTIME_T(t) (((cdtime_t) (t)) * 1073741824)
+#define CDTIME_T_TO_TIME_T(t) ((time_t) ((t) / 1073741824))
+
+#define CDTIME_T_TO_DOUBLE(t) (((double) (t)) / 1073741824.0)
+#define DOUBLE_TO_CDTIME_T(d) ((cdtime_t) ((d) * 1073741824.0))
+
+#define MS_TO_CDTIME_T(ms) ((cdtime_t) (((double) (ms)) * 1073741.824))
+#define CDTIME_T_TO_MS(t) ((long) (((double) (t)) / 1073741.824))
+#define US_TO_CDTIME_T(us) ((cdtime_t) (((double) (us)) * 1073.741824))
+#define CDTIME_T_TO_US(t) ((suseconds_t) (((double) (t)) / 1073.741824))
+#define NS_TO_CDTIME_T(ns) ((cdtime_t) (((double) (ns)) * 1.073741824))
+#define CDTIME_T_TO_NS(t) ((long) (((double) (t)) / 1.073741824))
+
+#define CDTIME_T_TO_TIMEVAL(cdt,tvp) do { \
+ (tvp)->tv_sec = CDTIME_T_TO_TIME_T (cdt); \
+ (tvp)->tv_usec = CDTIME_T_TO_US ((cdt) % 1073741824); \
+} while (0)
+#define TIMEVAL_TO_CDTIME_T(tv) (TIME_T_TO_CDTIME_T ((tv)->tv_sec) \
+ + US_TO_CDTIME_T ((tv)->tv_usec))
+
+#define CDTIME_T_TO_TIMESPEC(cdt,tsp) do { \
+ (tsp)->tv_sec = CDTIME_T_TO_TIME_T (cdt); \
+ (tsp)->tv_nsec = CDTIME_T_TO_NS ((cdt) % 1073741824); \
+} while (0)
+#define TIMESPEC_TO_CDTIME_T(ts) (TIME_T_TO_CDTIME_T ((ts)->tv_sec) \
+ + NS_TO_CDTIME_T ((ts)->tv_nsec))
+
+cdtime_t cdtime (void);
+
+#endif /* UTILS_TIME_H */
+/* vim: set sw=2 sts=2 et : */
diff --git a/src/varnish.c b/src/varnish.c
--- /dev/null
+++ b/src/varnish.c
@@ -0,0 +1,603 @@
+/**
+ * collectd - src/varnish.c
+ * Copyright (C) 2010 Jérôme Renard
+ * Copyright (C) 2010 Marc Fournier
+ * Copyright (C) 2010 Florian 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:
+ * Jérôme Renard <jerome.renard at gmail.com>
+ * Marc Fournier <marc.fournier at camptocamp.com>
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+/**
+ * Current list of what is monitored and what is not monitored (yet)
+ * {{{
+ * Field name Description Monitored
+ * ---------- ----------- ---------
+ * uptime Child uptime N
+ * client_conn Client connections accepted Y
+ * client_drop Connection dropped, no sess Y
+ * client_req Client requests received Y
+ * cache_hit Cache hits Y
+ * cache_hitpass Cache hits for pass Y
+ * cache_miss Cache misses Y
+ * backend_conn Backend conn. success Y
+ * backend_unhealthy Backend conn. not attempted Y
+ * backend_busy Backend conn. too many Y
+ * backend_fail Backend conn. failures Y
+ * backend_reuse Backend conn. reuses Y
+ * backend_toolate Backend conn. was closed Y
+ * backend_recycle Backend conn. recycles Y
+ * backend_unused Backend conn. unused Y
+ * fetch_head Fetch head Y
+ * fetch_length Fetch with Length Y
+ * fetch_chunked Fetch chunked Y
+ * fetch_eof Fetch EOF Y
+ * fetch_bad Fetch had bad headers Y
+ * fetch_close Fetch wanted close Y
+ * fetch_oldhttp Fetch pre HTTP/1.1 closed Y
+ * fetch_zero Fetch zero len Y
+ * fetch_failed Fetch failed Y
+ * n_sess_mem N struct sess_mem N
+ * n_sess N struct sess N
+ * n_object N struct object N
+ * n_vampireobject N unresurrected objects N
+ * n_objectcore N struct objectcore N
+ * n_objecthead N struct objecthead N
+ * n_smf N struct smf N
+ * n_smf_frag N small free smf N
+ * n_smf_large N large free smf N
+ * n_vbe_conn N struct vbe_conn N
+ * n_wrk N worker threads Y
+ * n_wrk_create N worker threads created Y
+ * n_wrk_failed N worker threads not created Y
+ * n_wrk_max N worker threads limited Y
+ * n_wrk_queue N queued work requests Y
+ * n_wrk_overflow N overflowed work requests Y
+ * n_wrk_drop N dropped work requests Y
+ * n_backend N backends N
+ * n_expired N expired objects N
+ * n_lru_nuked N LRU nuked objects N
+ * n_lru_saved N LRU saved objects N
+ * n_lru_moved N LRU moved objects N
+ * n_deathrow N objects on deathrow N
+ * losthdr HTTP header overflows N
+ * n_objsendfile Objects sent with sendfile N
+ * n_objwrite Objects sent with write N
+ * n_objoverflow Objects overflowing workspace N
+ * s_sess Total Sessions Y
+ * s_req Total Requests Y
+ * s_pipe Total pipe Y
+ * s_pass Total pass Y
+ * s_fetch Total fetch Y
+ * s_hdrbytes Total header bytes Y
+ * s_bodybytes Total body bytes Y
+ * sess_closed Session Closed N
+ * sess_pipeline Session Pipeline N
+ * sess_readahead Session Read Ahead N
+ * sess_linger Session Linger N
+ * sess_herd Session herd N
+ * shm_records SHM records Y
+ * shm_writes SHM writes Y
+ * shm_flushes SHM flushes due to overflow Y
+ * shm_cont SHM MTX contention Y
+ * shm_cycles SHM cycles through buffer Y
+ * sm_nreq allocator requests Y
+ * sm_nobj outstanding allocations Y
+ * sm_balloc bytes allocated Y
+ * sm_bfree bytes free Y
+ * sma_nreq SMA allocator requests Y
+ * sma_nobj SMA outstanding allocations Y
+ * sma_nbytes SMA outstanding bytes Y
+ * sma_balloc SMA bytes allocated Y
+ * sma_bfree SMA bytes free Y
+ * sms_nreq SMS allocator requests Y
+ * sms_nobj SMS outstanding allocations Y
+ * sms_nbytes SMS outstanding bytes Y
+ * sms_balloc SMS bytes allocated Y
+ * sms_bfree SMS bytes freed Y
+ * backend_req Backend requests made N
+ * n_vcl N vcl total N
+ * n_vcl_avail N vcl available N
+ * n_vcl_discard N vcl discarded N
+ * n_purge N total active purges N
+ * n_purge_add N new purges added N
+ * n_purge_retire N old purges deleted N
+ * n_purge_obj_test N objects tested N
+ * n_purge_re_test N regexps tested against N
+ * n_purge_dups N duplicate purges removed N
+ * hcb_nolock HCB Lookups without lock Y
+ * hcb_lock HCB Lookups with lock Y
+ * hcb_insert HCB Inserts Y
+ * esi_parse Objects ESI parsed (unlock) Y
+ * esi_errors ESI parse errors (unlock) Y
+ * }}}
+ */
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <varnish/varnishapi.h>
+
+/* {{{ user_config_s */
+struct user_config_s {
+ char *instance;
+
+ _Bool collect_cache;
+ _Bool collect_connections;
+ _Bool collect_esi;
+ _Bool collect_backend;
+ _Bool collect_fetch;
+ _Bool collect_hcb;
+ _Bool collect_shm;
+ _Bool collect_sma;
+ _Bool collect_sms;
+ _Bool collect_sm;
+ _Bool collect_totals;
+ _Bool collect_workers;
+};
+typedef struct user_config_s user_config_t; /* }}} */
+
+static _Bool have_instance = 0;
+
+static int varnish_submit (const char *plugin_instance, /* {{{ */
+ const char *category, const char *type, const char *type_instance, value_t value)
+{
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = &value;
+ vl.values_len = 1;
+
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+
+ sstrncpy (vl.plugin, "varnish", sizeof (vl.plugin));
+
+ if (plugin_instance == NULL)
+ plugin_instance = "default";
+
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+ "%s-%s", plugin_instance, category);
+
+ sstrncpy (vl.type, type, sizeof (vl.type));
+
+ if (type_instance != NULL)
+ sstrncpy (vl.type_instance, type_instance,
+ sizeof (vl.type_instance));
+
+ return (plugin_dispatch_values (&vl));
+} /* }}} int varnish_submit */
+
+static int varnish_submit_gauge (const char *plugin_instance, /* {{{ */
+ const char *category, const char *type, const char *type_instance,
+ uint64_t gauge_value)
+{
+ value_t value;
+
+ value.gauge = (gauge_t) gauge_value;
+
+ return (varnish_submit (plugin_instance, category, type, type_instance, value));
+} /* }}} int varnish_submit_gauge */
+
+static int varnish_submit_derive (const char *plugin_instance, /* {{{ */
+ const char *category, const char *type, const char *type_instance,
+ uint64_t derive_value)
+{
+ value_t value;
+
+ value.derive = (derive_t) derive_value;
+
+ return (varnish_submit (plugin_instance, category, type, type_instance, value));
+} /* }}} int varnish_submit_derive */
+
+static void varnish_monitor (const user_config_t *conf, struct varnish_stats *VSL_stats) /* {{{ */
+{
+ if (conf->collect_cache)
+ {
+ /* Cache hits */
+ varnish_submit_derive (conf->instance, "cache", "cache_result", "hit", VSL_stats->cache_hit);
+ /* Cache misses */
+ varnish_submit_derive (conf->instance, "cache", "cache_result", "miss", VSL_stats->cache_miss);
+ /* Cache hits for pass */
+ varnish_submit_derive (conf->instance, "cache", "cache_result", "hitpass", VSL_stats->cache_hitpass);
+ }
+
+ if (conf->collect_connections)
+ {
+ /* Client connections accepted */
+ varnish_submit_derive (conf->instance, "connections", "connections", "accepted", VSL_stats->client_conn);
+ /* Connection dropped, no sess */
+ varnish_submit_derive (conf->instance, "connections", "connections", "dropped" , VSL_stats->client_drop);
+ /* Client requests received */
+ varnish_submit_derive (conf->instance, "connections", "connections", "received", VSL_stats->client_req);
+ }
+
+ if (conf->collect_esi)
+ {
+ /* Objects ESI parsed (unlock) */
+ varnish_submit_derive (conf->instance, "esi", "total_operations", "parsed", VSL_stats->esi_parse);
+ /* ESI parse errors (unlock) */
+ varnish_submit_derive (conf->instance, "esi", "total_operations", "error", VSL_stats->esi_errors);
+ }
+
+ if (conf->collect_backend)
+ {
+ /* Backend conn. success */
+ varnish_submit_derive (conf->instance, "backend", "connections", "success" , VSL_stats->backend_conn);
+ /* Backend conn. not attempted */
+ varnish_submit_derive (conf->instance, "backend", "connections", "not-attempted", VSL_stats->backend_unhealthy);
+ /* Backend conn. too many */
+ varnish_submit_derive (conf->instance, "backend", "connections", "too-many" , VSL_stats->backend_busy);
+ /* Backend conn. failures */
+ varnish_submit_derive (conf->instance, "backend", "connections", "failures" , VSL_stats->backend_fail);
+ /* Backend conn. reuses */
+ varnish_submit_derive (conf->instance, "backend", "connections", "reuses" , VSL_stats->backend_reuse);
+ /* Backend conn. was closed */
+ varnish_submit_derive (conf->instance, "backend", "connections", "was-closed" , VSL_stats->backend_toolate);
+ /* Backend conn. recycles */
+ varnish_submit_derive (conf->instance, "backend", "connections", "recycled" , VSL_stats->backend_recycle);
+ /* Backend conn. unused */
+ varnish_submit_derive (conf->instance, "backend", "connections", "unused" , VSL_stats->backend_unused);
+ }
+
+ if (conf->collect_fetch)
+ {
+ /* Fetch head */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "head" , VSL_stats->fetch_head);
+ /* Fetch with length */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "length" , VSL_stats->fetch_length);
+ /* Fetch chunked */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "chunked" , VSL_stats->fetch_chunked);
+ /* Fetch EOF */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "eof" , VSL_stats->fetch_eof);
+ /* Fetch bad headers */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "bad_headers", VSL_stats->fetch_bad);
+ /* Fetch wanted close */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "close" , VSL_stats->fetch_close);
+ /* Fetch pre HTTP/1.1 closed */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "oldhttp" , VSL_stats->fetch_oldhttp);
+ /* Fetch zero len */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "zero" , VSL_stats->fetch_zero);
+ /* Fetch failed */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "failed" , VSL_stats->fetch_failed);
+ }
+
+ if (conf->collect_hcb)
+ {
+ /* HCB Lookups without lock */
+ varnish_submit_derive (conf->instance, "hcb", "cache_operation", "lookup_nolock", VSL_stats->hcb_nolock);
+ /* HCB Lookups with lock */
+ varnish_submit_derive (conf->instance, "hcb", "cache_operation", "lookup_lock", VSL_stats->hcb_lock);
+ /* HCB Inserts */
+ varnish_submit_derive (conf->instance, "hcb", "cache_operation", "insert", VSL_stats->hcb_insert);
+ }
+
+ if (conf->collect_shm)
+ {
+ /* SHM records */
+ varnish_submit_derive (conf->instance, "shm", "total_operations", "records" , VSL_stats->shm_records);
+ /* SHM writes */
+ varnish_submit_derive (conf->instance, "shm", "total_operations", "writes" , VSL_stats->shm_writes);
+ /* SHM flushes due to overflow */
+ varnish_submit_derive (conf->instance, "shm", "total_operations", "flushes" , VSL_stats->shm_flushes);
+ /* SHM MTX contention */
+ varnish_submit_derive (conf->instance, "shm", "total_operations", "contention", VSL_stats->shm_cont);
+ /* SHM cycles through buffer */
+ varnish_submit_derive (conf->instance, "shm", "total_operations", "cycles" , VSL_stats->shm_cycles);
+ }
+
+ if (conf->collect_sm)
+ {
+ /* allocator requests */
+ varnish_submit_derive (conf->instance, "sm", "total_requests", "nreq", VSL_stats->sm_nreq);
+ /* outstanding allocations */
+ varnish_submit_gauge (conf->instance, "sm", "requests", "outstanding", VSL_stats->sm_nobj);
+ /* bytes allocated */
+ varnish_submit_gauge (conf->instance, "sm", "bytes", "allocated", VSL_stats->sm_balloc);
+ /* bytes free */
+ varnish_submit_gauge (conf->instance, "sm", "bytes", "free", VSL_stats->sm_bfree);
+ }
+
+ if (conf->collect_sma)
+ {
+ /* SMA allocator requests */
+ varnish_submit_derive (conf->instance, "sma", "total_requests", "nreq", VSL_stats->sma_nreq);
+ /* SMA outstanding allocations */
+ varnish_submit_gauge (conf->instance, "sma", "requests", "outstanding", VSL_stats->sma_nobj);
+ /* SMA outstanding bytes */
+ varnish_submit_gauge (conf->instance, "sma", "bytes", "outstanding", VSL_stats->sma_nbytes);
+ /* SMA bytes allocated */
+ varnish_submit_gauge (conf->instance, "sma", "bytes", "allocated", VSL_stats->sma_balloc);
+ /* SMA bytes free */
+ varnish_submit_gauge (conf->instance, "sma", "bytes", "free" , VSL_stats->sma_bfree);
+ }
+
+ if (conf->collect_sms)
+ {
+ /* SMS allocator requests */
+ varnish_submit_derive (conf->instance, "sms", "total_requests", "allocator", VSL_stats->sms_nreq);
+ /* SMS outstanding allocations */
+ varnish_submit_gauge (conf->instance, "sms", "requests", "outstanding", VSL_stats->sms_nobj);
+ /* SMS outstanding bytes */
+ varnish_submit_gauge (conf->instance, "sms", "bytes", "outstanding", VSL_stats->sms_nbytes);
+ /* SMS bytes allocated */
+ varnish_submit_gauge (conf->instance, "sms", "bytes", "allocated", VSL_stats->sms_balloc);
+ /* SMS bytes freed */
+ varnish_submit_gauge (conf->instance, "sms", "bytes", "free", VSL_stats->sms_bfree);
+ }
+
+ if (conf->collect_totals)
+ {
+ /* Total Sessions */
+ varnish_submit_derive (conf->instance, "totals", "total_sessions", "sessions", VSL_stats->s_sess);
+ /* Total Requests */
+ varnish_submit_derive (conf->instance, "totals", "total_requests", "requests", VSL_stats->s_req);
+ /* Total pipe */
+ varnish_submit_derive (conf->instance, "totals", "total_operations", "pipe", VSL_stats->s_pipe);
+ /* Total pass */
+ varnish_submit_derive (conf->instance, "totals", "total_operations", "pass", VSL_stats->s_pass);
+ /* Total fetch */
+ varnish_submit_derive (conf->instance, "totals", "total_operations", "fetches", VSL_stats->s_fetch);
+ /* Total header bytes */
+ varnish_submit_derive (conf->instance, "totals", "total_bytes", "header-bytes", VSL_stats->s_hdrbytes);
+ /* Total body byte */
+ varnish_submit_derive (conf->instance, "totals", "total_bytes", "body-bytes", VSL_stats->s_bodybytes);
+ }
+
+ if (conf->collect_workers)
+ {
+ /* worker threads */
+ varnish_submit_gauge (conf->instance, "workers", "threads", "worker", VSL_stats->n_wrk);
+ /* worker threads created */
+ varnish_submit_gauge (conf->instance, "workers", "total_threads", "created", VSL_stats->n_wrk_create);
+ /* worker threads not created */
+ varnish_submit_gauge (conf->instance, "workers", "total_threads", "failed", VSL_stats->n_wrk_failed);
+ /* worker threads limited */
+ varnish_submit_gauge (conf->instance, "workers", "total_threads", "limited", VSL_stats->n_wrk_max);
+ /* queued work requests */
+ varnish_submit_gauge (conf->instance, "workers", "total_requests", "queued", VSL_stats->n_wrk_queue);
+ /* overflowed work requests */
+ varnish_submit_gauge (conf->instance, "workers", "total_requests", "overflowed", VSL_stats->n_wrk_overflow);
+ /* dropped work requests */
+ varnish_submit_gauge (conf->instance, "workers", "total_requests", "dropped", VSL_stats->n_wrk_drop);
+ }
+} /* }}} void varnish_monitor */
+
+static int varnish_read (user_data_t *ud) /* {{{ */
+{
+ struct varnish_stats *VSL_stats;
+ user_config_t *conf;
+
+ if ((ud == NULL) || (ud->data == NULL))
+ return (EINVAL);
+
+ conf = ud->data;
+
+ VSL_stats = VSL_OpenStats (conf->instance);
+ if (VSL_stats == NULL)
+ {
+ ERROR ("Varnish plugin : unable to load statistics");
+
+ return (-1);
+ }
+
+ varnish_monitor (conf, VSL_stats);
+
+ return (0);
+} /* }}} */
+
+static void varnish_config_free (void *ptr) /* {{{ */
+{
+ user_config_t *conf = ptr;
+
+ if (conf == NULL)
+ return;
+
+ sfree (conf->instance);
+ sfree (conf);
+} /* }}} */
+
+static int varnish_config_apply_default (user_config_t *conf) /* {{{ */
+{
+ if (conf == NULL)
+ return (EINVAL);
+
+ conf->collect_backend = 1;
+ conf->collect_cache = 1;
+ conf->collect_connections = 1;
+ conf->collect_esi = 0;
+ conf->collect_fetch = 0;
+ conf->collect_hcb = 0;
+ conf->collect_shm = 1;
+ conf->collect_sm = 0;
+ conf->collect_sma = 0;
+ conf->collect_sms = 0;
+ conf->collect_totals = 0;
+
+ return (0);
+} /* }}} int varnish_config_apply_default */
+
+static int varnish_init (void) /* {{{ */
+{
+ user_config_t *conf;
+ user_data_t ud;
+
+ if (have_instance)
+ return (0);
+
+ conf = malloc (sizeof (*conf));
+ if (conf == NULL)
+ return (ENOMEM);
+ memset (conf, 0, sizeof (*conf));
+
+ /* Default settings: */
+ conf->instance = NULL;
+
+ varnish_config_apply_default (conf);
+
+ ud.data = conf;
+ ud.free_func = varnish_config_free;
+
+ plugin_register_complex_read (/* group = */ "varnish",
+ /* name = */ "varnish/localhost",
+ /* callback = */ varnish_read,
+ /* interval = */ NULL,
+ /* user data = */ &ud);
+
+ return (0);
+} /* }}} int varnish_init */
+
+static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */
+{
+ user_config_t *conf;
+ user_data_t ud;
+ char callback_name[DATA_MAX_NAME_LEN];
+ int i;
+
+ conf = malloc (sizeof (*conf));
+ if (conf == NULL)
+ return (ENOMEM);
+ memset (conf, 0, sizeof (*conf));
+ conf->instance = NULL;
+
+ varnish_config_apply_default (conf);
+
+ if (ci->values_num == 1)
+ {
+ int status;
+
+ status = cf_util_get_string (ci, &conf->instance);
+ if (status != 0)
+ {
+ sfree (conf);
+ return (status);
+ }
+ assert (conf->instance != NULL);
+
+ if (strcmp ("localhost", conf->instance) == 0)
+ {
+ sfree (conf->instance);
+ conf->instance = NULL;
+ }
+ }
+ else if (ci->values_num > 1)
+ {
+ WARNING ("Varnish plugin: \"Instance\" blocks accept only "
+ "one argument.");
+ return (EINVAL);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("CollectCache", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_cache);
+ else if (strcasecmp ("CollectConnections", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_connections);
+ else if (strcasecmp ("CollectESI", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_esi);
+ else if (strcasecmp ("CollectBackend", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_backend);
+ else if (strcasecmp ("CollectFetch", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_fetch);
+ else if (strcasecmp ("CollectHCB", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_hcb);
+ else if (strcasecmp ("CollectSHM", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_shm);
+ else if (strcasecmp ("CollectSMA", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_sma);
+ else if (strcasecmp ("CollectSMS", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_sms);
+ else if (strcasecmp ("CollectSM", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_sm);
+ else if (strcasecmp ("CollectTotals", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_totals);
+ else if (strcasecmp ("CollectWorkers", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_workers);
+ else
+ {
+ WARNING ("Varnish plugin: Ignoring unknown "
+ "configuration option: \"%s\"",
+ child->key);
+ }
+ }
+
+ if (!conf->collect_cache
+ && !conf->collect_connections
+ && !conf->collect_esi
+ && !conf->collect_backend
+ && !conf->collect_fetch
+ && !conf->collect_hcb
+ && !conf->collect_shm
+ && !conf->collect_sma
+ && !conf->collect_sms
+ && !conf->collect_sm
+ && !conf->collect_totals
+ && !conf->collect_workers)
+ {
+ WARNING ("Varnish plugin: No metric has been configured for "
+ "instance \"%s\". Disabling this instance.",
+ (conf->instance == NULL) ? "localhost" : conf->instance);
+ return (EINVAL);
+ }
+
+ ssnprintf (callback_name, sizeof (callback_name), "varnish/%s",
+ (conf->instance == NULL) ? "localhost" : conf->instance);
+
+ ud.data = conf;
+ ud.free_func = varnish_config_free;
+
+ plugin_register_complex_read (/* group = */ "varnish",
+ /* name = */ callback_name,
+ /* callback = */ varnish_read,
+ /* interval = */ NULL,
+ /* user data = */ &ud);
+
+ have_instance = 1;
+
+ return (0);
+} /* }}} int varnish_config_instance */
+
+static int varnish_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Instance", child->key) == 0)
+ varnish_config_instance (child);
+ else
+ {
+ WARNING ("Varnish plugin: Ignoring unknown "
+ "configuration option: \"%s\"",
+ child->key);
+ }
+ }
+
+ return (0);
+} /* }}} int varnish_config */
+
+void module_register (void) /* {{{ */
+{
+ plugin_register_complex_config ("varnish", varnish_config);
+ plugin_register_init ("varnish", varnish_init);
+} /* }}} */
+
+/* vim: set sw=8 noet fdm=marker : */
diff --git a/src/write_http.c b/src/write_http.c
index ab8757ed67f151875bc806279425f3c86d971c87..1a0e4ef06d2fa13dc91cdb7faf315e6874e1d609 100644 (file)
--- a/src/write_http.c
+++ b/src/write_http.c
char send_buffer[4096];
size_t send_buffer_free;
size_t send_buffer_fill;
- time_t send_buffer_init_time;
+ cdtime_t send_buffer_init_time;
pthread_mutex_t send_lock;
};
memset (cb->send_buffer, 0, sizeof (cb->send_buffer));
cb->send_buffer_free = sizeof (cb->send_buffer);
cb->send_buffer_fill = 0;
- cb->send_buffer_init_time = time (NULL);
+ cb->send_buffer_init_time = cdtime ();
if (cb->format == WH_FORMAT_JSON)
{
return (0);
} /* }}} int wh_callback_init */
-static int wh_flush_nolock (int timeout, wh_callback_t *cb) /* {{{ */
+static int wh_flush_nolock (cdtime_t timeout, wh_callback_t *cb) /* {{{ */
{
int status;
- DEBUG ("write_http plugin: wh_flush_nolock: timeout = %i; "
+ DEBUG ("write_http plugin: wh_flush_nolock: timeout = %.3f; "
"send_buffer_fill = %zu;",
- timeout, cb->send_buffer_fill);
+ CDTIME_T_TO_DOUBLE (timeout),
+ cb->send_buffer_fill);
+ /* timeout == 0 => flush unconditionally */
if (timeout > 0)
{
- time_t now;
+ cdtime_t now;
- now = time (NULL);
+ now = cdtime ();
if ((cb->send_buffer_init_time + timeout) > now)
return (0);
}
{
if (cb->send_buffer_fill <= 0)
{
- cb->send_buffer_init_time = time (NULL);
+ cb->send_buffer_init_time = cdtime ();
return (0);
}
{
if (cb->send_buffer_fill <= 2)
{
- cb->send_buffer_init_time = time (NULL);
+ cb->send_buffer_init_time = cdtime ();
return (0);
}
return (status);
} /* }}} wh_flush_nolock */
-static int wh_flush (int timeout, /* {{{ */
+static int wh_flush (cdtime_t timeout, /* {{{ */
const char *identifier __attribute__((unused)),
user_data_t *user_data)
{
cb = data;
- wh_flush_nolock (/* timeout = */ -1, cb);
+ wh_flush_nolock (/* timeout = */ 0, cb);
curl_easy_cleanup (cb->curl);
sfree (cb->location);
sfree (cb);
} /* }}} void wh_callback_free */
-static int wh_value_list_to_string (char *buffer, /* {{{ */
- size_t buffer_size,
- const data_set_t *ds, const value_list_t *vl,
- wh_callback_t *cb)
-{
- size_t offset = 0;
- int status;
- int i;
- gauge_t *rates = NULL;
-
- assert (0 == strcmp (ds->type, vl->type));
-
- memset (buffer, 0, buffer_size);
-
-#define BUFFER_ADD(...) do { \
- status = ssnprintf (buffer + offset, buffer_size - offset, \
- __VA_ARGS__); \
- if (status < 1) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else if (((size_t) status) >= (buffer_size - offset)) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else \
- offset += ((size_t) status); \
-} while (0)
-
- BUFFER_ADD ("%lu", (unsigned long) vl->time);
-
- for (i = 0; i < ds->ds_num; i++)
- {
- if (ds->ds[i].type == DS_TYPE_GAUGE)
- BUFFER_ADD (":%f", vl->values[i].gauge);
- else if (cb->store_rates)
- {
- if (rates == NULL)
- rates = uc_get_rate (ds, vl);
- if (rates == NULL)
- {
- WARNING ("write_http plugin: "
- "uc_get_rate failed.");
- return (-1);
- }
- BUFFER_ADD (":%g", rates[i]);
- }
- else if (ds->ds[i].type == DS_TYPE_COUNTER)
- BUFFER_ADD (":%llu", vl->values[i].counter);
- else if (ds->ds[i].type == DS_TYPE_DERIVE)
- BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
- else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
- BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
- else
- {
- ERROR ("write_http plugin: Unknown data source type: %i",
- ds->ds[i].type);
- sfree (rates);
- return (-1);
- }
- } /* for ds->ds_num */
-
-#undef BUFFER_ADD
-
- sfree (rates);
- return (0);
-} /* }}} int wh_value_list_to_string */
-
static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{{ */
wh_callback_t *cb)
{
@@ -366,7 +298,7 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
/* Convert the values to an ASCII representation and put that into
* `values'. */
- status = wh_value_list_to_string (values, sizeof (values), ds, vl, cb);
+ status = format_values (values, sizeof (values), ds, vl, cb->store_rates);
if (status != 0) {
ERROR ("write_http plugin: error with "
"wh_value_list_to_string");
@@ -374,8 +306,10 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
}
command_len = (size_t) ssnprintf (command, sizeof (command),
- "PUTVAL %s interval=%i %s\r\n",
- key, vl->interval, values);
+ "PUTVAL %s interval=%.3f %s\r\n",
+ key,
+ CDTIME_T_TO_DOUBLE (vl->interval),
+ values);
if (command_len >= sizeof (command)) {
ERROR ("write_http plugin: Command buffer too small: "
"Need %zu bytes.", command_len + 1);
@@ -397,7 +331,7 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
if (command_len >= cb->send_buffer_free)
{
- status = wh_flush_nolock (/* timeout = */ -1, cb);
+ status = wh_flush_nolock (/* timeout = */ 0, cb);
if (status != 0)
{
pthread_mutex_unlock (&cb->send_lock);
@@ -449,7 +383,7 @@ static int wh_write_json (const data_set_t *ds, const value_list_t *vl, /* {{{ *
ds, vl, cb->store_rates);
if (status == (-ENOMEM))
{
- status = wh_flush_nolock (/* timeout = */ -1, cb);
+ status = wh_flush_nolock (/* timeout = */ 0, cb);
if (status != 0)
{
wh_reset_buffer (cb);
diff --git a/src/write_redis.c b/src/write_redis.c
--- /dev/null
+++ b/src/write_redis.c
@@ -0,0 +1,238 @@
+/**
+ * collectd - src/write_redis.c
+ * Copyright (C) 2010 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <ff at octo.it>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "configfile.h"
+
+#include <pthread.h>
+#include <credis.h>
+
+struct wr_node_s
+{
+ char name[DATA_MAX_NAME_LEN];
+
+ char *host;
+ int port;
+ int timeout;
+
+ REDIS conn;
+ pthread_mutex_t lock;
+};
+typedef struct wr_node_s wr_node_t;
+
+/*
+ * Functions
+ */
+static int wr_write (const data_set_t *ds, /* {{{ */
+ const value_list_t *vl,
+ user_data_t *ud)
+{
+ wr_node_t *node = ud->data;
+ char ident[512];
+ char key[512];
+ char value[512];
+ size_t value_size;
+ char *value_ptr;
+ int status;
+ int i;
+
+ status = FORMAT_VL (ident, sizeof (ident), vl);
+ if (status != 0)
+ return (status);
+ ssnprintf (key, sizeof (key), "collectd/%s", ident);
+
+ memset (value, 0, sizeof (value));
+ value_size = sizeof (value);
+ value_ptr = &value[0];
+
+#define APPEND(...) do { \
+ status = snprintf (value_ptr, value_size, __VA_ARGS__); \
+ if (((size_t) status) > value_size) \
+ { \
+ value_ptr += value_size; \
+ value_size = 0; \
+ } \
+ else \
+ { \
+ value_ptr += status; \
+ value_size -= status; \
+ } \
+} while (0)
+
+ APPEND ("%lu", (unsigned long) vl->time);
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ APPEND ("%llu", vl->values[i].counter);
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ APPEND ("%g", vl->values[i].gauge);
+ else if (ds->ds[i].type == DS_TYPE_DERIVE)
+ APPEND ("%"PRIi64, vl->values[i].derive);
+ else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+ APPEND ("%"PRIu64, vl->values[i].absolute);
+ else
+ assert (23 == 42);
+ }
+
+#undef APPEND
+
+ pthread_mutex_lock (&node->lock);
+
+ if (node->conn == NULL)
+ {
+ node->conn = credis_connect (node->host, node->port, node->timeout);
+ if (node->conn == NULL)
+ {
+ ERROR ("write_redis plugin: Connecting to host \"%s\" (port %i) failed.",
+ (node->host != NULL) ? node->host : "localhost",
+ (node->port != 0) ? node->port : 6379);
+ pthread_mutex_unlock (&node->lock);
+ return (-1);
+ }
+ }
+
+ /* "credis_zadd" doesn't handle a NULL pointer gracefully, so I'd rather
+ * have a meaningful assertion message than a normal segmentation fault. */
+ assert (node->conn != NULL);
+ status = credis_zadd (node->conn, key, (double) vl->time, value);
+
+ credis_sadd (node->conn, "collectd/values", ident);
+
+ pthread_mutex_unlock (&node->lock);
+
+ return (0);
+} /* }}} int wr_write */
+
+static void wr_config_free (void *ptr) /* {{{ */
+{
+ wr_node_t *node = ptr;
+
+ if (node == NULL)
+ return;
+
+ if (node->conn != NULL)
+ {
+ credis_close (node->conn);
+ node->conn = NULL;
+ }
+
+ sfree (node->host);
+ sfree (node);
+} /* }}} void wr_config_free */
+
+static int wr_config_node (oconfig_item_t *ci) /* {{{ */
+{
+ wr_node_t *node;
+ int status;
+ int i;
+
+ node = malloc (sizeof (*node));
+ if (node == NULL)
+ return (ENOMEM);
+ memset (node, 0, sizeof (*node));
+ node->host = NULL;
+ node->port = 0;
+ node->timeout = 1000;
+ node->conn = NULL;
+ pthread_mutex_init (&node->lock, /* attr = */ NULL);
+
+ status = cf_util_get_string_buffer (ci, node->name, sizeof (node->name));
+ if (status != 0)
+ {
+ sfree (node);
+ return (status);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Host", child->key) == 0)
+ status = cf_util_get_string (child, &node->host);
+ else if (strcasecmp ("Port", child->key) == 0)
+ {
+ status = cf_util_get_port_number (child);
+ if (status > 0)
+ {
+ node->port = status;
+ status = 0;
+ }
+ }
+ else if (strcasecmp ("Timeout", child->key) == 0)
+ status = cf_util_get_int (child, &node->timeout);
+ else
+ WARNING ("write_redis plugin: Ignoring unknown config option \"%s\".",
+ child->key);
+
+ if (status != 0)
+ break;
+ } /* for (i = 0; i < ci->children_num; i++) */
+
+ if (status == 0)
+ {
+ char cb_name[DATA_MAX_NAME_LEN];
+ user_data_t ud;
+
+ ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name);
+
+ ud.data = node;
+ ud.free_func = wr_config_free;
+
+ status = plugin_register_write (cb_name, wr_write, &ud);
+ }
+
+ if (status != 0)
+ wr_config_free (node);
+
+ return (status);
+} /* }}} int wr_config_node */
+
+static int wr_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Node", child->key) == 0)
+ wr_config_node (child);
+ else
+ WARNING ("write_redis plugin: Ignoring unknown "
+ "configuration option \"%s\" at top level.", child->key);
+ }
+
+ return (0);
+} /* }}} int wr_config */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("write_redis", wr_config);
+}
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */
diff --git a/src/zfs_arc.c b/src/zfs_arc.c
index 5f14e90981adda089fb2b94cd85b5094a4e451b2..bc2b0d2b4e6eab185d5d2687ceee80819d6b5aff 100644 (file)
--- a/src/zfs_arc.c
+++ b/src/zfs_arc.c
@@ -46,54 +46,48 @@ static void za_submit (const char* type, const char* type_instance, value_t* val
static void za_submit_gauge (const char* type, const char* type_instance, gauge_t value)
{
- value_t values[1];
+ value_t vv;
- values[0].gauge = value;
-
- za_submit (type, type_instance, values, STATIC_ARRAY_SIZE(values));
+ vv.gauge = value;
+ za_submit (type, type_instance, &vv, 1);
}
-static void za_submit_size (gauge_t size, gauge_t size_target, gauge_t limit_min, gauge_t limit_max)
+static void za_submit_derive (const char* type, const char* type_instance, derive_t dv)
{
- value_t values[4];
-
- values[0].gauge = size;
- values[1].gauge = size_target;
- values[2].gauge = limit_min;
- values[3].gauge = limit_max;
+ value_t vv;
- za_submit ("arc_size", "", values, STATIC_ARRAY_SIZE(values));
+ vv.derive = dv;
+ za_submit (type, type_instance, &vv, 1);
}
-static void za_submit_bytes (counter_t read, counter_t write)
+static void za_submit_ratio (const char* type_instance, gauge_t hits, gauge_t misses)
{
- value_t values[2];
+ gauge_t ratio = NAN;
- values[0].counter = read;
- values[1].counter = write;
+ if (!isfinite (hits) || (hits < 0.0))
+ hits = 0.0;
+ if (!isfinite (misses) || (misses < 0.0))
+ misses = 0.0;
- za_submit ("arc_l2_bytes", "", values, STATIC_ARRAY_SIZE(values));
-}
-
-static void za_submit_counts (char *type_instance, counter_t demand_data, counter_t demand_metadata,
- counter_t prefetch_data, counter_t prefetch_metadata)
-{
- value_t values[4];
+ if ((hits != 0.0) || (misses != 0.0))
+ ratio = hits / (hits + misses);
- values[0].counter = demand_data;
- values[1].counter = demand_metadata;
- values[2].counter = prefetch_data;
- values[3].counter = prefetch_metadata;
-
- za_submit ("arc_counts", type_instance, values, STATIC_ARRAY_SIZE(values));
+ za_submit_gauge ("cache_ratio", type_instance, ratio);
}
static int za_read (void)
{
- gauge_t arcsize, targetsize, minlimit, maxlimit, hits, misses, l2_size, l2_hits, l2_misses;
- counter_t demand_data_hits, demand_metadata_hits, prefetch_data_hits, prefetch_metadata_hits;
- counter_t demand_data_misses, demand_metadata_misses, prefetch_data_misses, prefetch_metadata_misses;
- counter_t l2_read_bytes, l2_write_bytes;
+ gauge_t arc_size, l2_size;
+ derive_t demand_data_hits,
+ demand_metadata_hits,
+ prefetch_data_hits,
+ prefetch_metadata_hits,
+ demand_data_misses,
+ demand_metadata_misses,
+ prefetch_data_misses,
+ prefetch_metadata_misses;
+ gauge_t arc_hits, arc_misses, arc_ratio, l2_hits, l2_misses, l2_ratio;
+ value_t l2_io[2];
get_kstat (&ksp, "zfs", 0, "arcstats");
if (ksp == NULL)
return (-1);
}
- arcsize = get_kstat_value(ksp, "size");
- targetsize = get_kstat_value(ksp, "c");
- minlimit = get_kstat_value(ksp, "c_min");
- maxlimit = get_kstat_value(ksp, "c_max");
+ /* Sizes */
+ arc_size = get_kstat_value(ksp, "size");
+ l2_size = get_kstat_value(ksp, "l2_size");
+
+ za_submit_gauge ("cache_size", "arc", arc_size);
+ za_submit_gauge ("cache_size", "L2", l2_size);
+ /* Hits / misses */
demand_data_hits = get_kstat_value(ksp, "demand_data_hits");
demand_metadata_hits = get_kstat_value(ksp, "demand_metadata_hits");
prefetch_data_hits = get_kstat_value(ksp, "prefetch_data_hits");
prefetch_data_misses = get_kstat_value(ksp, "prefetch_data_misses");
prefetch_metadata_misses = get_kstat_value(ksp, "prefetch_metadata_misses");
- hits = get_kstat_value(ksp, "hits");
- misses = get_kstat_value(ksp, "misses");
+ za_submit_derive ("cache_result", "demand_data-hit", demand_data_hits);
+ za_submit_derive ("cache_result", "demand_metadata-hit", demand_metadata_hits);
+ za_submit_derive ("cache_result", "prefetch_data-hit", prefetch_data_hits);
+ za_submit_derive ("cache_result", "prefetch_metadata-hit", prefetch_metadata_hits);
- l2_size = get_kstat_value(ksp, "l2_size");
- l2_read_bytes = get_kstat_value(ksp, "l2_read_bytes");
- l2_write_bytes = get_kstat_value(ksp, "l2_write_bytes");
- l2_hits = get_kstat_value(ksp, "l2_hits");
- l2_misses = get_kstat_value(ksp, "l2_misses");
+ za_submit_derive ("cache_result", "demand_data-miss", demand_data_misses);
+ za_submit_derive ("cache_result", "demand_metadata-miss", demand_metadata_misses);
+ za_submit_derive ("cache_result", "prefetch_data-miss", prefetch_data_misses);
+ za_submit_derive ("cache_result", "prefetch_metadata-miss", prefetch_metadata_misses);
+ /* Ratios */
+ arc_hits = (gauge_t) get_kstat_value(ksp, "hits");
+ arc_misses = (gauge_t) get_kstat_value(ksp, "misses");
+ l2_hits = (gauge_t) get_kstat_value(ksp, "l2_hits");
+ l2_misses = (gauge_t) get_kstat_value(ksp, "l2_misses");
- za_submit_size (arcsize, targetsize, minlimit, maxlimit);
- za_submit_gauge ("arc_l2_size", "", l2_size);
+ za_submit_ratio ("arc", arc_hits, arc_misses);
+ za_submit_ratio ("L2", l2_hits, l2_misses);
- za_submit_counts ("hits", demand_data_hits, demand_metadata_hits,
- prefetch_data_hits, prefetch_metadata_hits);
- za_submit_counts ("misses", demand_data_misses, demand_metadata_misses,
- prefetch_data_misses, prefetch_metadata_misses);
+ /* I/O */
+ l2_io[0].derive = get_kstat_value(ksp, "l2_read_bytes");
+ l2_io[1].derive = get_kstat_value(ksp, "l2_write_bytes");
- za_submit_gauge ("arc_ratio", "L1", hits / (hits + misses));
- za_submit_gauge ("arc_ratio", "L2", l2_hits / (l2_hits + l2_misses));
-
- za_submit_bytes (l2_read_bytes, l2_write_bytes);
+ za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
return (0);
-}
+} /* int za_read */
static int za_init (void) /* {{{ */
{