Merge branch 'collectd-4.10'
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sun, 13 Jun 2010 19:44:21 +0000 (21:44 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Sun, 13 Jun 2010 19:44:21 +0000 (21:44 +0200)
17 files changed:
AUTHORS
README
configure.in
src/Makefile.am
src/collectd.conf.in
src/collectd.conf.pod
src/configfile.c
src/configfile.h
src/df.c
src/interface.c
src/libvirt.c
src/swap.c
src/target_v5upgrade.c [new file with mode: 0644]
src/types.db
src/utils_threshold.c
src/utils_threshold.h
src/varnish.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 4568965..e83c2f8 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -72,6 +72,9 @@ Franck Lombardi
 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.
diff --git a/README b/README
index ade430c..17b62d8 100644 (file)
--- a/README
+++ b/README
@@ -650,6 +650,10 @@ Prerequisites
     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
 ------------------------------------
 
index 13a1f9d..22910aa 100644 (file)
@@ -104,9 +104,13 @@ AC_ARG_ENABLE(standards,
 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")
 
@@ -588,6 +592,55 @@ AC_CHECK_FUNCS(syslog, [have_syslog="yes"], [have_syslog="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"])
@@ -3637,6 +3690,98 @@ fi
 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=""
@@ -4342,6 +4487,7 @@ AC_PLUGIN([target_notification], [yes],        [The notification target])
 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])
@@ -4351,6 +4497,7 @@ AC_PLUGIN([unixsock],    [yes],                [Unixsock communication plugin])
 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])
@@ -4558,6 +4705,7 @@ Configuration:
     libstatgrab . . . . . $with_libstatgrab
     libtokyotyrant  . . . $with_libtokyotyrant
     libupsclient  . . . . $with_libupsclient
+    libvarnish  . . . . . $with_libvarnish
     libvirt . . . . . . . $with_libvirt
     libxml2 . . . . . . . $with_libxml2
     libxmms . . . . . . . $with_libxmms
@@ -4658,6 +4806,7 @@ Configuration:
     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
@@ -4667,6 +4816,7 @@ Configuration:
     uptime  . . . . . . . $enable_uptime
     users . . . . . . . . $enable_users
     uuid  . . . . . . . . $enable_uuid
+    varnish . . . . . . . $enable_varnish
     vmem  . . . . . . . . $enable_vmem
     vserver . . . . . . . $enable_vserver
     wireless  . . . . . . $enable_wireless
index c6b0538..00d0e20 100644 (file)
@@ -1042,6 +1042,14 @@ collectd_LDADD += "-dlopen" target_set.la
 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
@@ -1143,6 +1151,16 @@ collectd_LDADD += "-dlopen" uuid.la
 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
index d8e39db..9cdecc0 100644 (file)
@@ -11,7 +11,7 @@
 ##############################################################################
 
 #Hostname    "localhost"
-FQDNLookup   true
+#FQDNLookup   true
 #BaseDir     "@prefix@/var/lib/@PACKAGE_NAME@"
 #PIDFile     "@prefix@/var/run/@PACKAGE_NAME@.pid"
 #PluginDir   "@prefix@/lib/@PACKAGE_NAME@"
@@ -133,6 +133,7 @@ FQDNLookup   true
 #@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
@@ -390,6 +391,7 @@ FQDNLookup   true
 #      InterfaceDevice "name:device"
 #      IgnoreSelected false
 #      HostnameFormat name
+#      InterfaceFormat name
 #</Plugin>
 
 #<Plugin madwifi>
@@ -890,6 +892,27 @@ FQDNLookup   true
 #      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>
index cc448a0..dd08e28 100644 (file)
@@ -128,13 +128,8 @@ hostname will be determined using the L<gethostname(2)> system call.
 
 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>
 
@@ -1568,6 +1563,16 @@ You can also specify combinations of these fields. For example B<name uuid>
 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>
@@ -4576,6 +4581,13 @@ information.
          WarningMin 100000000
        </Type>
      </Plugin>
+
+     <Type "load">
+       DataSource "midterm"
+       FailureMax 4
+       Hits 3
+       Hysteresis 3
+     </Type>
    </Host>
  </Threshold>
 
@@ -4648,6 +4660,27 @@ percentage value, relative to the other data sources. This is helpful for
 example for the "df" type, where you may want to issue a warning when less than
 5E<nbsp>% of the total space is available. Defaults to B<false>.
 
