author | Florian Forster <octo@collectd.org> | |
Sat, 13 Jul 2013 09:24:27 +0000 (11:24 +0200) | ||
committer | Florian Forster <octo@collectd.org> | |
Sat, 13 Jul 2013 09:24:27 +0000 (11:24 +0200) |
Conflicts:
src/plugin.c
src/plugin.c
27 files changed:
index 45645d1a26e52700130ed68c6dc7042307f27895..adb74813b3559cfbf3f677a05fe77ef195432ff2 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
especially a nasty bug in the network plugin.
- Wireshark dissector.
+Chad Malfait <malfaitc at yahoo.com>
+ - LVM plugin.
+
Chris Lundquist <clundquist at bluebox.net>
- Improvements to the write_mongodb plugin.
Edward “Koko” Konetzko <konetzed at quixoticagony.com>
- fscache plugin.
+Evan Felix <evan.felix at pnnl.gov>
+ - mic plugin.
+
Fabian Linzberger <e at lefant.net>
- Percentage aggregation for `collectd-nagios'.
Jason Pepas <cell at ices.utexas.edu>
- nfs plugin.
+J. Javier Maestro <jjmaestro at ieee.org>
+ - Write-Graphite plugin: UDP support and LogSendErrors flag.
+
Jérôme Renard <jerome.renard at gmail.com>
- varnish plugin.
Michael Stapelberg <michael+git at stapelberg.de>
- OpenBSD port of the tcpconns plugin.
+ - cgroups plugin.
Michał Mirosław <mirq-linux at rere.qmqm.pl>
- thermal plugin.
Vincent Stehlé <vincent.stehle at free.fr>
- hddtemp plugin.
+Xin Li <delphij at freebsd.org>
+ - FreeBSD port of the ZFS-ARC plugin.
+
collectd is available at:
<http://collectd.org/>
index c3c454720484f71c3915bf6f0917ce2e27dd93ae..3f65963ae353a7e4dc3294acb27801025f895f94 100644 (file)
--- a/README
+++ b/README
Name server and resolver statistics from the `statistics-channel'
interface of BIND 9.5, 9,6 and later.
+ - cgroups
+ CPU accounting information for process groups under Linux.
+
- conntrack
Number of nf_conntrack entries.
- libvirt
CPU, memory, disk and network I/O statistics from virtual machines.
+ - lvm
+ Size of “Logical Volumes” (LV) and “Volume Groups” (VG) of Linux'
+ “Logical Volume Manager” (LVM).
+
- madwifi
Queries very detailed usage statistics from wireless LAN adapters and
interfaces that use the Atheros chipset and the MadWifi driver.
Memory utilization: Memory occupied by running processes, page cache,
buffer cache and free.
+ - mic
+ Collects CPU usage, memory usage, temperatures and power consumption from
+ Intel Many Integrated Core (MIC) CPUs.
+
- modbus
Reads values from Modbus/TCP enabled devices. Supports reading values
from multiple "slaves" so gateway devices can be used.
done.
- write_graphite
- Sends data to Carbon, the storage layer of Graphite.
+ Sends data to Carbon, the storage layer of Graphite using TCP or UDP. It
+ can be configured to avoid logging send errors (especially useful when
+ using UDP).
- write_http
Sends the values collected by collectd to a web-server using HTTP POST
diff --git a/configure.in b/configure.in
index a62d608bf21fe35ac40df7662f6c64ea67a24264..27c6cd316b916a0047cfe389face9b5b40d0af9b 100644 (file)
--- a/configure.in
+++ b/configure.in
AC_DEFINE([KERNEL_AIX], 1, [True if program is to be compiled for a AIX kernel])
ac_system="AIX"
;;
+ *freebsd*)
+ AC_DEFINE([KERNEL_FREEBSD], 1, [True if program is to be compiled for a FreeBSD kernel])
+ ac_system="FreeBSD"
+ ;;
*)
ac_system="unknown"
esac
m4_divert_once([HELP_WITH], [
collectd additional packages:])
+AM_CONDITIONAL([BUILD_FREEBSD],[test "x$x$ac_system" = "xFreeBSD"])
+
AM_CONDITIONAL([BUILD_AIX],[test "x$x$ac_system" = "xAIX"])
if test "x$ac_system" = "xAIX"
AM_CONDITIONAL(BUILD_WITH_JAVA, test "x$with_java" = "xyes")
# }}}
+# --with-liblvm2app {{{
+with_liblvm2app_cppflags=""
+with_liblvm2app_ldflags=""
+AC_ARG_WITH(liblvm2app, [AS_HELP_STRING([--with-liblvm2app@<:@=PREFIX@:>@], [Path to liblvm2app.])],
+[
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ then
+ with_liblvm2app_cppflags="-I$withval/include"
+ with_liblvm2app_ldflags="-L$withval/lib"
+ with_liblvm2app="yes"
+ else
+ with_liblvm2app="$withval"
+ fi
+],
+[
+ with_liblvm2app="yes"
+])
+if test "x$with_liblvm2app" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
+
+ AC_CHECK_HEADERS(lvm2app.h, [with_liblvm2app="yes"], [with_liblvm2app="no (lvm2app.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+
+if test "x$with_liblvm2app" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
+ LDFLAGS="$LDFLAGS $with_liblvm2app_ldflags"
+
+ AC_CHECK_LIB(lvm2app, lvm_init, [with_liblvm2app="yes"], [with_liblvm2app="no (Symbol 'lvm_init' not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_liblvm2app" = "xyes"
+then
+ BUILD_WITH_LIBLVM2APP_CPPFLAGS="$with_liblvm2app_cppflags"
+ BUILD_WITH_LIBLVM2APP_LDFLAGS="$with_liblvm2app_ldflags"
+ BUILD_WITH_LIBLVM2APP_LIBS="-llvm2app"
+ AC_SUBST(BUILD_WITH_LIBLVM2APP_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBLVM2APP_LDFLAGS)
+ AC_SUBST(BUILD_WITH_LIBLVM2APP_LIBS)
+ AC_DEFINE(HAVE_LIBLVM2APP, 1, [Define if liblvm2app is present and usable.])
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBLVM2APP, test "x$with_liblvm2app" = "xyes")
+# }}}
+
# --with-libmemcached {{{
with_libmemcached_cppflags=""
with_libmemcached_ldflags=""
AM_CONDITIONAL(BUILD_WITH_LIBYAJL, test "x$with_libyajl" = "xyes")
# }}}
+# --with-mic {{{
+with_mic_cflags="-I/opt/intel/mic/sysmgmt/sdk/include"
+with_mic_ldpath="-L/opt/intel/mic/sysmgmt/sdk/lib/Linux"
+with_mic_libs=""
+AC_ARG_WITH(mic,[AS_HELP_STRING([--with-mic@<:@=PREFIX@:>@], [Path to Intel MIC Access API.])],
+[
+ if test "x$withval" = "xno"
+ then
+ with_mic="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_mic="yes"
+ else if test -d "$with_mic/lib"
+ then
+ AC_MSG_NOTICE([Not checking for Intel Mic: Manually configured])
+ with_mic_cflags="-I$withval/include"
+ with_mic_ldpath="-L$withval/lib/Linux"
+ with_mic_libs="-lMicAccessSDK -lscif -lpthread"
+ with_mic="yes"
+ fi; fi; fi
+],
+[with_mic="yes"])
+if test "x$with_mic" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_mic_cflags"
+ AC_CHECK_HEADERS(MicAccessApi.h,[],[with_mic="no (MicAccessApi not found)"])
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_mic" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
+
+ CPPFLAGS="$CPPFLAGS $with_mic_cflags"
+ LDFLAGS="$LDFLAGS $with_mic_ldpath"
+
+ AC_CHECK_LIB(MicAccessSDK, MicInitAPI,
+ [with_mic_ldpath="$with_mic_ldpath"
+ with_mic_libs="-lMicAccessSDK -lscif -lpthread"],
+ [with_mic="no (symbol MicInitAPI not found)"],[-lscif -lpthread])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
+fi
+
+if test "x$with_mic" = "xyes"
+then
+ BUILD_WITH_MIC_CPPFLAGS="$with_mic_cflags"
+ BUILD_WITH_MIC_LIBPATH="$with_mic_ldpath"
+ BUILD_WITH_MIC_LDADD="$with_mic_libs"
+ AC_SUBST(BUILD_WITH_MIC_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_MIC_LIBPATH)
+ AC_SUBST(BUILD_WITH_MIC_LDADD)
+fi
+#}}}
+
# --with-libvarnish {{{
with_libvarnish_cppflags=""
with_libvarnish_cflags=""
plugin_ascent="no"
plugin_battery="no"
plugin_bind="no"
+plugin_cgroups="no"
plugin_conntrack="no"
plugin_contextswitch="no"
plugin_cpu="no"
plugin_battery="yes"
plugin_conntrack="yes"
plugin_contextswitch="yes"
+ plugin_cgroups="yes"
plugin_cpu="yes"
plugin_cpufreq="yes"
plugin_disk="yes"
plugin_interface="yes"
plugin_irq="yes"
plugin_load="yes"
+ plugin_lvm="yes"
plugin_memory="yes"
plugin_nfs="yes"
plugin_numa="yes"
plugin_tcpconns="yes"
fi
+# FreeBSD
+
+if test "x$ac_system" = "xFreeBSD"
+then
+ plugin_zfs_arc="yes"
+fi
+
+
if test "x$with_perfstat" = "xyes"
then
plugin_cpu="yes"
AC_PLUGIN([curl], [$with_libcurl], [CURL generic web statistics])
AC_PLUGIN([curl_json], [$plugin_curl_json], [CouchDB statistics])
AC_PLUGIN([curl_xml], [$plugin_curl_xml], [CURL generic xml statistics])
+AC_PLUGIN([cgroups], [$plugin_cgroups], [CGroups CPU usage accounting])
AC_PLUGIN([dbi], [$with_libdbi], [General database statistics])
AC_PLUGIN([df], [$plugin_df], [Filesystem usage statistics])
AC_PLUGIN([disk], [$plugin_disk], [Disk usage statistics])
AC_PLUGIN([load], [$plugin_load], [System load])
AC_PLUGIN([logfile], [yes], [File logging plugin])
AC_PLUGIN([lpar], [$with_perfstat], [AIX logical partitions statistics])
+AC_PLUGIN([lvm], [$with_liblvm2app], [LVM statistics])
AC_PLUGIN([madwifi], [$have_linux_wireless_h], [Madwifi wireless statistics])
AC_PLUGIN([match_empty_counter], [yes], [The empty counter match])
AC_PLUGIN([match_hashed], [yes], [The hashed match])
AC_PLUGIN([memcachec], [$with_libmemcached], [memcachec statistics])
AC_PLUGIN([memcached], [yes], [memcached statistics])
AC_PLUGIN([memory], [$plugin_memory], [Memory usage])
+AC_PLUGIN([mic], [$with_mic], [Intel Many Integrated Core stats])
AC_PLUGIN([modbus], [$with_libmodbus], [Modbus plugin])
AC_PLUGIN([multimeter], [$plugin_multimeter], [Read multimeter values])
AC_PLUGIN([mysql], [$with_libmysql], [MySQL statistics])
Configuration:
Libraries:
+ intel mic . . . . . . $with_mic
libcurl . . . . . . . $with_libcurl
libdbi . . . . . . . $with_libdbi
libcredis . . . . . . $with_libcredis
bind . . . . . . . . $enable_bind
conntrack . . . . . . $enable_conntrack
contextswitch . . . . $enable_contextswitch
+ cgroups . . . . . . . $enable_cgroups
cpu . . . . . . . . . $enable_cpu
cpufreq . . . . . . . $enable_cpufreq
csv . . . . . . . . . $enable_csv
load . . . . . . . . $enable_load
logfile . . . . . . . $enable_logfile
lpar... . . . . . . . $enable_lpar
+ lvm . . . . . . . . . $enable_lvm
madwifi . . . . . . . $enable_madwifi
match_empty_counter . $enable_match_empty_counter
match_hashed . . . . $enable_match_hashed
index 9af0fb008a72790e48562e7e6440c3bec8c6dd2a..809f19dee65d2ec89a030a762bacb5e98041d8aa 100644 (file)
"""
import socket,struct,sys
-try:
- from io import StringIO
-except ImportError:
- from cStringIO import StringIO
+import platform
+if platform.python_version() < '2.8.0':
+ # Python 2.7 and below io.StringIO does not like unicode
+ from StringIO import StringIO
+else:
+ try:
+ from io import StringIO
+ except ImportError:
+ from cStringIO import StringIO
from datetime import datetime
from copy import deepcopy
assert double.size == number.size
result = []
- for dstype in buf[header.size+short.size:off]:
+ for dstype in [ord(x) for x in buf[header.size+short.size:off]]:
if dstype == DS_TYPE_COUNTER:
result.append((dstype, number.unpack_from(buf, off)[0]))
off += valskip
index 1b8e6b174ed8d8ad1a7abc1237842e03d5908075..5cd4ab8ee6de5d7ba3ebadd83418765dea9d39e5 100644 (file)
self._sock.send(c + "\n")
status_message = self._readline()
if self.noisy:
- print "[recive] %s" % status_message
+ print "[receive] %s" % status_message
if not status_message:
return None
code, message = status_message.split(' ', 1)
index ec55a52a55d75e68613e06b35e989601d0d25bd5..abdb168f15d28cce78db59ca29589d2ef0a40e5d 100644 (file)
service="collectd"
CONFIG=/etc/collectd.conf
COLLECTD=/usr/sbin/collectd
-COLLECTDMONPID=/var/run/collectdmon.pid
+COLLECTDMONPIDDIR="/var/run"
+COLLECTDMONPID="$COLLECTDMONPIDDIR/collectdmon.pid"
if [ -r /etc/sysconfig/$service ]; then
. /etc/sysconfig/$service
fi
+if [[ ! -d $COLLECTDMONPIDDIR ]]; then
+ mkdir -p $COLLECTDMONPIDDIR
+ [ -n "${RUNAS}" ] && chown "${RUNAS}:" "$COLLECTDMONPIDDIR"
+fi
+
check_config() {
if test ! -r "$CONFIG"; then
return 2
echo $"not starting due to configuration error"
failure $"not starting $service due to configuration error"
else
- daemon $prog -P $COLLECTDMONPID -c $COLLECTD -- -C "$CONFIG" $ARGS
+ daemon --user "${RUNAS:-root}" $prog -P $COLLECTDMONPID -c $COLLECTD -- -C "$CONFIG" $ARGS
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$service
}
stop () {
echo -n $"Stopping collectd: "
- killproc $prog
+ killproc -p $COLLECTDMONPID $prog
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$service
stop
;;
status)
- status $prog
+ status -p $COLLECTDMONPID $prog
;;
restart|reload)
check_config
fi
;;
condrestart)
- [ -f /var/lock/subsys/$prog ] && restart || :
+ [ -f /var/lock/subsys/$service ] && restart || :
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
diff --git a/src/Makefile.am b/src/Makefile.am
index 2bebec55c6d88ff320f94689c4eb795ead97a7cf..c3e596d4a5fea92d6853521fb9ee19458c5a94d4 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
collectd_DEPENDENCIES += bind.la
endif
+if BUILD_PLUGIN_CGROUPS
+pkglib_LTLIBRARIES += cgroups.la
+cgroups_la_SOURCES = cgroups.c utils_mount.c utils_mount.h
+cgroups_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" cgroups.la
+collectd_DEPENDENCIES += cgroups.la
+endif
+
if BUILD_PLUGIN_CONNTRACK
pkglib_LTLIBRARIES += conntrack.la
conntrack_la_SOURCES = conntrack.c
lpar_la_LIBADD = -lperfstat
endif
+if BUILD_PLUGIN_LVM
+pkglib_LTLIBRARIES += lvm.la
+lvm_la_SOURCES = lvm.c
+lvm_la_LDFLAGS = -module -avoid-version
+lvm_la_LIBADD = $(BUILD_WITH_LIBLVM2APP_LIBS)
+collectd_LDADD += "-dlopen" lvm.la
+collectd_DEPENDENCIES += lvm.la
+endif
+
if BUILD_PLUGIN_MADWIFI
pkglib_LTLIBRARIES += madwifi.la
madwifi_la_SOURCES = madwifi.c madwifi.h
collectd_DEPENDENCIES += uuid.la
endif
+if BUILD_PLUGIN_MIC
+pkglib_LTLIBRARIES += mic.la
+mic_la_SOURCES = mic.c
+mic_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_MIC_LIBPATH)
+mic_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_MIC_CPPFLAGS)
+mic_la_LIBADD = $(BUILD_WITH_MIC_LDADD)
+collectd_LDADD += "-dlopen" mic.la
+collectd_DEPENDENCIES += mic.la
+endif
+
if BUILD_PLUGIN_VARNISH
pkglib_LTLIBRARIES += varnish.la
varnish_la_SOURCES = varnish.c
zfs_arc_la_SOURCES = zfs_arc.c
zfs_arc_la_CFLAGS = $(AM_CFLAGS)
zfs_arc_la_LDFLAGS = -module -avoid-version
+if BUILD_FREEBSD
+zfs_arc_la_LIBADD = -lm
+else
zfs_arc_la_LIBADD = -lkstat
+endif
collectd_LDADD += "-dlopen" zfs_arc.la
collectd_DEPENDENCIES += zfs_arc.la
endif
diff --git a/src/amqp.c b/src/amqp.c
index 767a8776bbfb07ce2a26f932cf7fb5da4d22d047..edd4f749396bbb14c501792b62db70d188ade0de 100644 (file)
--- a/src/amqp.c
+++ b/src/amqp.c
/* publish only */
conf->delivery_mode = CAMQP_DM_VOLATILE;
conf->store_rates = 0;
+ conf->graphite_flags = 0;
/* publish & graphite only */
conf->prefix = NULL;
conf->postfix = NULL;
}
else if ((strcasecmp ("Format", child->key) == 0) && publish)
status = camqp_config_set_format (child, conf);
+ else if ((strcasecmp ("GraphiteSeparateInstances", child->key) == 0) && publish)
+ status = cf_util_get_flag (child, &conf->graphite_flags,
+ GRAPHITE_SEPARATE_INSTANCES);
+ else if ((strcasecmp ("GraphiteAlwaysAppendDS", child->key) == 0) && publish)
+ status = cf_util_get_flag (child, &conf->graphite_flags,
+ GRAPHITE_ALWAYS_APPEND_DS);
else if ((strcasecmp ("GraphitePrefix", child->key) == 0) && publish)
status = cf_util_get_string (child, &conf->prefix);
else if ((strcasecmp ("GraphitePostfix", child->key) == 0) && publish)
diff --git a/src/cgroups.c b/src/cgroups.c
--- /dev/null
+++ b/src/cgroups.c
@@ -0,0 +1,251 @@
+/**
+ * collectd - src/cgroups.c
+ * Copyright (C) 2011 Michael Stapelberg
+ * Copyright (C) 2013 Florian Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the license is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Michael Stapelberg <michael at stapelberg.de>
+ * Florian Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_mount.h"
+#include "utils_ignorelist.h"
+
+static char const *config_keys[] =
+{
+ "CGroup",
+ "IgnoreSelected"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static ignorelist_t *il_cgroup = NULL;
+
+__attribute__ ((nonnull(1)))
+__attribute__ ((nonnull(2)))
+static void cgroups_submit_one (char const *plugin_instance,
+ char const *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, "cgroups", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "cpu", sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance,
+ sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* void cgroups_submit_one */
+
+/*
+ * This callback reads the user/system CPU time for each cgroup.
+ */
+static int read_cpuacct_procs (const char *dirname, char const *cgroup_name,
+ void *user_data)
+{
+ char abs_path[PATH_MAX];
+ struct stat statbuf;
+ char buf[1024];
+ int status;
+
+ FILE *fh;
+
+ if (ignorelist_match (il_cgroup, cgroup_name))
+ return (0);
+
+ ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, cgroup_name);
+
+ status = lstat (abs_path, &statbuf);
+ if (status != 0)
+ {
+ ERROR ("cgroups plugin: stat (\"%s\") failed.",
+ abs_path);
+ return (-1);
+ }
+
+ /* We are only interested in directories, so skip everything else. */
+ if (!S_ISDIR (statbuf.st_mode))
+ return (0);
+
+ ssnprintf (abs_path, sizeof (abs_path), "%s/%s/cpuacct.stat",
+ dirname, cgroup_name);
+ fh = fopen (abs_path, "r");
+ if (fh == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("cgroups pluign: fopen (\"%s\") failed: %s",
+ abs_path,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ while (fgets (buf, sizeof (buf), fh) != NULL)
+ {
+ char *fields[8];
+ int numfields = 0;
+ char *key;
+ size_t key_len;
+ value_t value;
+
+ /* Expected format:
+ *
+ * user: 12345
+ * system: 23456
+ */
+ strstripnewline (buf);
+ numfields = strsplit (buf, fields, STATIC_ARRAY_SIZE (fields));
+ if (numfields != 2)
+ continue;
+
+ key = fields[0];
+ key_len = strlen (key);
+ if (key_len < 2)
+ continue;
+
+ /* Strip colon off the first column */
+ if (key[key_len - 1] != ':')
+ continue;
+ key[key_len - 1] = 0;
+
+ status = parse_value (fields[1], &value, DS_TYPE_DERIVE);
+ if (status != 0)
+ continue;
+
+ cgroups_submit_one (cgroup_name, key, value);
+ }
+
+ fclose (fh);
+ return (0);
+} /* int read_cpuacct_procs */
+
+/*
+ * Gets called for every file/folder in /sys/fs/cgroup/cpu,cpuacct (or
+ * whereever cpuacct is mounted on the system). Calls walk_directory with the
+ * read_cpuacct_procs callback on every folder it finds, such as "system".
+ */
+static int read_cpuacct_root (const char *dirname, const char *filename,
+ void *user_data)
+{
+ char abs_path[PATH_MAX];
+ struct stat statbuf;
+ int status;
+
+ ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename);
+
+ status = lstat (abs_path, &statbuf);
+ if (status != 0)
+ {
+ ERROR ("cgroups plugin: stat (%s) failed.", abs_path);
+ return (-1);
+ }
+
+ if (S_ISDIR (statbuf.st_mode))
+ {
+ status = walk_directory (abs_path, read_cpuacct_procs,
+ /* user_data = */ NULL,
+ /* include_hidden = */ 0);
+ return (status);
+ }
+
+ return (0);
+}
+
+static int cgroups_init (void)
+{
+ if (il_cgroup == NULL)
+ il_cgroup = ignorelist_create (1);
+
+ return (0);
+}
+
+static int cgroups_config (const char *key, const char *value)
+{
+ cgroups_init ();
+
+ if (strcasecmp (key, "CGroup") == 0)
+ {
+ if (ignorelist_add (il_cgroup, value))
+ return (1);
+ return (0);
+ }
+ else if (strcasecmp (key, "IgnoreSelected") == 0)
+ {
+ if (IS_TRUE (value))
+ ignorelist_set_invert (il_cgroup, 0);
+ else
+ ignorelist_set_invert (il_cgroup, 1);
+ return (0);
+ }
+
+ return (-1);
+}
+
+static int cgroups_read (void)
+{
+ cu_mount_t *mnt_list;
+ cu_mount_t *mnt_ptr;
+ _Bool cgroup_found = 0;
+
+ mnt_list = NULL;
+ if (cu_mount_getlist (&mnt_list) == NULL)
+ {
+ ERROR ("cgroups plugin: cu_mount_getlist failed.");
+ return (-1);
+ }
+
+ for (mnt_ptr = mnt_list; mnt_ptr != NULL; mnt_ptr = mnt_ptr->next)
+ {
+ /* Find the cgroup mountpoint which contains the cpuacct
+ * controller. */
+ if (strcmp(mnt_ptr->type, "cgroup") != 0 ||
+ !cu_mount_getoptionvalue(mnt_ptr->options, "cpuacct"))
+ continue;
+
+ walk_directory (mnt_ptr->dir, read_cpuacct_root,
+ /* user_data = */ NULL,
+ /* include_hidden = */ 0);
+ cgroup_found = 1;
+ /* It doesn't make sense to check other cpuacct mount-points
+ * (if any), they contain the same data. */
+ break;
+ }
+
+ cu_mount_freelist (mnt_list);
+
+ if (!cgroup_found)
+ {
+ WARNING ("cgroups plugin: Unable to find cgroup "
+ "mount-point with the \"cpuacct\" option.");
+ return (-1);
+ }
+
+ return (0);
+} /* int cgroup_read */
+
+void module_register (void)
+{
+ plugin_register_config ("cgroups", cgroups_config,
+ config_keys, config_keys_num);
+ plugin_register_init ("cgroups", cgroups_init);
+ plugin_register_read ("cgroups", cgroups_read);
+} /* void module_register */
diff --git a/src/collectd.conf.in b/src/collectd.conf.in
index 5af15684092acb486b57d90023f7203da1a9abaa..f4ac81a0f4d77577f4adc7a1ff12dfc4fa598ffd 100644 (file)
--- a/src/collectd.conf.in
+++ b/src/collectd.conf.in
#PluginDir "@libdir@/@PACKAGE_NAME@"
#TypesDB "@prefix@/share/@PACKAGE_NAME@/types.db"
+#----------------------------------------------------------------------------#
+# When enabled, plugins are loaded automatically with the default options #
+# when an appropriate <Plugin ...> block is encountered. #
+# Disabled by default. #
+#----------------------------------------------------------------------------#
+#AutoLoadPlugin false
+
#----------------------------------------------------------------------------#
# Interval at which to query values. This may be overwritten on a per-plugin #
# base by using the 'Interval' option of the LoadPlugin block: #
#@BUILD_PLUGIN_BIND_TRUE@LoadPlugin bind
#@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack
#@BUILD_PLUGIN_CONTEXTSWITCH_TRUE@LoadPlugin contextswitch
+#@BUILD_PLUGIN_CGROUPS_TRUE@LoadPlugin cgroups
@BUILD_PLUGIN_CPU_TRUE@@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
#@BUILD_PLUGIN_CPUFREQ_TRUE@LoadPlugin cpufreq
@LOAD_PLUGIN_CSV@LoadPlugin csv
#@BUILD_PLUGIN_LIBVIRT_TRUE@LoadPlugin libvirt
@BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
#@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
+#@BUILD_PLUGIN_LVM_TRUE@LoadPlugin lvm
#@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
#@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
#@BUILD_PLUGIN_MD_TRUE@LoadPlugin md
#@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
#@BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid
#@BUILD_PLUGIN_VARNISH_TRUE@LoadPlugin varnish
+#@BUILD_PLUGIN_MIC_TRUE@LoadPlugin mic
#@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem
#@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
#@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
# UUIDFile "/etc/uuid"
#</Plugin>
+#<Plugin mic>
+# ShowCPU true
+# ShowCPUCores true
+# ShowMemory true
+# ShowTemperatures true
+## Temperature Sensors can be ignored/shown by repeated #Temperature lines, and
+## then inverted with a IgnoreSelectedTemperature.
+## Known Temperature sensors: die, devmem, fin, fout, vccp, vddg, vddq
+# Temperature vddg
+# IgnoreSelectedTemperature true
+# ShowPower true
+## Power Sensors can be ignored/shown by repeated #Power lines, and
+## then inverted with a IgnoreSelectedTemperature.
+## Known Temperature sensors: total0, total1, inst, imax, pci3, c2x3, c2x4, vccp, vddg, vddq
+# Power total1
+# IgnoreSelectedPower true
+#</Plugin>
+
#<Plugin varnish>
# This tag support an argument if you want to
# monitor the local instance just use </Instance>
# <Instance>
# CollectCache true
# CollectBackend true
+# CollectBan false # Varnish 3 only
# CollectConnections true
+# CollectDirectorDNS false # Varnish 3 only
# CollectSHM true
# CollectESI false
# CollectFetch false
# CollectHCB false
-# CollectSMA false
+# CollectObjects false
+# CollectPurge false # Varnish 2 only
+# CollectSession false
+# CollectSMA false # Varnish 2 only
# CollectSMS false
-# CollectSM false
+# CollectSM false # Varnish 2 only
+# CollectStruct false
# CollectTotals false
+# CollectUptime false
+# CollectVCL false
# CollectWorkers false
# </Instance>
#</Plugin>
# <Node "example">
# Host "localhost"
# Port "2003"
+# Protocol "udp"
+# LogSendErrors true
# Prefix "collectd"
# Postfix "collectd"
# StoreRates true
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index 0a2a5f7790de1ca30e5b93aa714d97af5073b3d0..ddf3ac60e12da8699fdcc238674cee63aff75621 100644 (file)
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
=item B<LoadPlugin> I<Plugin>
-Loads the plugin I<Plugin>. There must be at least one such line or B<collectd>
-will be mostly useless.
+Loads the plugin I<Plugin>. This is required to load plugins, unless the
+B<AutoLoadPlugin> option is enabled (see below). Without any loaded plugins,
+I<collectd> will be mostly useless.
-Starting with collectd 4.9, this may also be a block in which further options
-affecting the behavior of B<LoadPlugin> may be specified. The following
-options are allowed inside a B<LoadPlugin> block:
+Only the first B<LoadPlugin> statement or block for a given plugin name has any
+effect. This is useful when you want to split up the configuration into smaller
+files and want each file to be "self contained", i.e. it contains a B<Plugin>
+block I<and> then appropriate B<LoadPlugin> statement. The downside is that if
+you have multiple conflicting B<LoadPlugin> blocks, e.g. when they specify
+different intervals, only one of them (the first one encountered) will take
+effect and all others will be silently ignored.
- <LoadPlugin perl>
- Globals true
- Interval 10
- </LoadPlugin>
+B<LoadPlugin> may either be a simple configuration I<statement> or a I<block>
+with additional options, affecting the behavior of B<LoadPlugin>. A simple
+statement looks like this:
+
+ LoadPlugin "cpu"
+
+Options inside a B<LoadPlugin> block can override default settings and
+influence the way plugins are loaded, e.g.:
+
+ <LoadPlugin perl>
+ Globals true
+ Interval 60
+ </LoadPlugin>
+
+The following options are valid inside B<LoadPlugin> blocks:
=over 4
=back
-=item B<Include> I<Path>
+=item B<AutoLoadPlugin> B<false>|B<true>
+
+When set to B<false> (the default), each plugin needs to be loaded explicitly,
+using the B<LoadPlugin> statement documented above. If a
+B<E<lt>PluginE<nbsp>...E<gt>> block is encountered and no configuration
+handling callback for this plugin has been registered, a warning is logged and
+the block is ignored.
+
+When set to B<true>, explicit B<LoadPlugin> statements are not required. Each
+B<E<lt>PluginE<nbsp>...E<gt>> block acts as if it was immediately preceded by a
+B<LoadPlugin> statement. B<LoadPlugin> statements are still required for
+plugins that don't provide any configuration, e.g. the I<Load plugin>.
+
+=item B<Include> I<Path> [I<pattern>]
If I<Path> points to a file, includes that file. If I<Path> points to a
directory, recursively includes all files within that directory and its
=back
+=head2 Plugin C<cgroups>
+
+This plugin collects the CPU user/system time for each I<cgroup> by reading the
+F<cpuacct.stat> files in the first cpuacct-mountpoint (typically
+F</sys/fs/cgroup/cpu.cpuacct> on machines using systemd).
+
+=over 4
+
+=item B<CGroup> I<Directory>
+
+Select I<cgroup> based on the name. Whether only matching I<cgroups> are
+collected or if they are ignored is controlled by the B<IgnoreSelected> option;
+see below.
+
+=item B<IgnoreSelected> B<true>|B<false>
+
+Invert the selection: If set to true, all cgroups I<except> the ones that
+match any one of the criteria are collected. By default only selected
+cgroups are collected if a selection is made. If no selection is configured
+at all, B<all> cgroups are selected.
+
+=back
+
=head2 Plugin C<cpufreq>
This plugin doesn't have any options. It reads
many small files are stored on the disk. This is a usual scenario for mail
transfer agents and web caches.
+=item B<ValuesAbsolute> B<true>|B<false>
+
+Enables or disables reporting of free, used and used disk space in 1K-blocks.
+Defaults to true.
+
+=item B<ValuesPercentage> B<true>|B<false>
+
+Enables or disables reporting of free, used and used disk space in percentage.
+Defaults to false.
+
+This is useful for deploying collectd on the cloud, where machines with
+different disk size may exist. Then it is more practical to configure thresholds
+based on relative disk size.
+
=back
=head2 Plugin C<disk>
=head2 Plugin C<memcached>
-The C<memcached plugin> connects to a memcached server and queries statistics
+The B<memcached plugin> connects to a memcached server and queries statistics
about cache utilization, memory and bandwidth used.
L<http://www.danga.com/memcached/>
=back
+=head2 Plugin C<mic>
+
+The B<mic plugin> gathers CPU statistics, memory usage and temperatures from
+Intel's Many Integrated Core (MIC) systems.
+
+B<Synopsis:>
+
+ <Plugin mic>
+ ShowCPU true
+ ShowCPUCores true
+ ShowMemory true
+
+ ShowTemperatures true
+ Temperature vddg
+ Temperature vddq
+ IgnoreSelectedTemperature true
+
+ ShowPower true
+ Power total0
+ Power total1
+ IgnoreSelectedPower true
+ </Plugin>
+
+The following options are valid inside the B<PluginE<nbsp>mic> block:
+
+=over 4
+
+=item B<ShowCPU> B<true>|B<false>
+
+If enabled (the default) a sum of the CPU usage accross all cores is reported.
+
+=item B<ShowCPUCores> B<true>|B<false>
+
+If enabled (the default) per-core CPU usage is reported.
+
+=item B<ShowMemory> B<true>|B<false>
+
+If enabled (the default) the physical memory usage of the MIC system is
+reported.
+
+=item B<ShowTemperatures> B<true>|B<false>
+
+If enabled (the default) various temperatures of the MIC system are reported.
+
+=item B<Temperature> I<Name>
+
+This option controls which temperatures are being reported. Whether matching
+temperatures are being ignored or I<only> matching temperatures are reported
+depends on the B<IgnoreSelectedTemperature> setting below. By default I<all>
+temperatures are reported.
+
+=item B<IgnoreSelectedTemperature> B<false>|B<true>
+
+Controls the behavior of the B<Temperature> setting above. If set to B<false>
+(the default) only temperatures matching a B<Temperature> option are reported
+or, if no B<Temperature> option is specified, all temperatures are reported. If
+set to B<true>, matching temperatures are I<ignored> and all other temperatures
+are reported.
+
+Known temperature names are:
+
+=over 4
+
+=item die
+
+Die of the CPU
+
+=item devmem
+
+Device Memory
+
+=item fin
+
+Fan In
+
+=item fout
+
+Fan Out
+
+=item vccp
+
+Voltage ccp
+
+=item vddg
+
+Voltage ddg
+
+=item vddq
+
+Voltage ddq
+
+=back
+
+=item B<ShowPower> B<true>|B<false>
+
+If enabled (the default) various temperatures of the MIC system are reported.
+
+=item B<Power> I<Name>
+
+This option controls which power readings are being reported. Whether matching
+power readings are being ignored or I<only> matching power readings are reported
+depends on the B<IgnoreSelectedPower> setting below. By default I<all>
+power readings are reported.
+
+=item B<IgnoreSelectedPower> B<false>|B<true>
+
+Controls the behavior of the B<Power> setting above. If set to B<false>
+(the default) only power readings matching a B<Power> option are reported
+or, if no B<Power> option is specified, all power readings are reported. If
+set to B<true>, matching power readings are I<ignored> and all other power readings
+are reported.
+
+Known power names are:
+
+=over 4
+
+=item total0
+
+Total power utilization averaged over Time Window 0 (uWatts).
+
+=item total1
+
+Total power utilization averaged over Time Window 0 (uWatts).
+
+=item inst
+
+Instantaneous power (uWatts).
+
+=item imax
+
+Max instantaneous power (uWatts).
+
+=item pcie
+
+PCI-E connector power (uWatts).
+
+=item c2x3
+
+2x3 connector power (uWatts).
+
+=item c2x4
+
+2x4 connector power (uWatts).
+
+=item vccp
+
+Core rail (uVolts).
+
+=item vddg
+
+Uncore rail (uVolts).
+
+=item vddq
+
+Memory subsystem rail (uVolts).
+
+=back
+
+=back
+
=head2 Plugin C<modbus>
The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP and reads
values), large integer values (unsigned 32E<nbsp>bit values) and floating point
values (two registers interpreted as IEEE floats in big endian notation).
-Synopsis:
+B<Synopsis:>
<Data "voltage-input-1">
RegisterBase 0
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<CollectBan> B<true>|B<false>
+
+Statistics about ban operations, such as number of bans added, retired, and
+number of objects tested against ban operations. Only available with Varnish
+3.x. False by default.
+
+=item B<CollectDirectorDNS> B<true>|B<false>
+
+DNS director lookup cache statistics. Only available with Varnish 3.x. False by
+default.
+
=item B<CollectESI> B<true>|B<false>
Edge Side Includes (ESI) parse statistics. False by default.
@@ -5552,10 +5789,27 @@ Statistics about fetches (HTTP requests sent to the backend). False by default.
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<CollectObjects> B<true>|B<false>
+
+Statistics on cached objects: number of objects expired, nuked (prematurely
+expired), saved, moved, etc. False by default.
+
+=item B<CollectPurge> B<true>|B<false>
+
+Statistics about purge operations, such as number of purges added, retired, and
+number of objects tested against purge operations. Only available with Varnish
+2.x. False by default.
+
+=item B<CollectSession> B<true>|B<false>
+
+Client session statistics. Number of past and current sessions, session herd and
+linger counters, etc. 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.
+malloc or umem (umem_alloc(3MALLOC) based) storage statistics. The umem storage
+component is Solaris specific. Only available with Varnish 2.x. False by
+default.
=item B<CollectSMS> B<true>|B<false>
=item B<CollectSM> B<true>|B<false>
-file (memory mapped file) storage statistics. False by default.
+file (memory mapped file) storage statistics. Only available with Varnish 2.x.
+False by default.
+
+=item B<CollectStruct> B<true>|B<false>
+
+Current varnish internal state statistics. Number of current sessions, objects
+in cache store, open connections to backends (with Varnish 2.x), etc. 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<CollectUptime> B<true>|B<false>
+
+Varnish uptime. False by default.
+
+=item B<CollectVCL> B<true>|B<false>
+
+Number of total (available + discarded) VCL (config files). False by default.
+
=item B<CollectWorkers> B<true>|B<false>
Collect statistics about worker threads. False by default.
The C<write_graphite> plugin writes data to I<Graphite>, an open-source metrics
storage and graphing project. The plugin connects to I<Carbon>, the data layer
-of I<Graphite>, and sends data via the "line based" protocol (per default using
-portE<nbsp>2003). The data will be sent in blocks of at most 1428 bytes to
-minimize the number of network packets.
+of I<Graphite>, via I<TCP> or I<UDP> and sends data via the "line based"
+protocol (per default using portE<nbsp>2003). The data will be sent in blocks
+of at most 1428 bytes to minimize the number of network packets.
Synopsis:
<Node "example">
Host "localhost"
Port "2003"
+ Protocol "udp"
+ LogSendErrors true
Prefix "collectd"
</Node>
</Plugin>
Service name or port number to connect to. Defaults to C<2003>.
+=item B<Protocol> I<String>
+
+Protocol to use when connecting to I<Graphite>. Defaults to C<tcp>.
+
+=item B<LogSendErrors> B<false>|B<true>
+
+If set to B<true> (the default), logs errors when sending data to I<Graphite>.
+If set to B<false>, it will not log the errors. This is especially useful when
+using Protocol UDP since many times we want to use the "fire-and-forget"
+approach and logging errors fills syslog with unneeded messages.
+
=item B<Prefix> I<String>
When set, I<String> is added in front of the host name. Dots and whitespace are
Protocol UDP
StoreRates true
AlwaysAppendDS false
- Delay 10
+ TTLFactor 2.0
</Node>
Tag "foobar"
</Plugin>
identifies a metric in I<Riemann>. If set to B<false> (the default), this is
only done when there is more than one DS.
+=item B<TTLFactor> I<Factor>
+
+I<Riemann> events have a I<Time to Live> (TTL) which specifies how long each
+event is considered active. I<collectd> populates this field based on the
+metrics interval setting. This setting controls the factor with which the
+interval is multiplied to set the TTL. The default value is B<2.0>. Unless you
+know exactly what you're doing, you should only increase this setting from its
+default value.
+
=back
=item B<Tag> I<String>
diff --git a/src/common.c b/src/common.c
index c41c4fe629dd14685e543964d9a7c05b7d8f399b..161b4d67fc063d693b1f319e016687cea4ae639d 100644 (file)
--- a/src/common.c
+++ b/src/common.c
return (ret);
} /* int ssnprintf */
+char *ssnprintf_alloc (char const *format, ...) /* {{{ */
+{
+ char static_buffer[1024] = "";
+ char *alloc_buffer;
+ size_t alloc_buffer_size;
+ int status;
+ va_list ap;
+
+ /* Try printing into the static buffer. In many cases it will be
+ * sufficiently large and we can simply return a strdup() of this
+ * buffer. */
+ va_start (ap, format);
+ status = vsnprintf (static_buffer, sizeof (static_buffer), format, ap);
+ va_end (ap);
+ if (status < 0)
+ return (NULL);
+
+ /* "status" does not include the null byte. */
+ alloc_buffer_size = (size_t) (status + 1);
+ if (alloc_buffer_size <= sizeof (static_buffer))
+ return (strdup (static_buffer));
+
+ /* Allocate a buffer large enough to hold the string. */
+ alloc_buffer = malloc (alloc_buffer_size);
+ if (alloc_buffer == NULL)
+ return (NULL);
+ memset (alloc_buffer, 0, alloc_buffer_size);
+
+ /* Print again into this new buffer. */
+ va_start (ap, format);
+ status = vsnprintf (alloc_buffer, alloc_buffer_size, format, ap);
+ va_end (ap);
+ if (status < 0)
+ {
+ sfree (alloc_buffer);
+ return (NULL);
+ }
+
+ return (alloc_buffer);
+} /* }}} char *ssnprintf_alloc */
+
char *sstrdup (const char *s)
{
char *r;
return (0);
}
-int read_file_contents (const char *filename, char *buf, int bufsize)
+ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize)
{
FILE *fh;
- int n;
+ ssize_t ret;
- if ((fh = fopen (filename, "r")) == NULL)
- return -1;
+ fh = fopen (filename, "r");
+ if (fh == NULL)
+ return (-1);
- n = fread(buf, 1, bufsize, fh);
- fclose(fh);
+ ret = (ssize_t) fread (buf, 1, bufsize, fh);
+ if ((ret == 0) && (ferror (fh) != 0))
+ {
+ ERROR ("read_file_contents: Reading file \"%s\" failed.",
+ filename);
+ ret = -1;
+ }
- return n;
+ fclose(fh);
+ return (ret);
}
counter_t counter_diff (counter_t old_value, counter_t new_value)
diff --git a/src/common.h b/src/common.h
index ae8e311f9983e8ff63441c0ab2936d287220ae67..317be8d1579d063cc23338e229abcdede533da84 100644 (file)
--- a/src/common.h
+++ b/src/common.h
typedef struct rate_to_value_state_s rate_to_value_state_t;
char *sstrncpy (char *dest, const char *src, size_t n);
+
+__attribute__ ((format(printf,3,4)))
int ssnprintf (char *dest, size_t n, const char *format, ...);
+
+__attribute__ ((format(printf,1,2)))
+char *ssnprintf_alloc (char const *format, ...);
+
char *sstrdup(const char *s);
void *smalloc(size_t size);
char *sstrerror (int errnum, char *buf, size_t buflen);
int walk_directory (const char *dir, dirwalk_callback_f callback,
void *user_data, int hidden);
/* Returns the number of bytes read or negative on error. */
-int read_file_contents (const char *filename, char *buf, int bufsize);
+ssize_t read_file_contents (char const *filename, char *buf, size_t bufsize);
counter_t counter_diff (counter_t old_value, counter_t new_value);
diff --git a/src/configfile.c b/src/configfile.c
index 154c041cee2d8b6d01ff4021c723810993c91dac..d6c224fd74966e23f6758ee79be11b75a67e5960 100644 (file)
--- a/src/configfile.c
+++ b/src/configfile.c
{"ReadThreads", NULL, "5"},
{"WriteThreads", NULL, "5"},
{"Timeout", NULL, "2"},
+ {"AutoLoadPlugin", NULL, "false"},
{"PreCacheChain", NULL, "PreCache"},
{"PostCacheChain", NULL, "PostCache"}
};
memset (&ctx, 0, sizeof (ctx));
ctx.interval = cf_get_default_interval ();
- /*
- * XXX: Magic at work:
- *
- * Some of the language bindings, for example the Python and Perl
- * plugins, need to be able to export symbols to the scripts they run.
- * For this to happen, the "Globals" flag needs to be set.
- * Unfortunately, this technical detail is hard to explain to the
- * average user and she shouldn't have to worry about this, ideally.
- * So in order to save everyone's sanity use a different default for a
- * handful of special plugins. --octo
- */
- if ((strcasecmp ("Perl", name) == 0)
- || (strcasecmp ("Python", name) == 0))
- flags |= PLUGIN_FLAGS_GLOBAL;
-
for (i = 0; i < ci->children_num; ++i) {
if (strcasecmp("Globals", ci->children[i].key) == 0)
cf_util_get_flag (ci->children + i, &flags, PLUGIN_FLAGS_GLOBAL);
name = ci->values[0].value.string;
+ if (IS_TRUE (global_option_get ("AutoLoadPlugin")))
+ {
+ int status;
+
+ status = plugin_load (name, /* flags = */ 0);
+ if (status != 0)
+ {
+ ERROR ("Automatically loading plugin \"%s\" failed "
+ "with status %i.", name, status);
+ return (status);
+ }
+ }
+
/* Check for a complex callback first */
for (cb = complex_callback_head; cb != NULL; cb = cb->next)
{
diff --git a/src/curl.c b/src/curl.c
index c6e2ae9c1f521350db159dc2922dafcb6fb54f41..280e61c8649ae70a0f2bc99658aeed5659e71e5a 100644 (file)
--- a/src/curl.c
+++ b/src/curl.c
#include "plugin.h"
#include "configfile.h"
#include "utils_match.h"
+#include "utils_time.h"
#include <curl/curl.h>
char *user;
char *pass;
char *credentials;
- int verify_peer;
- int verify_host;
+ _Bool verify_peer;
+ _Bool verify_host;
char *cacert;
struct curl_slist *headers;
char *post_body;
- int response_time;
+ _Bool response_time;
+ _Bool response_code;
CURL *curl;
char curl_errbuf[CURL_ERROR_SIZE];
{
web_page_t *wp;
size_t len;
-
+
len = size * nmemb;
if (len <= 0)
return (len);
sfree (wp);
} /* }}} void cc_web_page_free */
-static int cc_config_add_string (const char *name, char **dest, /* {{{ */
- oconfig_item_t *ci)
-{
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- WARNING ("curl plugin: `%s' needs exactly one string argument.", name);
- return (-1);
- }
-
- sfree (*dest);
- *dest = strdup (ci->values[0].value.string);
- if (*dest == NULL)
- return (-1);
-
- return (0);
-} /* }}} int cc_config_add_string */
-
static int cc_config_append_string (const char *name, struct curl_slist **dest, /* {{{ */
oconfig_item_t *ci)
{
@@ -193,21 +178,6 @@ static int cc_config_append_string (const char *name, struct curl_slist **dest,
return (0);
} /* }}} int cc_config_append_string */
-
-static int cc_config_set_boolean (const char *name, int *dest, /* {{{ */
- oconfig_item_t *ci)
-{
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
- {
- WARNING ("curl plugin: `%s' needs exactly one boolean argument.", name);
- return (-1);
- }
-
- *dest = ci->values[0].value.boolean ? 1 : 0;
-
- return (0);
-} /* }}} int cc_config_set_boolean */
-
static int cc_config_add_match_dstype (int *dstype_ret, /* {{{ */
oconfig_item_t *ci)
{
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Regex", child->key) == 0)
- status = cc_config_add_string ("Regex", &match->regex, child);
+ status = cf_util_get_string (child, &match->regex);
else if (strcasecmp ("ExcludeRegex", child->key) == 0)
- status = cc_config_add_string ("ExcludeRegex", &match->exclude_regex, child);
+ status = cf_util_get_string (child, &match->exclude_regex);
else if (strcasecmp ("DSType", child->key) == 0)
status = cc_config_add_match_dstype (&match->dstype, child);
else if (strcasecmp ("Type", child->key) == 0)
- status = cc_config_add_string ("Type", &match->type, child);
+ status = cf_util_get_string (child, &match->type);
else if (strcasecmp ("Instance", child->key) == 0)
- status = cc_config_add_string ("Instance", &match->instance, child);
+ status = cf_util_get_string (child, &match->instance);
else
{
WARNING ("curl plugin: Option `%s' not allowed here.", child->key);
page->verify_peer = 1;
page->verify_host = 1;
page->response_time = 0;
+ page->response_code = 0;
page->instance = strdup (ci->values[0].value.string);
if (page->instance == NULL)
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("URL", child->key) == 0)
- status = cc_config_add_string ("URL", &page->url, child);
+ status = cf_util_get_string (child, &page->url);
else if (strcasecmp ("User", child->key) == 0)
- status = cc_config_add_string ("User", &page->user, child);
+ status = cf_util_get_string (child, &page->user);
else if (strcasecmp ("Password", child->key) == 0)
- status = cc_config_add_string ("Password", &page->pass, child);
+ status = cf_util_get_string (child, &page->pass);
else if (strcasecmp ("VerifyPeer", child->key) == 0)
- status = cc_config_set_boolean ("VerifyPeer", &page->verify_peer, child);
+ status = cf_util_get_boolean (child, &page->verify_peer);
else if (strcasecmp ("VerifyHost", child->key) == 0)
- status = cc_config_set_boolean ("VerifyHost", &page->verify_host, child);
+ status = cf_util_get_boolean (child, &page->verify_host);
else if (strcasecmp ("MeasureResponseTime", child->key) == 0)
- status = cc_config_set_boolean (child->key, &page->response_time, child);
+ status = cf_util_get_boolean (child, &page->response_time);
+ else if (strcasecmp ("MeasureResponseCode", child->key) == 0)
+ status = cf_util_get_boolean (child, &page->response_code);
else if (strcasecmp ("CACert", child->key) == 0)
- status = cc_config_add_string ("CACert", &page->cacert, child);
+ status = cf_util_get_string (child, &page->cacert);
else if (strcasecmp ("Match", child->key) == 0)
/* Be liberal with failing matches => don't set `status'. */
cc_config_add_match (page, child);
else if (strcasecmp ("Header", child->key) == 0)
status = cc_config_append_string ("Header", &page->headers, child);
else if (strcasecmp ("Post", child->key) == 0)
- status = cc_config_add_string ("Post", &page->post_body, child);
+ status = cf_util_get_string (child, &page->post_body);
else
{
WARNING ("curl plugin: Option `%s' not allowed here.", child->key);
status = -1;
}
- if (page->matches == NULL && !page->response_time)
+ if (page->matches == NULL && !page->response_time && !page->response_code)
{
assert (page->instance != NULL);
WARNING ("curl plugin: No (valid) `Match' block "
- "or MeasureResponseTime within `Page' block `%s'.", page->instance);
+ "or MeasureResponseTime or MeasureResponseCode within "
+ "`Page' block `%s'.", page->instance);
status = -1;
}
plugin_dispatch_values (&vl);
} /* }}} void cc_submit */
-static void cc_submit_response_time (const web_page_t *wp, double seconds) /* {{{ */
+static void cc_submit_response_code (const web_page_t *wp, long code) /* {{{ */
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = code;
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "response_code", sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+} /* }}} void cc_submit_response_code */
+
+static void cc_submit_response_time (const web_page_t *wp, /* {{{ */
+ cdtime_t response_time)
{
value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].gauge = seconds;
+ values[0].gauge = CDTIME_T_TO_DOUBLE (response_time);
vl.values = values;
vl.values_len = 1;
{
web_match_t *wm;
int status;
- struct timeval start, end;
+ cdtime_t start = 0;
if (wp->response_time)
- gettimeofday (&start, NULL);
+ start = cdtime ();
wp->buffer_fill = 0;
status = curl_easy_perform (wp->curl);
}
if (wp->response_time)
+ cc_submit_response_time (wp, cdtime() - start);
+
+ if(wp->response_code)
{
- double secs = 0;
- gettimeofday (&end, NULL);
- secs += end.tv_sec - start.tv_sec;
- secs += (end.tv_usec - start.tv_usec) / 1000000.0;
- cc_submit_response_time (wp, secs);
+ long response_code = 0;
+ status = curl_easy_getinfo(wp->curl, CURLINFO_RESPONSE_CODE, &response_code);
+ if(status != CURLE_OK) {
+ ERROR ("curl plugin: Fetching response code failed with staus %i: %s",
+ status, wp->curl_errbuf);
+ } else {
+ cc_submit_response_code(wp, response_code);
+ }
}
for (wm = wp->matches; wm != NULL; wm = wm->next)
diff --git a/src/curl_xml.c b/src/curl_xml.c
index 0b4130473f4e3359dc9cbb66059831ac09386a34..5adaf067a157e44220655adb79855c6fee0d3b26 100644 (file)
--- a/src/curl_xml.c
+++ b/src/curl_xml.c
if (status == 0)
{
user_data_t ud;
- char cb_name[DATA_MAX_NAME_LEN];
+ char *cb_name;
if (db->instance == NULL)
db->instance = strdup("default");
ud.data = (void *) db;
ud.free_func = cx_free;
- ssnprintf (cb_name, sizeof (cb_name), "curl_xml-%s-%s",
- db->instance, db->url);
-
- plugin_register_complex_read (/* group = */ NULL, cb_name, cx_read,
+ cb_name = ssnprintf_alloc ("curl_xml-%s-%s", db->instance, db->url);
+ plugin_register_complex_read (/* group = */ "curl_xml", cb_name, cx_read,
/* interval = */ NULL, &ud);
+ sfree (cb_name);
}
else
{
diff --git a/src/df.c b/src/df.c
index ded374b942e5d08d804dd027292eef2ef9f50fcb..540985d798ea46da3d12ad24aec2e638a0075643 100644 (file)
--- a/src/df.c
+++ b/src/df.c
"IgnoreSelected",
"ReportByDevice",
"ReportReserved",
- "ReportInodes"
+ "ReportInodes",
+ "ValuesAbsolute",
+ "ValuesPercentage"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
static _Bool by_device = 0;
static _Bool report_inodes = 0;
+static _Bool values_absolute = 1;
+static _Bool values_percentage = 0;
static int df_init (void)
{
return (0);
}
+ else if (strcasecmp (key, "ValuesAbsolute") == 0)
+ {
+ if (IS_TRUE (value))
+ values_absolute = 1;
+ else
+ values_absolute = 0;
+
+ return (0);
+ }
+ else if (strcasecmp (key, "ValuesPercentage") == 0)
+ {
+ if (IS_TRUE (value))
+ values_percentage = 1;
+ else
+ values_percentage = 0;
+ return (0);
+ }
return (-1);
}
if (!statbuf.f_blocks)
continue;
- if (by_device)
+ if (by_device)
{
/* eg, /dev/hda1 -- strip off the "/dev/" */
if (strncmp (mnt_ptr->spec_device, "/dev/", strlen ("/dev/")) == 0)
else
sstrncpy (disk_name, mnt_ptr->spec_device, sizeof (disk_name));
- if (strlen(disk_name) < 1)
+ if (strlen(disk_name) < 1)
{
- DEBUG("df: no device name name for mountpoint %s, skipping", mnt_ptr->dir);
+ DEBUG("df: no device name for mountpoint %s, skipping", mnt_ptr->dir);
continue;
}
- }
- else
+ }
+ else
{
if (strcmp (mnt_ptr->dir, "/") == 0)
{
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",
+ if (values_absolute)
+ {
+ df_submit_one (disk_name, "df_complex", "free",
(gauge_t) (blk_free * blocksize));
- df_submit_one (disk_name, "df_complex", "reserved",
+ df_submit_one (disk_name, "df_complex", "reserved",
(gauge_t) (blk_reserved * blocksize));
- df_submit_one (disk_name, "df_complex", "used",
+ df_submit_one (disk_name, "df_complex", "used",
(gauge_t) (blk_used * blocksize));
-
+ }
+
+ if (values_percentage)
+ {
+ if (statbuf.f_blocks > 0)
+ {
+ df_submit_one (disk_name, "df_complex_pct", "free",
+ (gauge_t) ((float_t)(blk_free) / statbuf.f_blocks * 100));
+ df_submit_one (disk_name, "df_complex_pct", "reserved",
+ (gauge_t) ((float_t)(blk_reserved) / statbuf.f_blocks * 100));
+ df_submit_one (disk_name, "df_complex_pct", "used",
+ (gauge_t) ((float_t)(blk_used) / statbuf.f_blocks * 100));
+ }
+ else return (-1);
+ }
+
/* inode handling */
if (report_inodes)
{
statbuf.f_ffree = statbuf.f_favail;
if (statbuf.f_files < statbuf.f_ffree)
statbuf.f_files = statbuf.f_ffree;
-
+
inode_free = (uint64_t) statbuf.f_favail;
inode_reserved = (uint64_t) (statbuf.f_ffree - statbuf.f_favail);
inode_used = (uint64_t) (statbuf.f_files - statbuf.f_ffree);
-
- df_submit_one (disk_name, "df_inodes", "free",
- (gauge_t) inode_free);
- df_submit_one (disk_name, "df_inodes", "reserved",
- (gauge_t) inode_reserved);
- df_submit_one (disk_name, "df_inodes", "used",
- (gauge_t) inode_used);
+
+ if (values_percentage)
+ {
+ if (statbuf.f_files > 0)
+ {
+ df_submit_one (disk_name, "df_inodes_pct", "free",
+ (gauge_t) ((float_t)(inode_free) / statbuf.f_files * 100));
+ df_submit_one (disk_name, "df_inodes_pct", "reserved",
+ (gauge_t) ((float_t)(inode_reserved) / statbuf.f_files * 100));
+ df_submit_one (disk_name, "df_inodes_pct", "used",
+ (gauge_t) ((float_t)(inode_used) / statbuf.f_files * 100));
+ }
+ else return (-1);
+ }
+ if (values_absolute)
+ {
+ df_submit_one (disk_name, "df_inodes", "free",
+ (gauge_t) inode_free);
+ df_submit_one (disk_name, "df_inodes", "reserved",
+ (gauge_t) inode_reserved);
+ df_submit_one (disk_name, "df_inodes", "used",
+ (gauge_t) inode_used);
+ }
}
}
diff --git a/src/lvm.c b/src/lvm.c
--- /dev/null
+++ b/src/lvm.c
@@ -0,0 +1,103 @@
+/**
+ * collectd - src/lvm.c
+ * Copyright (C) 2013 Chad Malfait
+ *
+ * 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:
+ * Chad Malfait <malfaitc at yahoo.com>
+ **/
+
+#include <lvm2app.h>
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+static void lvm_submit (char const *plugin_instance, char const *type_instance,
+ uint64_t ivalue)
+{
+ value_t v;
+ value_list_t vl = VALUE_LIST_INIT;
+
+ v.gauge = (gauge_t) ivalue;
+
+ vl.values = &v;
+ vl.values_len = 1;
+
+ sstrncpy(vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy(vl.plugin, "lvm", sizeof (vl.plugin));
+ sstrncpy(vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+ sstrncpy(vl.type, "df_complex", sizeof (vl.type));
+ sstrncpy(vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+}
+
+static int vg_read(vg_t vg, char const *vg_name)
+{
+ struct dm_list *lvs;
+ struct lvm_lv_list *lvl;
+
+ lvm_submit (vg_name, "free", lvm_vg_get_free_size(vg));
+
+ lvs = lvm_vg_list_lvs(vg);
+ dm_list_iterate_items(lvl, lvs) {
+ lvm_submit(vg_name, lvm_lv_get_name(lvl->lv), lvm_lv_get_size(lvl->lv));
+ }
+
+ return (0);
+}
+
+static int lvm_read(void)
+{
+ lvm_t lvm;
+ struct dm_list *vg_names;
+ struct lvm_str_list *name_list;
+
+ lvm = lvm_init(NULL);
+ if (!lvm) {
+ ERROR("lvm plugin: lvm_init failed.");
+ return (-1);
+ }
+
+ vg_names = lvm_list_vg_names(lvm);
+ if (!vg_names) {
+ ERROR("lvm plugin lvm_list_vg_name failed %s", lvm_errmsg(lvm));
+ lvm_quit(lvm);
+ return (-1);
+ }
+
+ dm_list_iterate_items(name_list, vg_names) {
+ vg_t vg;
+
+ vg = lvm_vg_open(lvm, name_list->str, "r", 0);
+ if (!vg) {
+ ERROR ("lvm plugin: lvm_vg_open (%s) failed: %s",
+ name_list->str, lvm_errmsg(lvm));
+ continue;
+ }
+
+ vg_read(vg, name_list->str);
+ lvm_vg_close(vg);
+ }
+
+ lvm_quit(lvm);
+ return (0);
+} /*lvm_read */
+
+void module_register(void)
+{
+ plugin_register_read("lvm", lvm_read);
+} /* void module_register */
diff --git a/src/mic.c b/src/mic.c
--- /dev/null
+++ b/src/mic.c
@@ -0,0 +1,417 @@
+/**
+ * collectd - src/mic.c
+ * Copyright (C) 2013 Battelle Memorial Institute
+ *
+ * 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:
+ * Evan Felix <evan.felix at pnnl.gov>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "utils_ignorelist.h"
+
+#include <MicAccessTypes.h>
+#include <MicAccessErrorTypes.h>
+#include <MicAccessApi.h>
+#include <MicThermalAPI.h>
+#include <MicPowerManagerAPI.h>
+
+#define MAX_MICS 32
+#define MAX_CORES 256
+
+static MicDeviceOnSystem mics[MAX_MICS];
+static U32 num_mics = 0;
+static HANDLE mic_handle = NULL;
+
+static int const therm_ids[] = {
+ eMicThermalDie, eMicThermalDevMem, eMicThermalFin, eMicThermalFout,
+ eMicThermalVccp, eMicThermalVddg, eMicThermalVddq };
+static char const * const therm_names[] = {
+ "die", "devmem", "fin", "fout",
+ "vccp", "vddg", "vddq" };
+
+static const char *config_keys[] =
+{
+ "ShowCPU",
+ "ShowCPUCores",
+ "ShowMemory",
+ "ShowTemperatures",
+ "Temperature",
+ "IgnoreSelectedTemperature",
+ "ShowPower",
+ "Power",
+ "IgnoreSelectedPower"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static _Bool show_cpu = 1;
+static _Bool show_cpu_cores = 1;
+static _Bool show_memory = 1;
+static _Bool show_temps = 1;
+static ignorelist_t *temp_ignore = NULL;
+static _Bool show_power = 1;
+static ignorelist_t *power_ignore = NULL;
+
+static int mic_init (void)
+{
+ U32 ret;
+ U32 mic_count;
+
+ if (mic_handle)
+ return (0);
+
+ mic_count = (U32) STATIC_ARRAY_SIZE(mics);
+ ret = MicInitAPI(&mic_handle, eTARGET_SCIF_DRIVER, mics, &mic_count);
+ if (ret != MIC_ACCESS_API_SUCCESS) {
+ ERROR("mic plugin: Problem initializing MicAccessAPI: %s",
+ MicGetErrorString(ret));
+ }
+ DEBUG("mic plugin: found: %"PRIu32" MIC(s)",mic_count);
+
+ if (mic_count<0 || mic_count>=MAX_MICS) {
+ ERROR("mic plugin: No Intel MICs in system");
+ return (1);
+ }
+ else {
+ num_mics = mic_count;
+ return (0);
+ }
+}
+
+static int mic_config (const char *key, const char *value) {
+ if (temp_ignore == NULL)
+ temp_ignore = ignorelist_create(1);
+ if (power_ignore == NULL)
+ power_ignore = ignorelist_create(1);
+ if (temp_ignore == NULL || power_ignore == NULL)
+ return (1);
+
+ if (strcasecmp("ShowCPU",key) == 0)
+ {
+ show_cpu = IS_TRUE(value);
+ }
+ else if (strcasecmp("ShowCPUCores",key) == 0)
+ {
+ show_cpu_cores = IS_TRUE(value);
+ }
+ else if (strcasecmp("ShowTemperatures",key) == 0)
+ {
+ show_temps = IS_TRUE(value);
+ }
+ else if (strcasecmp("ShowMemory",key) == 0)
+ {
+ show_memory = IS_TRUE(value);
+ }
+ else if (strcasecmp("ShowPower",key) == 0)
+ {
+ show_power = IS_TRUE(value);
+ }
+ else if (strcasecmp("Temperature",key) == 0)
+ {
+ ignorelist_add(temp_ignore,value);
+ }
+ else if (strcasecmp("IgnoreSelectedTemperature",key) == 0)
+ {
+ int invert = 1;
+ if (IS_TRUE(value))
+ invert = 0;
+ ignorelist_set_invert(temp_ignore,invert);
+ }
+ else if (strcasecmp("Power",key) == 0)
+ {
+ ignorelist_add(power_ignore,value);
+ }
+ else if (strcasecmp("IgnoreSelectedPower",key) == 0)
+ {
+ int invert = 1;
+ if (IS_TRUE(value))
+ invert = 0;
+ ignorelist_set_invert(power_ignore,invert);
+ }
+ else
+ {
+ return (-1);
+ }
+ return (0);
+}
+
+static void mic_submit_memory_use(int micnumber, const char *type_instance, U32 val)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ /* MicAccessAPI reports KB's of memory, adjust for this */
+ DEBUG("mic plugin: Memory Value Report; %u %lf",val,((gauge_t)val)*1024.0);
+ values[0].gauge = ((gauge_t)val)*1024.0;
+
+ vl.values=values;
+ vl.values_len=1;
+
+ strncpy (vl.host, hostname_g, sizeof (vl.host));
+ strncpy (vl.plugin, "mic", sizeof (vl.plugin));
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "%i", micnumber);
+ strncpy (vl.type, "memory", sizeof (vl.type));
+ strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+}
+
+/* Gather memory Utilization */
+static int mic_read_memory(int mic)
+{
+ U32 ret;
+ U32 mem_total,mem_free,mem_bufs;
+
+ ret = MicGetMemoryUtilization(mic_handle,&mem_total,&mem_free,&mem_bufs);
+ if (ret != MIC_ACCESS_API_SUCCESS) {
+ ERROR("mic plugin: Problem getting Memory Utilization: %s",
+ MicGetErrorString(ret));
+ return (1);
+ }
+ mic_submit_memory_use(mic,"free",mem_free);
+ mic_submit_memory_use(mic,"used",mem_total-mem_free-mem_bufs);
+ mic_submit_memory_use(mic,"buffered",mem_bufs);
+ DEBUG("mic plugin: Memory Read: %u %u %u",mem_total,mem_free,mem_bufs);
+ return (0);
+}
+
+static void mic_submit_temp(int micnumber, const char *type, gauge_t val)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = val;
+
+ vl.values=values;
+ vl.values_len=1;
+
+ strncpy (vl.host, hostname_g, sizeof (vl.host));
+ strncpy (vl.plugin, "mic", sizeof (vl.plugin));
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+ "%i", micnumber);
+ strncpy (vl.type, "temperature", sizeof (vl.type));
+ strncpy (vl.type_instance, type, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+}
+
+/* Gather Temperature Information */
+static int mic_read_temps(int mic)
+{
+ size_t num_therms = STATIC_ARRAY_SIZE(therm_ids);
+ size_t j;
+
+ for (j = 0; j < num_therms; j++) {
+ U32 status;
+ U32 temp_buffer;
+ U32 buffer_size = (U32)sizeof(temp_buffer);
+ char const *name = therm_names[j];
+
+ if (ignorelist_match(temp_ignore, name) != 0)
+ continue;
+
+ status = MicGetTemperature(mic_handle, therm_ids[j],
+ &temp_buffer, &buffer_size);
+ if (status != MIC_ACCESS_API_SUCCESS) {
+ ERROR("mic plugin: Error reading temperature \"%s\": "
+ "%s", name, MicGetErrorString(status));
+ return (1);
+ }
+ mic_submit_temp(mic, name, temp_buffer);
+ }
+ return (0);
+}
+
+static void mic_submit_cpu(int micnumber, const char *type_instance,
+ int core, derive_t val)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].derive = val;
+
+ vl.values=values;
+ vl.values_len=1;
+
+ strncpy (vl.host, hostname_g, sizeof (vl.host));
+ strncpy (vl.plugin, "mic", sizeof (vl.plugin));
+ if (core < 0) /* global aggregation */
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+ "%i", micnumber);
+ else /* per-core statistics */
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+ "%i-cpu-%i", micnumber, core);
+ strncpy (vl.type, "cpu", sizeof (vl.type));
+ strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+}
+
+/*Gather CPU Utilization Information */
+static int mic_read_cpu(int mic)
+{
+ MicCoreUtil core_util;
+ MicCoreJiff core_jiffs[MAX_CORES];
+ U32 core_jiffs_size;
+ U32 status;
+
+ core_jiffs_size = MAX_CORES * sizeof(MicCoreJiff);
+ status = MicGetCoreUtilization(mic_handle, &core_util,
+ core_jiffs, &core_jiffs_size);
+ if (status != MIC_ACCESS_API_SUCCESS) {
+ ERROR("mic plugin: Problem getting CPU utilization: %s",
+ MicGetErrorString(status));
+ return(-1);
+ }
+
+ if (show_cpu) {
+ mic_submit_cpu(mic, "user", -1, core_util.sum.user);
+ mic_submit_cpu(mic, "sys", -1, core_util.sum.sys);
+ mic_submit_cpu(mic, "nice", -1, core_util.sum.nice);
+ mic_submit_cpu(mic, "idle", -1, core_util.sum.idle);
+ }
+
+ if (show_cpu_cores) {
+ int j;
+ for (j = 0; j < core_util.core; j++) {
+ mic_submit_cpu(mic, "user", j, core_jiffs[j].user);
+ mic_submit_cpu(mic, "sys", j, core_jiffs[j].sys);
+ mic_submit_cpu(mic, "nice", j, core_jiffs[j].nice);
+ mic_submit_cpu(mic, "idle", j, core_jiffs[j].idle);
+ }
+ }
+ return (0);
+}
+
+static void mic_submit_power(int micnumber, const char *type, const char *type_instance, gauge_t val)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = val;
+
+ vl.values=values;
+ vl.values_len=1;
+
+ strncpy (vl.host, hostname_g, sizeof (vl.host));
+ strncpy (vl.plugin, "mic", sizeof (vl.plugin));
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), "%i", micnumber);
+ strncpy (vl.type, type, sizeof (vl.type));
+ strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+}
+
+/* Gather Power Information */
+static int mic_read_power(int mic)
+{
+ U32 ret;
+ MicPwrUsage power_use;
+
+ ret = MicGetPowerUsage(mic_handle,&power_use);
+ if (ret != MIC_ACCESS_API_SUCCESS) {
+ ERROR("mic plugin: Problem getting Power Usage: %s",
+ MicGetErrorString(ret));
+ return (1);
+ }
+
+ /* power is in uWatts, current in mA, voltage in uVolts.. convert to
+ * base unit */
+ #define SUB_POWER(name) do { if (ignorelist_match(power_ignore,#name)==0) \
+ mic_submit_power(mic,"power",#name,(gauge_t)power_use.name.prr*0.000001); \
+ } while(0)
+ #define SUB_VOLTS(name) do { if (ignorelist_match(power_ignore,#name)==0) {\
+ mic_submit_power(mic,"power",#name,(gauge_t)(power_use.name.pwr*0.000001)); \
+ mic_submit_power(mic,"current",#name,(gauge_t)(power_use.name.cur*0.001)); \
+ mic_submit_power(mic,"voltage",#name,(gauge_t)(power_use.name.volt*0.000001)); \
+ }} while(0)
+
+ SUB_POWER(total0);
+ SUB_POWER(total1);
+ SUB_POWER(inst);
+ SUB_POWER(imax);
+ SUB_POWER(pcie);
+ SUB_POWER(c2x3);
+ SUB_POWER(c2x4);
+ SUB_VOLTS(vccp);
+ SUB_VOLTS(vddg);
+ SUB_VOLTS(vddq);
+
+ return (0);
+}
+
+static int mic_read (void)
+{
+ int i;
+ U32 ret;
+ int error;
+
+ error=0;
+ for (i=0;i<num_mics;i++) {
+ ret = MicInitAdapter(&mic_handle,&mics[i]);
+ if (ret != MIC_ACCESS_API_SUCCESS) {
+ ERROR("mic plugin: Problem initializing MicAdapter: %s",
+ MicGetErrorString(ret));
+ error=1;
+ }
+
+ if (error == 0 && show_memory)
+ error = mic_read_memory(i);
+
+ if (error == 0 && show_temps)
+ error = mic_read_temps(i);
+
+ if (error == 0 && (show_cpu || show_cpu_cores))
+ error = mic_read_cpu(i);
+
+ if (error == 0 && (show_power))
+ error = mic_read_power(i);
+
+ ret = MicCloseAdapter(mic_handle);
+ if (ret != MIC_ACCESS_API_SUCCESS) {
+ ERROR("mic plugin: Problem closing MicAdapter: %s",
+ MicGetErrorString(ret));
+ error=2;
+ break;
+ }
+ }
+ if (num_mics==0)
+ error=3;
+ return error;
+}
+
+
+static int mic_shutdown (void)
+{
+ if (mic_handle)
+ MicCloseAPI(&mic_handle);
+ mic_handle = NULL;
+
+ return (0);
+}
+
+void module_register (void)
+{
+ plugin_register_init ("mic", mic_init);
+ plugin_register_shutdown ("mic", mic_shutdown);
+ plugin_register_read ("mic", mic_read);
+ plugin_register_config ("mic",mic_config, config_keys, config_keys_num);
+} /* void module_register */
+
+/*
+ * vim: set shiftwidth=8 softtabstop=8 noet textwidth=78 :
+ */
diff --git a/src/plugin.c b/src/plugin.c
index d3767d1283b9678bec65e8665d5feb7b8c64bef7..2ad866e3bb2fbcb44012ff997b62932563bdd349 100644 (file)
--- a/src/plugin.c
+++ b/src/plugin.c
#define rf_ctx rf_super.cf_ctx
callback_func_t rf_super;
char rf_group[DATA_MAX_NAME_LEN];
- char rf_name[DATA_MAX_NAME_LEN];
+ char *rf_name;
int rf_type;
cdtime_t rf_interval;
cdtime_t rf_effective_interval;
/*
* Private variables
*/
+static c_avl_tree_t *plugins_loaded = NULL;
+
static llist_t *list_init;
static llist_t *list_write;
static llist_t *list_flush;
{
DEBUG ("plugin_read_thread: Destroying the `%s' "
"callback.", rf->rf_name);
+ sfree (rf->rf_name);
destroy_callback ((callback_func_t *) rf);
rf = NULL;
continue;
}
}
+static _Bool plugin_is_loaded (char const *name)
+{
+ int status;
+
+ if (plugins_loaded == NULL)
+ plugins_loaded = c_avl_create ((void *) strcasecmp);
+ assert (plugins_loaded != NULL);
+
+ status = c_avl_get (plugins_loaded, name, /* ret_value = */ NULL);
+ return (status == 0);
+}
+
+static int plugin_mark_loaded (char const *name)
+{
+ char *name_copy;
+ int status;
+
+ name_copy = strdup (name);
+ if (name_copy == NULL)
+ return (ENOMEM);
+
+ status = c_avl_insert (plugins_loaded,
+ /* key = */ name_copy, /* value = */ NULL);
+ return (status);
+}
+
+static void plugin_free_loaded ()
+{
+ void *key;
+ void *value;
+
+ if (plugins_loaded == NULL)
+ return;
+
+ while (c_avl_pick (plugins_loaded, &key, &value) == 0)
+ {
+ sfree (key);
+ assert (value == NULL);
+ }
+
+ c_avl_destroy (plugins_loaded);
+ plugins_loaded = NULL;
+}
+
#define BUFSIZE 512
-int plugin_load (const char *type, uint32_t flags)
+int plugin_load (char const *plugin_name, uint32_t flags)
{
DIR *dh;
const char *dir;
struct dirent *de;
int status;
+ if (plugin_name == NULL)
+ return (EINVAL);
+
+ /* Check if plugin is already loaded and don't do anything in this
+ * case. */
+ if (plugin_is_loaded (plugin_name))
+ return (0);
+
dir = plugin_get_dir ();
ret = 1;
+ /*
+ * XXX: Magic at work:
+ *
+ * Some of the language bindings, for example the Python and Perl
+ * plugins, need to be able to export symbols to the scripts they run.
+ * For this to happen, the "Globals" flag needs to be set.
+ * Unfortunately, this technical detail is hard to explain to the
+ * average user and she shouldn't have to worry about this, ideally.
+ * So in order to save everyone's sanity use a different default for a
+ * handful of special plugins. --octo
+ */
+ if ((strcasecmp ("perl", plugin_name) == 0)
+ || (strcasecmp ("python", plugin_name) == 0))
+ flags |= PLUGIN_FLAGS_GLOBAL;
+
/* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
* type when matching the filename */
- status = ssnprintf (typename, sizeof (typename), "%s.so", type);
+ status = ssnprintf (typename, sizeof (typename), "%s.so", plugin_name);
if ((status < 0) || ((size_t) status >= sizeof (typename)))
{
- WARNING ("plugin_load: Filename too long: \"%s.so\"", type);
+ WARNING ("plugin_load: Filename too long: \"%s.so\"", plugin_name);
return (-1);
}
typename_len = strlen (typename);
if (status == 0)
{
/* success */
+ plugin_mark_loaded (plugin_name);
ret = 0;
break;
}
else
{
ERROR ("plugin_load: Load plugin \"%s\" failed with "
- "status %i.", type, status);
+ "status %i.", plugin_name, status);
}
}
if (filename[0] == 0)
ERROR ("plugin_load: Could not find plugin \"%s\" in %s",
- type, dir);
+ plugin_name, dir);
return (ret);
}
rf->rf_udata.free_func = NULL;
rf->rf_ctx = plugin_get_ctx ();
rf->rf_group[0] = '\0';
- sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
+ rf->rf_name = strdup (name);
rf->rf_type = RF_SIMPLE;
rf->rf_interval = plugin_get_interval ();
sstrncpy (rf->rf_group, group, sizeof (rf->rf_group));
else
rf->rf_group[0] = '\0';
- sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
+ rf->rf_name = strdup (name);
rf->rf_type = RF_COMPLEX;
if (interval != NULL)
rf->rf_interval = TIMESPEC_TO_CDTIME_T (interval);
destroy_all_callbacks (&list_shutdown);
destroy_all_callbacks (&list_log);
+ plugin_free_loaded ();
plugin_free_data_sets ();
} /* void plugin_shutdown_all */
diff --git a/src/plugin.h b/src/plugin.h
index 635ff308f2cd4f83278554f4f79759a5b2efaeb4..8f0c6d86105fbfe56547d6b5d78ac9fd7a7f4b26 100644 (file)
--- a/src/plugin.h
+++ b/src/plugin.h
* and a value below zero if an error occurs.
*
* NOTES
- * No attempt is made to re-load an already loaded module.
+ * Re-loading an already loaded module is detected and zero is returned in
+ * this case.
*/
int plugin_load (const char *name, uint32_t flags);
diff --git a/src/thermal.c b/src/thermal.c
index 603f85bbf6a96595ee04891127f37006d90730aa..27c92bc730c65b44c54c25bd9dc27a75c279980c 100644 (file)
--- a/src/thermal.c
+++ b/src/thermal.c
if (device_list && ignorelist_match (device_list, name))
return -1;
- len = snprintf (filename, sizeof (filename),
+ len = ssnprintf (filename, sizeof (filename),
"%s/%s/temp", dirname_sysfs, name);
if ((len < 0) || ((size_t) len >= sizeof (filename)))
return -1;
- len = read_file_contents (filename, data, sizeof(data));
+ len = (ssize_t) read_file_contents (filename, data, sizeof(data));
if (len > 1 && data[--len] == '\n') {
char *endptr = NULL;
double temp;
@@ -100,12 +100,12 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
}
}
- len = snprintf (filename, sizeof (filename),
+ len = ssnprintf (filename, sizeof (filename),
"%s/%s/cur_state", dirname_sysfs, name);
if ((len < 0) || ((size_t) len >= sizeof (filename)))
return -1;
- len = read_file_contents (filename, data, sizeof(data));
+ len = (ssize_t) read_file_contents (filename, data, sizeof(data));
if (len > 1 && data[--len] == '\n') {
char *endptr = NULL;
double state;
@@ -139,12 +139,12 @@ static int thermal_procfs_device_read (const char __attribute__((unused)) *dir,
* temperature: 55 C
*/
- len = snprintf (filename, sizeof (filename),
+ len = ssnprintf (filename, sizeof (filename),
"%s/%s/temperature", dirname_procfs, name);
if ((len < 0) || ((size_t) len >= sizeof (filename)))
return -1;
- len = read_file_contents (filename, data, sizeof(data));
+ len = (ssize_t) read_file_contents (filename, data, sizeof(data));
if ((len > 0) && ((size_t) len > sizeof(str_temp))
&& (data[--len] == '\n')
&& (! strncmp(data, str_temp, sizeof(str_temp)-1))) {
diff --git a/src/types.db b/src/types.db
index fb443d9e99023e59bc367e2579c6adafe7ce7bb3..4922aa75f06338626e661878fb8d296eecec74e3 100644 (file)
--- a/src/types.db
+++ b/src/types.db
apache_scoreboard value:GAUGE:0:65535
ath_nodes value:GAUGE:0:65535
ath_stat value:DERIVE:0:U
+backends value:GAUGE:0:65535
bitrate value:GAUGE:0:4294967295
bytes value:GAUGE:0:U
cache_eviction value:DERIVE:0:U
node_rssi value:GAUGE:0:255
node_stat value:DERIVE:0:U
node_tx_rate value:GAUGE:0:127
+objects value:GAUGE:0:U
operations value:DERIVE:0:U
percent value:GAUGE:0:100.1
pf_counters value:DERIVE:0:U
records value:GAUGE:0:U
requests value:GAUGE:0:U
response_time value:GAUGE:0:U
+response_code value:GAUGE:0:U
route_etx value:GAUGE:0:U
route_metric value:GAUGE:0:U
routes value:GAUGE:0:U
time_offset value:GAUGE:-1000000:1000000
total_bytes value:DERIVE:0:U
total_connections value:DERIVE:0:U
+total_objects value:DERIVE:0:U
total_operations value:DERIVE:0:U
total_requests value:DERIVE:0:U
total_sessions value:DERIVE:0:U
total_values value:DERIVE:0:U
uptime value:GAUGE:0:4294967295
users value:GAUGE:0:65535
+vcl value:GAUGE:0:65535
vcpu value:GAUGE:0:U
virt_cpu_total value:DERIVE:0:U
virt_vcpu value:DERIVE:0:U
vs_memory value:GAUGE:0:9223372036854775807
vs_processes value:GAUGE:0:65535
vs_threads value:GAUGE:0:65535
+
#
# Legacy types
# (required for the v5 upgrade target)
diff --git a/src/varnish.c b/src/varnish.c
index 5de3389d862eb41828b5fb73a55f1d5fe2197104..e2ced0e4e20e128184f56330634aa854ae9c21b1 100644 (file)
--- a/src/varnish.c
+++ b/src/varnish.c
* Florian octo Forster <octo at collectd.org>
**/
-/**
- * Current list of what is monitored and what is not monitored (yet)
- * {{{
- * Field name Description Monitored
- * ---------- ----------- ---------
- * uptime Child uptime N
- * client_conn Client connections accepted Y
- * client_drop Connection dropped, no sess Y
- * client_req Client requests received Y
- * cache_hit Cache hits Y
- * cache_hitpass Cache hits for pass Y
- * cache_miss Cache misses Y
- * backend_conn Backend conn. success Y
- * backend_unhealthy Backend conn. not attempted Y
- * backend_busy Backend conn. too many Y
- * backend_fail Backend conn. failures Y
- * backend_reuse Backend conn. reuses Y
- * backend_toolate Backend conn. was closed Y
- * backend_recycle Backend conn. recycles Y
- * backend_unused Backend conn. unused Y
- * fetch_head Fetch head Y
- * fetch_length Fetch with Length Y
- * fetch_chunked Fetch chunked Y
- * fetch_eof Fetch EOF Y
- * fetch_bad Fetch had bad headers Y
- * fetch_close Fetch wanted close Y
- * fetch_oldhttp Fetch pre HTTP/1.1 closed Y
- * fetch_zero Fetch zero len Y
- * fetch_failed Fetch failed Y
- * n_sess_mem N struct sess_mem N
- * n_sess N struct sess N
- * n_object N struct object N
- * n_vampireobject N unresurrected objects N
- * n_objectcore N struct objectcore N
- * n_objecthead N struct objecthead N
- * n_smf N struct smf N
- * n_smf_frag N small free smf N
- * n_smf_large N large free smf N
- * n_vbe_conn N struct vbe_conn N
- * n_wrk N worker threads Y
- * n_wrk_create N worker threads created Y
- * n_wrk_failed N worker threads not created Y
- * n_wrk_max N worker threads limited Y
- * n_wrk_queue N queued work requests Y
- * n_wrk_overflow N overflowed work requests Y
- * n_wrk_drop N dropped work requests Y
- * n_backend N backends N
- * n_expired N expired objects N
- * n_lru_nuked N LRU nuked objects N
- * n_lru_saved N LRU saved objects N
- * n_lru_moved N LRU moved objects N
- * n_deathrow N objects on deathrow N
- * losthdr HTTP header overflows N
- * n_objsendfile Objects sent with sendfile N
- * n_objwrite Objects sent with write N
- * n_objoverflow Objects overflowing workspace N
- * s_sess Total Sessions Y
- * s_req Total Requests Y
- * s_pipe Total pipe Y
- * s_pass Total pass Y
- * s_fetch Total fetch Y
- * s_hdrbytes Total header bytes Y
- * s_bodybytes Total body bytes Y
- * sess_closed Session Closed N
- * sess_pipeline Session Pipeline N
- * sess_readahead Session Read Ahead N
- * sess_linger Session Linger N
- * sess_herd Session herd N
- * shm_records SHM records Y
- * shm_writes SHM writes Y
- * shm_flushes SHM flushes due to overflow Y
- * shm_cont SHM MTX contention Y
- * shm_cycles SHM cycles through buffer Y
- * sm_nreq allocator requests Y
- * sm_nobj outstanding allocations Y
- * sm_balloc bytes allocated Y
- * sm_bfree bytes free Y
- * sma_nreq SMA allocator requests Y
- * sma_nobj SMA outstanding allocations Y
- * sma_nbytes SMA outstanding bytes Y
- * sma_balloc SMA bytes allocated Y
- * sma_bfree SMA bytes free Y
- * sms_nreq SMS allocator requests Y
- * sms_nobj SMS outstanding allocations Y
- * sms_nbytes SMS outstanding bytes Y
- * sms_balloc SMS bytes allocated Y
- * sms_bfree SMS bytes freed Y
- * backend_req Backend requests made N
- * n_vcl N vcl total N
- * n_vcl_avail N vcl available N
- * n_vcl_discard N vcl discarded N
- * n_purge N total active purges N
- * n_purge_add N new purges added N
- * n_purge_retire N old purges deleted N
- * n_purge_obj_test N objects tested N
- * n_purge_re_test N regexps tested against N
- * n_purge_dups N duplicate purges removed N
- * hcb_nolock HCB Lookups without lock Y
- * hcb_lock HCB Lookups with lock Y
- * hcb_insert HCB Inserts Y
- * esi_parse Objects ESI parsed (unlock) Y
- * esi_errors ESI parse errors (unlock) Y
- * }}}
- */
#include "collectd.h"
#include "common.h"
#include "plugin.h"
_Bool collect_connections;
_Bool collect_esi;
_Bool collect_backend;
+#ifdef HAVE_VARNISH_V3
+ _Bool collect_dirdns;
+#endif
_Bool collect_fetch;
_Bool collect_hcb;
+ _Bool collect_objects;
+#if HAVE_VARNISH_V2
+ _Bool collect_purge;
+#else
+ _Bool collect_ban;
+#endif
+ _Bool collect_session;
_Bool collect_shm;
_Bool collect_sms;
#if HAVE_VARNISH_V2
_Bool collect_sm;
_Bool collect_sma;
#endif
+ _Bool collect_struct;
_Bool collect_totals;
+ _Bool collect_uptime;
+ _Bool collect_vcl;
_Bool collect_workers;
};
typedef struct user_config_s user_config_t; /* }}} */
varnish_submit_derive (conf->instance, "connections", "connections", "received", stats->client_req);
}
+#ifdef HAVE_VARNISH_V3
+ if (conf->collect_dirdns)
+ {
+ /* DNS director lookups */
+ varnish_submit_derive (conf->instance, "dirdns", "cache_operation", "lookups", stats->dir_dns_lookups);
+ /* DNS director failed lookups */
+ varnish_submit_derive (conf->instance, "dirdns", "cache_result", "failed", stats->dir_dns_failed);
+ /* DNS director cached lookups hit */
+ varnish_submit_derive (conf->instance, "dirdns", "cache_result", "hits", stats->dir_dns_hit);
+ /* DNS director full dnscache */
+ varnish_submit_derive (conf->instance, "dirdns", "cache_result", "cache_full", stats->dir_dns_cache_full);
+ }
+#endif
+
if (conf->collect_esi)
{
/* ESI parse errors (unlock) */
- varnish_submit_derive (conf->instance, "esi", "total_operations", "error", stats->esi_errors);
+ varnish_submit_derive (conf->instance, "esi", "total_operations", "error", stats->esi_errors);
#if HAVE_VARNISH_V2
/* Objects ESI parsed (unlock) */
- varnish_submit_derive (conf->instance, "esi", "total_operations", "parsed", stats->esi_parse);
+ varnish_submit_derive (conf->instance, "esi", "total_operations", "parsed", stats->esi_parse);
+#else
+ /* ESI parse warnings (unlock) */
+ varnish_submit_derive (conf->instance, "esi", "total_operations", "warning", stats->esi_warnings);
#endif
}
#if HAVE_VARNISH_V2
/* Backend conn. unused */
varnish_submit_derive (conf->instance, "backend", "connections", "unused" , stats->backend_unused);
+#else
+ /* Backend conn. retry */
+ varnish_submit_derive (conf->instance, "backend", "connections", "retries" , stats->backend_retry);
#endif
+ /* Backend requests mades */
+ varnish_submit_derive (conf->instance, "backend", "http_requests", "requests" , stats->backend_req);
+ /* N backends */
+ varnish_submit_gauge (conf->instance, "backend", "backends", "n_backends" , stats->n_backend);
}
if (conf->collect_fetch)
varnish_submit_derive (conf->instance, "fetch", "http_requests", "zero" , stats->fetch_zero);
/* Fetch failed */
varnish_submit_derive (conf->instance, "fetch", "http_requests", "failed" , stats->fetch_failed);
+#if HAVE_VARNISH_V3
+ /* Fetch no body (1xx) */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "no_body_1xx", stats->fetch_1xx);
+ /* Fetch no body (204) */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "no_body_204", stats->fetch_204);
+ /* Fetch no body (304) */
+ varnish_submit_derive (conf->instance, "fetch", "http_requests", "no_body_304", stats->fetch_304);
+#endif
}
if (conf->collect_hcb)
varnish_submit_derive (conf->instance, "hcb", "cache_operation", "insert", stats->hcb_insert);
}
+ if (conf->collect_objects)
+ {
+ /* N expired objects */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "expired", stats->n_expired);
+ /* N LRU nuked objects */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "lru_nuked", stats->n_lru_nuked);
+#if HAVE_VARNISH_V2
+ /* N LRU saved objects */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "lru_saved", stats->n_lru_saved);
+#endif
+ /* N LRU moved objects */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "lru_moved", stats->n_lru_moved);
+#if HAVE_VARNISH_V2
+ /* N objects on deathrow */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "deathrow", stats->n_deathrow);
+#endif
+ /* HTTP header overflows */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "header_overflow", stats->losthdr);
+ /* Objects sent with sendfile */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "sent_sendfile", stats->n_objsendfile);
+ /* Objects sent with write */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "sent_write", stats->n_objwrite);
+ /* Objects overflowing workspace */
+ varnish_submit_derive (conf->instance, "objects", "total_objects", "workspace_overflow", stats->n_objoverflow);
+ }
+
+#if HAVE_VARNISH_V2
+ if (conf->collect_purge)
+ {
+ /* N total active purges */
+ varnish_submit_derive (conf->instance, "purge", "total_operations", "total", stats->n_purge);
+ /* N new purges added */
+ varnish_submit_derive (conf->instance, "purge", "total_operations", "added", stats->n_purge_add);
+ /* N old purges deleted */
+ varnish_submit_derive (conf->instance, "purge", "total_operations", "deleted", stats->n_purge_retire);
+ /* N objects tested */
+ varnish_submit_derive (conf->instance, "purge", "total_operations", "objects_tested", stats->n_purge_obj_test);
+ /* N regexps tested against */
+ varnish_submit_derive (conf->instance, "purge", "total_operations", "regexps_tested", stats->n_purge_re_test);
+ /* N duplicate purges removed */
+ varnish_submit_derive (conf->instance, "purge", "total_operations", "duplicate", stats->n_purge_dups);
+ }
+#else
+ if (conf->collect_ban)
+ {
+ /* N total active bans */
+ varnish_submit_derive (conf->instance, "ban", "total_operations", "total", stats->n_ban);
+ /* N new bans added */
+ varnish_submit_derive (conf->instance, "ban", "total_operations", "added", stats->n_ban_add);
+ /* N old bans deleted */
+ varnish_submit_derive (conf->instance, "ban", "total_operations", "deleted", stats->n_ban_retire);
+ /* N objects tested */
+ varnish_submit_derive (conf->instance, "ban", "total_operations", "objects_tested", stats->n_ban_obj_test);
+ /* N regexps tested against */
+ varnish_submit_derive (conf->instance, "ban", "total_operations", "regexps_tested", stats->n_ban_re_test);
+ /* N duplicate bans removed */
+ varnish_submit_derive (conf->instance, "ban", "total_operations", "duplicate", stats->n_ban_dups);
+ }
+#endif
+
+ if (conf->collect_session)
+ {
+ /* Session Closed */
+ varnish_submit_derive (conf->instance, "session", "total_operations", "closed", stats->sess_closed);
+ /* Session Pipeline */
+ varnish_submit_derive (conf->instance, "session", "total_operations", "pipeline", stats->sess_pipeline);
+ /* Session Read Ahead */
+ varnish_submit_derive (conf->instance, "session", "total_operations", "readahead", stats->sess_readahead);
+ /* Session Linger */
+ varnish_submit_derive (conf->instance, "session", "total_operations", "linger", stats->sess_linger);
+ /* Session herd */
+ varnish_submit_derive (conf->instance, "session", "total_operations", "herd", stats->sess_herd);
+ }
+
if (conf->collect_shm)
{
/* SHM records */
varnish_submit_derive (conf->instance, "sms", "total_bytes", "free", stats->sms_bfree);
}
+ if (conf->collect_struct)
+ {
+ /* N struct sess_mem */
+ varnish_submit_gauge (conf->instance, "struct", "current_sessions", "sess_mem", stats->n_sess_mem);
+ /* N struct sess */
+ varnish_submit_gauge (conf->instance, "struct", "current_sessions", "sess", stats->n_sess);
+ /* N struct object */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "object", stats->n_object);
+ /* N unresurrected objects */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "vampireobject", stats->n_vampireobject);
+ /* N struct objectcore */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "objectcore", stats->n_objectcore);
+ /* N struct objecthead */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "objecthead", stats->n_objecthead);
+#ifdef HAVE_VARNISH_V2
+ /* N struct smf */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "smf", stats->n_smf);
+ /* N small free smf */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "smf_frag", stats->n_smf_frag);
+ /* N large free smf */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "smf_large", stats->n_smf_large);
+ /* N struct vbe_conn */
+ varnish_submit_gauge (conf->instance, "struct", "objects", "vbe_conn", stats->n_vbe_conn);
+#endif
+ }
+
if (conf->collect_totals)
{
/* Total Sessions */
varnish_submit_derive (conf->instance, "totals", "total_bytes", "body-bytes", stats->s_bodybytes);
}
+ if (conf->collect_uptime)
+ {
+ /* Client uptime */
+ varnish_submit_gauge (conf->instance, "uptime", "uptime", "client_uptime", stats->uptime);
+ }
+
+ if (conf->collect_vcl)
+ {
+ /* N vcl total */
+ varnish_submit_gauge (conf->instance, "vcl", "vcl", "total_vcl", stats->n_vcl);
+ /* N vcl available */
+ varnish_submit_gauge (conf->instance, "vcl", "vcl", "avail_vcl", stats->n_vcl_avail);
+ /* N vcl discarded */
+ varnish_submit_gauge (conf->instance, "vcl", "vcl", "discarded_vcl", stats->n_vcl_discard);
+ }
+
if (conf->collect_workers)
{
/* worker threads */
varnish_submit_derive (conf->instance, "workers", "total_requests", "queued", stats->n_wrk_queue);
/* overflowed work requests */
varnish_submit_derive (conf->instance, "workers", "total_requests", "overflowed", stats->n_wrk_overflow);
+#else
+ /* queued work requests */
+ varnish_submit_derive (conf->instance, "workers", "total_requests", "queued", stats->n_wrk_queued);
+ /* work request queue length */
+ varnish_submit_derive (conf->instance, "workers", "total_requests", "queue_length", stats->n_wrk_lqueue);
#endif
}
} /* }}} void varnish_monitor */
conf->collect_backend = 1;
conf->collect_cache = 1;
conf->collect_connections = 1;
+#ifdef HAVE_VARNISH_V3
+ conf->collect_dirdns = 0;
+#endif
conf->collect_esi = 0;
conf->collect_fetch = 0;
conf->collect_hcb = 0;
+ conf->collect_objects = 0;
+#if HAVE_VARNISH_V2
+ conf->collect_purge = 0;
+#else
+ conf->collect_ban = 0;
+#endif
+ conf->collect_session = 0;
conf->collect_shm = 1;
#if HAVE_VARNISH_V2
conf->collect_sm = 0;
conf->collect_sma = 0;
#endif
conf->collect_sms = 0;
+ conf->collect_struct = 0;
conf->collect_totals = 0;
+ conf->collect_uptime = 0;
+ conf->collect_vcl = 0;
+ conf->collect_workers = 0;
return (0);
} /* }}} int varnish_config_apply_default */
cf_util_get_boolean (child, &conf->collect_connections);
else if (strcasecmp ("CollectESI", child->key) == 0)
cf_util_get_boolean (child, &conf->collect_esi);
+#ifdef HAVE_VARNISH_V3
+ else if (strcasecmp ("CollectDirectorDNS", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_dirdns);
+#endif
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 ("CollectObjects", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_objects);
+#if HAVE_VARNISH_V2
+ else if (strcasecmp ("CollectPurge", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_purge);
+#else
+ else if (strcasecmp ("CollectBan", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_ban);
+#endif
+ else if (strcasecmp ("CollectSession", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_session);
else if (strcasecmp ("CollectSHM", child->key) == 0)
cf_util_get_boolean (child, &conf->collect_shm);
else if (strcasecmp ("CollectSMS", child->key) == 0)
else if (strcasecmp ("CollectSM", child->key) == 0)
cf_util_get_boolean (child, &conf->collect_sm);
#endif
+ else if (strcasecmp ("CollectStruct", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_struct);
else if (strcasecmp ("CollectTotals", child->key) == 0)
cf_util_get_boolean (child, &conf->collect_totals);
+ else if (strcasecmp ("CollectUptime", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_uptime);
+ else if (strcasecmp ("CollectVCL", child->key) == 0)
+ cf_util_get_boolean (child, &conf->collect_vcl);
else if (strcasecmp ("CollectWorkers", child->key) == 0)
cf_util_get_boolean (child, &conf->collect_workers);
else
&& !conf->collect_connections
&& !conf->collect_esi
&& !conf->collect_backend
+#ifdef HAVE_VARNISH_V3
+ && !conf->collect_dirdns
+#endif
&& !conf->collect_fetch
&& !conf->collect_hcb
+ && !conf->collect_objects
+#if HAVE_VARNISH_V2
+ && !conf->collect_purge
+#else
+ && !conf->collect_ban
+#endif
+ && !conf->collect_session
&& !conf->collect_shm
&& !conf->collect_sms
#if HAVE_VARNISH_V2
&& !conf->collect_sma
&& !conf->collect_sm
#endif
+ && !conf->collect_struct
&& !conf->collect_totals
+ && !conf->collect_uptime
+ && !conf->collect_vcl
&& !conf->collect_workers)
{
WARNING ("Varnish plugin: No metric has been configured for "
diff --git a/src/write_graphite.c b/src/write_graphite.c
index 99c6f4d80a91a669ee0ac86f0bfe0620de6bb13f..6124d33edf5a07ae26f922b1cc7a151a959b6c28 100644 (file)
--- a/src/write_graphite.c
+++ b/src/write_graphite.c
* <Carbon>
* Host "localhost"
* Port "2003"
+ * Protocol "udp"
+ * LogSendErrors true
* Prefix "collectd"
* </Carbon>
* </Plugin>
# define WG_DEFAULT_SERVICE "2003"
#endif
+#ifndef WG_DEFAULT_PROTOCOL
+# define WG_DEFAULT_PROTOCOL "udp"
+#endif
+
+#ifndef WG_DEFAULT_LOG_SEND_ERRORS
+# define WG_DEFAULT_LOG_SEND_ERRORS 1
+#endif
+
#ifndef WG_DEFAULT_ESCAPE
# define WG_DEFAULT_ESCAPE '_'
#endif
char *node;
char *service;
+ char *protocol;
+ _Bool log_send_errors;
char *prefix;
char *postfix;
char escape_char;
ssize_t status = 0;
status = swrite (cb->sock_fd, cb->send_buf, strlen (cb->send_buf));
- if (status < 0)
+ if (cb->log_send_errors && status < 0)
{
char errbuf[1024];
- ERROR ("write_graphite plugin: send failed with status %zi (%s)",
+ ERROR ("write_graphite plugin: send to %s:%s (%s) failed with status %zi (%s)",
+ cb->node, cb->service, cb->protocol,
status, sstrerror (errno, errbuf, sizeof (errbuf)));
const char *node = cb->node ? cb->node : WG_DEFAULT_NODE;
const char *service = cb->service ? cb->service : WG_DEFAULT_SERVICE;
+ const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
if (cb->sock_fd > 0)
return (0);
ai_hints.ai_flags |= AI_ADDRCONFIG;
#endif
ai_hints.ai_family = AF_UNSPEC;
- ai_hints.ai_socktype = SOCK_STREAM;
+
+ if (0 == strcasecmp ("tcp", protocol))
+ ai_hints.ai_socktype = SOCK_STREAM;
+ else
+ ai_hints.ai_socktype = SOCK_DGRAM;
ai_list = NULL;
status = getaddrinfo (node, service, &ai_hints, &ai_list);
if (status != 0)
{
- ERROR ("write_graphite plugin: getaddrinfo (%s, %s) failed: %s",
- node, service, gai_strerror (status));
+ ERROR ("write_graphite plugin: getaddrinfo (%s, %s, %s) failed: %s",
+ node, service, protocol, gai_strerror (status));
return (-1);
}
{
char errbuf[1024];
c_complain (LOG_ERR, &cb->init_complaint,
- "write_graphite plugin: Connecting to %s:%s failed. "
- "The last error was: %s", node, service,
+ "write_graphite plugin: Connecting to %s:%s via %s failed. "
+ "The last error was: %s", node, service, protocol,
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
else
{
c_release (LOG_INFO, &cb->init_complaint,
- "write_graphite plugin: Successfully connected to %s:%s.",
- node, service);
+ "write_graphite plugin: Successfully connected to %s:%s via %s.",
+ node, service, protocol);
}
wg_reset_buffer (cb);
sfree(cb->name);
sfree(cb->node);
+ sfree(cb->protocol);
sfree(cb->service);
sfree(cb->prefix);
sfree(cb->postfix);
cb->send_buf_fill += message_len;
cb->send_buf_free -= message_len;
- DEBUG ("write_graphite plugin: [%s]:%s buf %zu/%zu (%.1f %%) \"%s\"",
+ DEBUG ("write_graphite plugin: [%s]:%s (%s) buf %zu/%zu (%.1f %%) \"%s\"",
cb->node,
cb->service,
+ cb->protocol,
cb->send_buf_fill, sizeof (cb->send_buf),
100.0 * ((double) cb->send_buf_fill) / ((double) sizeof (cb->send_buf)),
message);
user_data_t user_data;
char callback_name[DATA_MAX_NAME_LEN];
int i;
+ int status = 0;
cb = malloc (sizeof (*cb));
if (cb == NULL)
cb->name = NULL;
cb->node = NULL;
cb->service = NULL;
+ cb->protocol = NULL;
+ cb->log_send_errors = WG_DEFAULT_LOG_SEND_ERRORS;
cb->prefix = NULL;
cb->postfix = NULL;
cb->escape_char = WG_DEFAULT_ESCAPE;
/* FIXME: Legacy configuration syntax. */
if (strcasecmp ("Carbon", ci->key) != 0)
{
- int status = cf_util_get_string (ci, &cb->name);
+ status = cf_util_get_string (ci, &cb->name);
if (status != 0)
{
wg_callback_free (cb);
cf_util_get_string (child, &cb->node);
else if (strcasecmp ("Port", child->key) == 0)
cf_util_get_service (child, &cb->service);
+ else if (strcasecmp ("Protocol", child->key) == 0)
+ {
+ cf_util_get_string (child, &cb->protocol);
+
+ if (strcasecmp ("UDP", cb->protocol) != 0 &&
+ strcasecmp ("TCP", cb->protocol) != 0)
+ {
+ ERROR ("write_graphite plugin: Unknown protocol (%s)",
+ cb->protocol);
+ status = -1;
+ }
+ }
+ else if (strcasecmp ("LogSendErrors", child->key) == 0)
+ cf_util_get_boolean (child, &cb->log_send_errors);
else if (strcasecmp ("Prefix", child->key) == 0)
cf_util_get_string (child, &cb->prefix);
else if (strcasecmp ("Postfix", child->key) == 0)
{
ERROR ("write_graphite plugin: Invalid configuration "
"option: %s.", child->key);
+ status = -1;
}
+
+ if (status != 0)
+ break;
+ }
+
+ if (status != 0)
+ {
+ wg_callback_free (cb);
+ return (status);
}
/* FIXME: Legacy configuration syntax. */
if (cb->name == NULL)
- ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s/%s",
+ ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s/%s/%s",
cb->node != NULL ? cb->node : WG_DEFAULT_NODE,
- cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE);
+ cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE,
+ cb->protocol != NULL ? cb->protocol : WG_DEFAULT_PROTOCOL);
else
ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
cb->name);
diff --git a/src/write_riemann.c b/src/write_riemann.c
index 15bb23787c59f7b4f01d543c621a75fee2be42f4..3345d0444a94653a4e3be42a9d9051bfd264e790 100644 (file)
--- a/src/write_riemann.c
+++ b/src/write_riemann.c
#define RIEMANN_HOST "localhost"
#define RIEMANN_PORT "5555"
+#define RIEMANN_TTL_FACTOR 2.0
struct riemann_host {
char *name;
char *service;
_Bool use_tcp;
int s;
+ double ttl_factor;
int reference_count;
};
@@ -376,6 +378,7 @@ static Event *riemann_value_to_protobuf (struct riemann_host const *host, /* {{{
Event *event;
char name_buffer[5 * DATA_MAX_NAME_LEN];
char service_buffer[6 * DATA_MAX_NAME_LEN];
+ double ttl;
int i;
event = malloc (sizeof (*event));
@@ -390,7 +393,9 @@ static Event *riemann_value_to_protobuf (struct riemann_host const *host, /* {{{
event->host = strdup (vl->host);
event->time = CDTIME_T_TO_TIME_T (vl->time);
event->has_time = 1;
- event->ttl = CDTIME_T_TO_TIME_T (2 * vl->interval);
+
+ ttl = CDTIME_T_TO_DOUBLE (vl->interval) * host->ttl_factor;
+ event->ttl = (float) ttl;
event->has_ttl = 1;
riemann_event_add_attribute (event, "plugin", vl->plugin);
host->store_rates = 1;
host->always_append_ds = 0;
host->use_tcp = 0;
+ host->ttl_factor = RIEMANN_TTL_FACTOR;
status = cf_util_get_string (ci, &host->name);
if (status != 0) {
&host->always_append_ds);
if (status != 0)
break;
+ } else if (strcasecmp ("TTLFactor", child->key) == 0) {
+ double tmp = NAN;
+ status = cf_util_get_double (child, &tmp);
+ if (status != 0)
+ break;
+ if (tmp >= 2.0) {
+ host->ttl_factor = tmp;
+ } else if (tmp >= 1.0) {
+ NOTICE ("write_riemann plugin: The configured "
+ "TTLFactor is very small "
+ "(%.1f). A value of 2.0 or "
+ "greater is recommended.",
+ tmp);
+ host->ttl_factor = tmp;
+ } else if (tmp > 0.0) {
+ WARNING ("write_riemann plugin: The configured "
+ "TTLFactor is too small to be "
+ "useful (%.1f). I'll use it "
+ "since the user knows best, "
+ "but under protest.",
+ tmp);
+ host->ttl_factor = tmp;
+ } else { /* zero, negative and NAN */
+ ERROR ("write_riemann plugin: The configured "
+ "TTLFactor is invalid (%.1f).",
+ tmp);
+ }
} else {
WARNING("write_riemann plugin: ignoring unknown config "
"option: \"%s\"", child->key);
diff --git a/src/zfs_arc.c b/src/zfs_arc.c
index aa900193b834e32b5d71c282f11663fe824a4e47..2edba6d1b68d4abc803b06145d6b2f5376503eca 100644 (file)
--- a/src/zfs_arc.c
+++ b/src/zfs_arc.c
* collectd - src/zfs_arc.c
* Copyright (C) 2009 Anthony Dewhurst
* Copyright (C) 2012 Aurelien Rougemont
+ * Copyright (C) 2013 Xin Li
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Authors:
* Anthony Dewhurst <dewhurst at gmail>
* Aurelien Rougemont <beorn at gandi.net>
+ * Xin Li <delphij at FreeBSD.org>
**/
#include "collectd.h"
* Global variables
*/
+#if !defined(__FreeBSD__)
extern kstat_ctl_t *kc;
+static long long get_zfs_value(kstat_t *ksp, char *name)
+{
+
+ return (get_kstat_value(ksp, name));
+}
+#else
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+const char zfs_arcstat[] = "kstat.zfs.misc.arcstats.";
+
+#if !defined(kstat_t)
+typedef void kstat_t;
+#endif
+
+static long long get_zfs_value(kstat_t *dummy __attribute__((unused)),
+ char const *name)
+{
+ char buffer[256];
+ long long value;
+ size_t valuelen = sizeof(value);
+ int rv;
+
+ ssnprintf (buffer, sizeof (buffer), "%s%s", zfs_arcstat, name);
+ rv = sysctlbyname (buffer, (void *) &value, &valuelen,
+ /* new value = */ NULL, /* new length = */ (size_t) 0);
+ if (rv == 0)
+ return (value);
+
+ return (-1);
+}
+#endif
+
static void za_submit (const char* type, const char* type_instance, value_t* values, int values_len)
{
value_list_t vl = VALUE_LIST_INIT;
long long tmp;
value_t v;
- tmp = get_kstat_value (ksp, (char *)kstat_value);
+ tmp = get_zfs_value (ksp, (char *)kstat_value);
if (tmp == -1LL)
{
ERROR ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
long long tmp;
value_t v;
- tmp = get_kstat_value (ksp, (char *)kstat_value);
+ tmp = get_zfs_value (ksp, (char *)kstat_value);
if (tmp == -1LL)
{
ERROR ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
value_t l2_io[2];
kstat_t *ksp = NULL;
+#if !defined(__FreeBSD__)
get_kstat (&ksp, "zfs", 0, "arcstats");
if (ksp == NULL)
{
ERROR ("zfs_arc plugin: Cannot find zfs:0:arcstats kstat.");
return (-1);
}
+#endif
/* Sizes */
za_read_gauge (ksp, "size", "cache_size", "arc");
za_read_gauge (ksp, "l2_size", "cache_size", "L2");
- /* Operations */
+ /* Operations */
za_read_derive (ksp, "allocated","cache_operation", "allocated");
za_read_derive (ksp, "deleted", "cache_operation", "deleted");
za_read_derive (ksp, "stolen", "cache_operation", "stolen");
- /* Issue indicators */
- za_read_derive (ksp, "mutex_miss", "mutex_operations", "miss");
+ /* Issue indicators */
+ za_read_derive (ksp, "mutex_miss", "mutex_operations", "miss");
za_read_derive (ksp, "hash_collisions", "hash_collisions", "");
- /* Evictions */
+ /* Evictions */
za_read_derive (ksp, "evict_l2_cached", "cache_eviction", "cached");
za_read_derive (ksp, "evict_l2_eligible", "cache_eviction", "eligible");
za_read_derive (ksp, "evict_l2_ineligible", "cache_eviction", "ineligible");
za_read_derive (ksp, "prefetch_metadata_misses", "cache_result", "prefetch_metadata-miss");
/* Ratios */
- arc_hits = (gauge_t) get_kstat_value(ksp, "hits");
- arc_misses = (gauge_t) get_kstat_value(ksp, "misses");
- l2_hits = (gauge_t) get_kstat_value(ksp, "l2_hits");
- l2_misses = (gauge_t) get_kstat_value(ksp, "l2_misses");
+ arc_hits = (gauge_t) get_zfs_value(ksp, "hits");
+ arc_misses = (gauge_t) get_zfs_value(ksp, "misses");
+ l2_hits = (gauge_t) get_zfs_value(ksp, "l2_hits");
+ l2_misses = (gauge_t) get_zfs_value(ksp, "l2_misses");
za_submit_ratio ("arc", arc_hits, arc_misses);
za_submit_ratio ("L2", l2_hits, l2_misses);
/* I/O */
- l2_io[0].derive = get_kstat_value(ksp, "l2_read_bytes");
- l2_io[1].derive = get_kstat_value(ksp, "l2_write_bytes");
+ l2_io[0].derive = get_zfs_value(ksp, "l2_read_bytes");
+ l2_io[1].derive = get_zfs_value(ksp, "l2_write_bytes");
za_submit ("io_octets", "L2", l2_io, /* num values = */ 2);
static int za_init (void) /* {{{ */
{
+#if !defined(__FreeBSD__)
/* kstats chain already opened by update_kstat (using *kc), verify everything went fine. */
if (kc == NULL)
{
ERROR ("zfs_arc plugin: kstat chain control structure not available.");
return (-1);
}
+#endif
return (0);
} /* }}} int za_init */