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.
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
------------------------------------
/*
* 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;
/*
* 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);
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(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"])
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=""
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])
libstatgrab . . . . . $with_libstatgrab
libtokyotyrant . . . $with_libtokyotyrant
libupsclient . . . . $with_libupsclient
+ libvarnish . . . . . $with_libvarnish
libvirt . . . . . . . $with_libvirt
libxml2 . . . . . . . $with_libxml2
libxmms . . . . . . . $with_libxmms
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
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);
}
}
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;
# 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
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
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
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
/**
* 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
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) */
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
##############################################################################
#Hostname "localhost"
-FQDNLookup true
+#FQDNLookup true
#BaseDir "@prefix@/var/lib/@PACKAGE_NAME@"
#PIDFile "@prefix@/var/run/@PACKAGE_NAME@.pid"
#PluginDir "@prefix@/lib/@PACKAGE_NAME@"
#@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
# InterfaceDevice "name:device"
# IgnoreSelected false
# HostnameFormat name
+# InterfaceFormat name
#</Plugin>
#<Plugin madwifi>
# 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>
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>
(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>
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,
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
=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
/**
* 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"},
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. */
#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
* 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. */
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)
return (0);
}
- else if (strcasecmp (key, "ReportReserved") == 0)
- {
- if (IS_TRUE (value))
- report_reserved = true;
- else
- report_reserved = false;
-
- return (0);
- }
else if (strcasecmp (key, "ReportInodes") == 0)
{
if (IS_TRUE (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,
{
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)
{
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)
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]);
}
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 }}} */
/**
* 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);
}
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 */
"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;
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 (virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
NULL, 0) != 0) {
- free (vinfo);
+ sfree (vinfo);
continue;
}
vcpu_submit (vinfo[j].cpuTime,
t, domains[i], vinfo[j].number, "virt_vcpu");
- free (vinfo);
+ sfree (vinfo);
}
/* Get block device stats for each domain. */
/* 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);
+ 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;
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++;
}
}
ssnprintf (name, n, "%s:%s", domname, devpath);
r = ignorelist_match (il, name);
- free (name);
+ sfree (name);
return r;
}
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 (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 */
/* }}} End of configuration handling functions */
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)
-{
- 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)
+static void derive_submit (const char *type, const char *type_instance,
+ derive_t value, 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)
{
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);
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.",
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)
--- /dev/null
+/**
+ * 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 */
+
+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));
+
+ 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 : */
+
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
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_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
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));
(*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;
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')))
{
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;
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;
# include <pcap.h>
#endif
+#define DNS_MSG_HDR_SZ 12
+
#define T_MAX 65536
#define OP_MAX 16
#define C_MAX 65536
#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);
gauge_t failure_min;
gauge_t failure_max;
gauge_t hysteresis;
- int flags;
+ unsigned int flags;
int hits;
struct threshold_s *next;
} threshold_t;
--- /dev/null
+/**
+ * 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 *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 : */