+=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
index 787ad0e..46624dc 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * 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
@@ -96,7 +96,7 @@ static cf_global_option_t cf_global_options[] =
        {"BaseDir",     NULL, PKGLOCALSTATEDIR},
        {"PIDFile",     NULL, PIDFILE},
        {"Hostname",    NULL, NULL},
-       {"FQDNLookup",  NULL, "false"},
+       {"FQDNLookup",  NULL, "true"},
        {"Interval",    NULL, "10"},
        {"ReadThreads", NULL, "5"},
        {"Timeout",     NULL, "2"},
@@ -1009,11 +1009,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. */
index 432e09f..519a6ff 100644 (file)
@@ -2,7 +2,7 @@
 #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
@@ -103,6 +103,11 @@ int cf_util_get_int (const oconfig_item_t *ci, int *ret_value);
  * 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. */
index 9185ba4..61d0c28 100644 (file)
--- a/src/df.c
+++ b/src/df.c
@@ -61,7 +61,6 @@ 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 int df_init (void)
@@ -123,11 +122,7 @@ static int df_config (const char *key, const char *value)
        }
        else if (strcasecmp (key, "ReportReserved") == 0)
        {
-               if (IS_TRUE (value))
-                       report_reserved = true;
-               else
-                       report_reserved = false;
-
+               /* Nop for backwards compatibility. */
                return (0);
        }
        else if (strcasecmp (key, "ReportInodes") == 0)
@@ -144,28 +139,6 @@ static int df_config (const char *key, const char *value)
        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,
@@ -210,6 +183,9 @@ static int df_read (void)
        {
                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)
@@ -268,39 +244,22 @@ static int df_read (void)
 
                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)
index 1ba6c8c..177afba 100644 (file)
@@ -171,8 +171,8 @@ static void if_submit (const char *dev, const char *type,
        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 */
index bcbf0e6..44f3832 100644 (file)
@@ -43,6 +43,7 @@ static const char *config_keys[] = {
     "IgnoreSelected",
 
     "HostnameFormat",
+    "InterfaceFormat",
 
     NULL
 };
@@ -89,13 +90,14 @@ static int add_block_device (virDomainPtr dom, const char *path);
 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
@@ -110,6 +112,14 @@ enum hf_field {
 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;
 
@@ -215,7 +225,7 @@ lv_config (const char *key, const char *value)
 
         n = strsplit (value_copy, fields, HF_MAX_FIELDS);
         if (n < 1) {
-            free (value_copy);
+            sfree (value_copy);
             ERROR ("HostnameFormat: no fields");
             return -1;
         }
@@ -228,12 +238,12 @@ lv_config (const char *key, const char *value)
             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;
@@ -241,6 +251,18 @@ lv_config (const char *key, const char *value)
         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;
 }
@@ -310,7 +332,7 @@ lv_read (void)
 
         if (virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
                     NULL, 0) != 0) {
-            free (vinfo);
+            sfree (vinfo);
             continue;
         }
 
@@ -318,7 +340,7 @@ lv_read (void)
             vcpu_submit (vinfo[j].cpuTime,
                     t, domains[i], vinfo[j].number, "virt_vcpu");
 
-        free (vinfo);
+        sfree (vinfo);
     }
 
     /* Get block device stats for each domain. */
@@ -343,6 +365,10 @@ lv_read (void)
     /* 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,
@@ -352,22 +378,22 @@ lv_read (void)
        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);
+                   t, 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);
+                   t, 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);
+                   t, 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);
+                   t, interface_devices[i].dom, display_name);
     } /* for (nr_interface_devices) */
 
     return 0;
@@ -398,7 +424,7 @@ refresh_lists (void)
         n = virConnectListDomains (conn, domids, n);
         if (n < 0) {
             VIRT_ERROR (conn, "reading list of domains");
-            free (domids);
+            sfree (domids);
             return -1;
         }
 
@@ -482,38 +508,54 @@ refresh_lists (void)
 
             /* 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;
@@ -527,7 +569,7 @@ free_domains ()
     if (domains) {
         for (i = 0; i < nr_domains; ++i)
             virDomainFree (domains[i]);
-        free (domains);
+        sfree (domains);
     }
     domains = NULL;
     nr_domains = 0;
@@ -559,8 +601,8 @@ free_block_devices ()
 
     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;
@@ -583,7 +625,7 @@ add_block_device (virDomainPtr dom, const char *path)
         new_ptr = malloc (new_size);
 
     if (new_ptr == NULL) {
-        free (path_copy);
+        sfree (path_copy);
         return -1;
     }
     block_devices = new_ptr;
@@ -598,36 +640,43 @@ free_interface_devices ()
     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,7 +694,7 @@ 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;
 }
 
index e467818..e5cbf33 100644 (file)
@@ -76,8 +76,8 @@ static derive_t pagesize;
 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)
@@ -115,8 +115,9 @@ static int swap_init (void)
                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)
@@ -345,6 +346,74 @@ static int swap_read (void)
 /* #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;
@@ -353,18 +422,6 @@ static int swap_read (void)
        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)
        {
@@ -420,6 +477,7 @@ static int swap_read (void)
        swap_submit ("free", total - used, DS_TYPE_GAUGE);
 
        sfree (swap_entries);
+ #endif /* HAVE_SWAPCTL_THREE_ARGS */
 /* #endif HAVE_SWAPCTL */
 
 #elif defined(VM_SWAPUSAGE)
diff --git a/src/target_v5upgrade.c b/src/target_v5upgrade.c
new file mode 100644 (file)
index 0000000..e7f0599
--- /dev/null
@@ -0,0 +1,140 @@
+/**
+ * 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" */
+  memcpy (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;
+  memcpy (new_vl.type_instance, "used", sizeof (new_vl.type_instance));
+  plugin_dispatch_values (&new_vl);
+
+  new_vl.values[0].gauge = vl->values[1].gauge;
+  memcpy (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 */
+
+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));
+
+  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 : */
+
index 69301b2..143e72f 100644 (file)
@@ -13,8 +13,9 @@ ath_nodes             value:GAUGE:0:65535
 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
@@ -134,8 +135,9 @@ ps_stacksize                value:GAUGE:0:9223372036854775807
 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
@@ -155,7 +157,9 @@ time_dispersion             seconds:GAUGE:-1000000:1000000
 timeleft               timeleft:GAUGE:0:3600
 time_offset            seconds:GAUGE:-1000000:1000000
 total_bytes            value:DERIVE:0:U
+total_operations       value:DERIVE:0:U
 total_requests         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
index 090cc75..99309b9 100644 (file)
@@ -40,6 +40,7 @@
 #define UT_FLAG_INVERT  0x01
 #define UT_FLAG_PERSIST 0x02
 #define UT_FLAG_PERCENTAGE 0x04
+#define UT_FLAG_INTERESTING 0x08
 /* }}} */
 
 /*
@@ -217,60 +218,6 @@ static int ut_config_type_min (threshold_t *th, oconfig_item_t *ci)
   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)
@@ -330,6 +277,7 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
   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++)
   {
@@ -346,12 +294,14 @@ static int ut_config_type (const threshold_t *th_orig, oconfig_item_t *ci)
     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)
@@ -517,6 +467,7 @@ int ut_config (const oconfig_item_t *ci)
 
   th.hits = 0;
   th.hysteresis = 0;
+  th.flags = UT_FLAG_INTERESTING; /* interesting by default */
     
   for (i = 0; i < ci->children_num; i++)
   {
@@ -1028,6 +979,10 @@ int ut_check_interesting (const char *name)
   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);
index 8aaf34c..5955ca6 100644 (file)
@@ -39,7 +39,7 @@ typedef struct threshold_s
   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/varnish.c b/src/varnish.c
new file mode 100644 (file)
index 0000000..724b4fa
--- /dev/null
@@ -0,0 +1,596 @@
+/**
+ * collectd - src/varnish.c
+ * Copyright (C) 2010 Jerome Renard
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at verplant.org>
+ *   Jerome Renard <jerome.renard@gmail.com>
+ **/
+
+/**
+ * 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 *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)
+               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));
+
+       return (plugin_dispatch_values(&vl));
+} /* }}} int varnish_submit */
+
+static int varnish_submit_gauge (const char *plugin_instance, /* {{{ */
+               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, type, type_instance, value));
+} /* }}} int varnish_submit_gauge */
+
+static int varnish_submit_derive (const char *plugin_instance, /* {{{ */
+               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, 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_result", "hit"    , VSL_stats->cache_hit);
+               /* Cache misses */
+               varnish_submit_derive (conf->instance, "cache_result", "miss"   , VSL_stats->cache_miss);
+               /* Cache hits for pass */
+               varnish_submit_derive (conf->instance, "cache_result", "hitpass", VSL_stats->cache_hitpass);
+       }
+
+       if(conf->collect_connections)
+       {
+               /* Client connections accepted */
+               varnish_submit_derive (conf->instance, "connections", "client-accepted", VSL_stats->client_conn);
+               /* Connection dropped, no sess */
+               varnish_submit_derive (conf->instance, "connections", "client-dropped" , VSL_stats->client_drop);
+               /* Client requests received    */
+               varnish_submit_derive (conf->instance, "connections", "client-received", VSL_stats->client_req);
+       }
+
+       if(conf->collect_esi)
+       {
+               /* Objects ESI parsed (unlock) */
+               varnish_submit_derive (conf->instance, "total_operations", "esi-parsed", VSL_stats->esi_parse);
+               /* ESI parse errors (unlock)   */
+               varnish_submit_derive (conf->instance, "total_operations", "esi-error", VSL_stats->esi_errors);
+       }
+
+       if(conf->collect_backend)
+       {
+               /* Backend conn. success       */
+               varnish_submit_derive (conf->instance, "connections", "backend-success"      , VSL_stats->backend_conn);
+               /* Backend conn. not attempted */
+               varnish_submit_derive (conf->instance, "connections", "backend-not-attempted", VSL_stats->backend_unhealthy);
+               /* Backend conn. too many      */
+               varnish_submit_derive (conf->instance, "connections", "backend-too-many"     , VSL_stats->backend_busy);
+               /* Backend conn. failures      */
+               varnish_submit_derive (conf->instance, "connections", "backend-failures"     , VSL_stats->backend_fail);
+               /* Backend conn. reuses        */
+               varnish_submit_derive (conf->instance, "connections", "backend-reuses"       , VSL_stats->backend_reuse);
+               /* Backend conn. was closed    */
+               varnish_submit_derive (conf->instance, "connections", "backend-was-closed"   , VSL_stats->backend_toolate);
+               /* Backend conn. recycles      */
+               varnish_submit_derive (conf->instance, "connections", "backend-recycled"     , VSL_stats->backend_recycle);
+               /* Backend conn. unused        */
+               varnish_submit_derive (conf->instance, "connections", "backend-unused"       , VSL_stats->backend_unused);
+       }
+
+       if(conf->collect_fetch)
+       {
+               /* Fetch head                */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-head"       , VSL_stats->fetch_head);
+               /* Fetch with length         */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-length"     , VSL_stats->fetch_length);
+               /* Fetch chunked             */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-chunked"    , VSL_stats->fetch_chunked);
+               /* Fetch EOF                 */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-eof"        , VSL_stats->fetch_eof);
+               /* Fetch bad headers         */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-bad_headers", VSL_stats->fetch_bad);
+               /* Fetch wanted close        */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-close"      , VSL_stats->fetch_close);
+               /* Fetch pre HTTP/1.1 closed */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-oldhttp"    , VSL_stats->fetch_oldhttp);
+               /* Fetch zero len            */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-zero"       , VSL_stats->fetch_zero);
+               /* Fetch failed              */
+               varnish_submit_derive (conf->instance, "http_requests", "fetch-failed"     , VSL_stats->fetch_failed);
+       }
+
+       if(conf->collect_hcb)
+       {
+               /* HCB Lookups without lock */
+               varnish_submit_derive (conf->instance, "cache_operation", "lookup_nolock", VSL_stats->hcb_nolock);
+               /* HCB Lookups with lock    */
+               varnish_submit_derive (conf->instance, "cache_operation", "lookup_lock",   VSL_stats->hcb_lock);
+               /* HCB Inserts              */
+               varnish_submit_derive (conf->instance, "cache_operation", "insert",        VSL_stats->hcb_insert);
+       }
+
+       if(conf->collect_shm)
+       {
+               /* SHM records                 */
+               varnish_submit_derive (conf->instance, "total_operations", "shmlog-records"   , VSL_stats->shm_records);
+               /* SHM writes                  */
+               varnish_submit_derive (conf->instance, "total_operations", "shmlog-writes"    , VSL_stats->shm_writes);
+               /* SHM flushes due to overflow */
+               varnish_submit_derive (conf->instance, "total_operations", "shmlog-flushes"   , VSL_stats->shm_flushes);
+               /* SHM MTX contention          */
+               varnish_submit_derive (conf->instance, "total_operations", "shmlog-contention", VSL_stats->shm_cont);
+               /* SHM cycles through buffer   */
+               varnish_submit_derive (conf->instance, "total_operations", "shmlog-cycles"    , VSL_stats->shm_cycles);
+       }
+
+       if(conf->collect_sm)
+       {
+               /* allocator requests */
+               varnish_submit_derive (conf->instance, "total_requests", "storage-file",      VSL_stats->sm_nreq);
+               /* outstanding allocations */
+               varnish_submit_gauge (conf->instance, "requests", "storage-file-outstanding", VSL_stats->sm_nobj);
+               /* bytes allocated */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-file-allocated",      VSL_stats->sm_balloc);
+               /* bytes free */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-file-free",           VSL_stats->sm_bfree);
+       }
+
+       if(conf->collect_sma)
+       {
+               /* SMA allocator requests */
+               varnish_submit_derive (conf->instance, "total_requests", "storage-mem",      VSL_stats->sma_nreq);
+               /* SMA outstanding allocations */
+               varnish_submit_gauge (conf->instance, "requests", "storage-mem-outstanding", VSL_stats->sma_nobj);
+               /* SMA outstanding bytes */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-mem-outstanding",    VSL_stats->sma_nbytes);
+               /* SMA bytes allocated */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-mem-allocated",      VSL_stats->sma_balloc);
+               /* SMA bytes free */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-mem-free" ,          VSL_stats->sma_bfree);
+       }
+
+       if(conf->collect_sms)
+       {
+               /* SMS allocator requests */
+               varnish_submit_derive (conf->instance, "total_requests", "storage-synth",      VSL_stats->sms_nreq);
+               /* SMS outstanding allocations */
+               varnish_submit_gauge (conf->instance, "requests", "storage-synth-outstanding", VSL_stats->sms_nobj);
+               /* SMS outstanding bytes */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-synth-outstanding",    VSL_stats->sms_nbytes);
+               /* SMS bytes allocated */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-synth-allocated",      VSL_stats->sms_balloc);
+               /* SMS bytes freed */
+               varnish_submit_gauge (conf->instance, "bytes", "storage-synth-free",           VSL_stats->sms_bfree);
+       }
+
+       if(conf->collect_totals)
+       {
+               /* Total Sessions */
+               varnish_submit_derive (conf->instance, "total_counters", "sessions", VSL_stats->s_sess);
+               /* Total Requests */
+               varnish_submit_derive (conf->instance, "total_requests", "requests", VSL_stats->s_req);
+               /* Total pipe */
+               varnish_submit_derive (conf->instance, "total_operations", "pipe", VSL_stats->s_pipe);
+               /* Total pass */
+               varnish_submit_derive (conf->instance, "total_operations", "pass", VSL_stats->s_pass);
+               /* Total fetch */
+               varnish_submit_derive (conf->instance, "total_operations", "fetches", VSL_stats->s_fetch);
+               /* Total header bytes */
+               varnish_submit_derive (conf->instance, "total_bytes", "header-bytes", VSL_stats->s_hdrbytes);
+               /* Total body byte */
+               varnish_submit_derive (conf->instance, "total_bytes", "body-bytes", VSL_stats->s_bodybytes);
+       }
+
+       if(conf->collect_workers)
+       {
+               /* worker threads */
+               varnish_submit_gauge (conf->instance, "threads", "worker", VSL_stats->n_wrk);
+               /* worker threads created */
+               varnish_submit_gauge (conf->instance, "total_threads", "threads-created", VSL_stats->n_wrk_create);
+               /* worker threads not created */
+               varnish_submit_gauge (conf->instance, "total_threads", "threads-failed", VSL_stats->n_wrk_failed);
+               /* worker threads limited */
+               varnish_submit_gauge (conf->instance, "total_threads", "threads-limited", VSL_stats->n_wrk_max);
+               /* queued work requests */
+               varnish_submit_gauge (conf->instance, "total_requests", "worker-queued", VSL_stats->n_wrk_queue);
+               /* overflowed work requests */
+               varnish_submit_gauge (conf->instance, "total_requests", "worker-overflowed", VSL_stats->n_wrk_overflow);
+               /* dropped work requests */
+               varnish_submit_gauge (conf->instance, "total_requests", "worker-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 : */