From: Florian Forster Date: Sat, 1 Jun 2013 07:25:28 +0000 (+0200) Subject: Merge branch 'yaccz/curl-status' X-Git-Tag: collectd-5.4.0~31 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=42612558ff8279a80e32cc68d26b1b1bee800f4f;hp=14fcf8a4f648e6ed2ff5f2bc8d4f70057702b17e;p=collectd.git Merge branch 'yaccz/curl-status' --- diff --git a/AUTHORS b/AUTHORS index 45645d1a..9df0f7ae 100644 --- a/AUTHORS +++ b/AUTHORS @@ -47,6 +47,9 @@ Bruno Prémont especially a nasty bug in the network plugin. - Wireshark dissector. +Chad Malfait + - LVM plugin. + Chris Lundquist - Improvements to the write_mongodb plugin. @@ -73,6 +76,9 @@ Doug MacEachern Edward “Koko” Konetzko - fscache plugin. +Evan Felix + - mic plugin. + Fabian Linzberger - Percentage aggregation for `collectd-nagios'. @@ -126,6 +132,7 @@ Michael Hanselmann Michael Stapelberg - OpenBSD port of the tcpconns plugin. + - cgroups plugin. Michał Mirosław - thermal plugin. diff --git a/README b/README index c3c45472..04e87abf 100644 --- a/README +++ b/README @@ -37,6 +37,9 @@ Features 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. @@ -135,6 +138,10 @@ Features - 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. @@ -158,6 +165,10 @@ Features 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. diff --git a/configure.in b/configure.in index a62d608b..ba52389e 100644 --- a/configure.in +++ b/configure.in @@ -2152,6 +2152,58 @@ AC_SUBST(JAVA_LIBS) 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="" @@ -4152,6 +4204,63 @@ fi 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="" @@ -4578,6 +4687,7 @@ dependency_error="no" plugin_ascent="no" plugin_battery="no" plugin_bind="no" +plugin_cgroups="no" plugin_conntrack="no" plugin_contextswitch="no" plugin_cpu="no" @@ -4621,6 +4731,7 @@ then plugin_battery="yes" plugin_conntrack="yes" plugin_contextswitch="yes" + plugin_cgroups="yes" plugin_cpu="yes" plugin_cpufreq="yes" plugin_disk="yes" @@ -4629,6 +4740,7 @@ then plugin_interface="yes" plugin_irq="yes" plugin_load="yes" + plugin_lvm="yes" plugin_memory="yes" plugin_nfs="yes" plugin_numa="yes" @@ -4903,6 +5015,7 @@ AC_PLUGIN([csv], [yes], [CSV output plugin]) 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]) @@ -4925,6 +5038,7 @@ AC_PLUGIN([libvirt], [$plugin_libvirt], [Virtual machine statistics]) AC_PLUGIN([load], [$plugin_load], [System load]) AC_PLUGIN([logfile], [yes], [File logging plugin]) AC_PLUGIN([lpar], [$with_perfstat], [AIX logical partitions statistics]) +AC_PLUGIN([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]) @@ -4936,6 +5050,7 @@ AC_PLUGIN([md], [$have_linux_raid_md_u_h], [md (Linux software RAID) de 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]) @@ -5171,6 +5286,7 @@ cat <delivery_mode = CAMQP_DM_VOLATILE; conf->store_rates = 0; + conf->graphite_flags = 0; /* publish & graphite only */ conf->prefix = NULL; conf->postfix = NULL; @@ -942,6 +943,12 @@ static int camqp_config_connection (oconfig_item_t *ci, /* {{{ */ } 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 new file mode 100644 index 00000000..ffb1740a --- /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 + * Florian Forster + **/ + +#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 5af15684..4a88e664 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -18,6 +18,13 @@ #TypesDB "@prefix@/share/@PACKAGE_NAME@/types.db" #----------------------------------------------------------------------------# +# When enabled, plugins are loaded automatically with the default options # +# when an appropriate 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: # # # @@ -72,6 +79,7 @@ #@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 @@ -99,6 +107,7 @@ #@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 @@ -156,6 +165,7 @@ #@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 @@ -1026,6 +1036,24 @@ # UUIDFile "/etc/uuid" # +# +# 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 +# + # # This tag support an argument if you want to # monitor the local instance just use @@ -1034,15 +1062,23 @@ # # 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 # # diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 8606d3e0..b66c4350 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -68,17 +68,33 @@ directory for the daemon. =item B I -Loads the plugin I. There must be at least one such line or B -will be mostly useless. +Loads the plugin I. This is required to load plugins, unless the +B option is enabled (see below). Without any loaded plugins, +I will be mostly useless. -Starting with collectd 4.9, this may also be a block in which further options -affecting the behavior of B may be specified. The following -options are allowed inside a B block: +Only the first B 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 +block I then appropriate B statement. The downside is that if +you have multiple conflicting B 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. - - Globals true - Interval 10 - +B may either be a simple configuration I or a I +with additional options, affecting the behavior of B. A simple +statement looks like this: + + LoadPlugin "cpu" + +Options inside a B block can override default settings and +influence the way plugins are loaded, e.g.: + + + Globals true + Interval 60 + + +The following options are valid inside B blocks: =over 4 @@ -109,6 +125,19 @@ interval, that setting will take precedence. =back +=item B B|B + +When set to B (the default), each plugin needs to be loaded explicitly, +using the B statement documented above. If a +BPluginE...E> 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, explicit B statements are not required. Each +BPluginE...E> block acts as if it was immediately preceded by a +B statement. B statements are still required for +plugins that don't provide any configuration, e.g. the I. + =item B I [I] If I points to a file, includes that file. If I points to a @@ -852,6 +881,29 @@ By default no detailed zone information is collected. =back +=head2 Plugin C + +This plugin collects the CPU user/system time for each I by reading the +F files in the first cpuacct-mountpoint (typically +F on machines using systemd). + +=over 4 + +=item B I + +Select I based on the name. Whether only matching I are +collected or if they are ignored is controlled by the B option; +see below. + +=item B B|B + +Invert the selection: If set to true, all cgroups I 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 cgroups are selected. + +=back + =head2 Plugin C This plugin doesn't have any options. It reads @@ -1459,6 +1511,15 @@ Enable this option if inodes are a scarce resource for you, usually because many small files are stored on the disk. This is a usual scenario for mail transfer agents and web caches. +=item B B|B + +Enables or disables reporting of disk space and inodes as a percentage. +Defaults to B. + +This is useful for deploying I 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 @@ -2207,7 +2268,7 @@ interpreted. For a description of match blocks, please see L<"Plugin tail">. =head2 Plugin C -The C connects to a memcached server and queries statistics +The B connects to a memcached server and queries statistics about cache utilization, memory and bandwidth used. L @@ -2239,6 +2300,166 @@ setting is given, the B and B settings are ignored. =back +=head2 Plugin C + +The B gathers CPU statistics, memory usage and temperatures from +Intel's Many Integrated Core (MIC) systems. + +B + + + ShowCPU true + ShowCPUCores true + ShowMemory true + + ShowTemperatures true + Temperature vddg + Temperature vddq + IgnoreSelectedTemperature true + + ShowPower true + Power total0 + Power total1 + IgnoreSelectedPower true + + +The following options are valid inside the Bmic> block: + +=over 4 + +=item B B|B + +If enabled (the default) a sum of the CPU usage accross all cores is reported. + +=item B B|B + +If enabled (the default) per-core CPU usage is reported. + +=item B B|B + +If enabled (the default) the physical memory usage of the MIC system is +reported. + +=item B B|B + +If enabled (the default) various temperatures of the MIC system are reported. + +=item B I + +This option controls which temperatures are being reported. Whether matching +temperatures are being ignored or I matching temperatures are reported +depends on the B setting below. By default I +temperatures are reported. + +=item B B|B + +Controls the behavior of the B setting above. If set to B +(the default) only temperatures matching a B option are reported +or, if no B option is specified, all temperatures are reported. If +set to B, matching temperatures are I 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 B|B + +If enabled (the default) various temperatures of the MIC system are reported. + +=item B I + +This option controls which power readings are being reported. Whether matching +power readings are being ignored or I matching power readings are reported +depends on the B setting below. By default I +power readings are reported. + +=item B B|B + +Controls the behavior of the B setting above. If set to B +(the default) only power readings matching a B option are reported +or, if no B option is specified, all power readings are reported. If +set to B, matching power readings are I 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 The B connects to a Modbus "slave" via Modbus/TCP and reads @@ -2246,7 +2467,7 @@ register values. It supports reading single registers (unsigned 16Ebit values), large integer values (unsigned 32Ebit values) and floating point values (two registers interpreted as IEEE floats in big endian notation). -Synopsis: +B RegisterBase 0 @@ -5497,6 +5718,17 @@ and closed connections. True by default. 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 B|B + +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 B|B + +DNS director lookup cache statistics. Only available with Varnish 3.x. False by +default. + =item B B|B Edge Side Includes (ESI) parse statistics. False by default. @@ -5510,10 +5742,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 B|B + +Statistics on cached objects: number of objects expired, nuked (prematurely +expired), saved, moved, etc. False by default. + +=item B B|B + +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 B|B + +Client session statistics. Number of past and current sessions, session herd and +linger counters, etc. False by default. + =item B B|B -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 B|B @@ -5522,13 +5771,28 @@ component is used internally only. False by default. =item B B|B -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 B|B + +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 B|B Collects overview counters, such as the number of sessions created, the number of requests and bytes transferred. False by default. +=item B B|B + +Varnish uptime. False by default. + +=item B B|B + +Number of total (available + discarded) VCL (config files). False by default. + =item B B|B Collect statistics about worker threads. False by default. diff --git a/src/common.c b/src/common.c index d617832c..d963efa5 100644 --- a/src/common.c +++ b/src/common.c @@ -86,6 +86,47 @@ int ssnprintf (char *dest, size_t n, const char *format, ...) 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; @@ -1213,18 +1254,25 @@ int walk_directory (const char *dir, dirwalk_callback_f callback, 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 ae8e311f..317be8d1 100644 --- a/src/common.h +++ b/src/common.h @@ -56,7 +56,13 @@ struct rate_to_value_state_s 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); @@ -303,7 +309,7 @@ typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename, 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 ac5e8edc..876ee23e 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -110,6 +110,7 @@ static cf_global_option_t cf_global_options[] = {"ReadThreads", NULL, "5"}, {"WriteThreads", NULL, "5"}, {"Timeout", NULL, "2"}, + {"AutoLoadPlugin", NULL, "false"}, {"PreCacheChain", NULL, "PreCache"}, {"PostCacheChain", NULL, "PostCache"} }; @@ -277,21 +278,6 @@ static int dispatch_loadplugin (const oconfig_item_t *ci) 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); @@ -394,6 +380,19 @@ static int dispatch_block_plugin (oconfig_item_t *ci) 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_xml.c b/src/curl_xml.c index 0b413047..5adaf067 100644 --- a/src/curl_xml.c +++ b/src/curl_xml.c @@ -966,7 +966,7 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ 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"); @@ -978,11 +978,10 @@ static int cx_config_add_url (oconfig_item_t *ci) /* {{{ */ 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 ded374b9..5ff3f59b 100644 --- a/src/df.c +++ b/src/df.c @@ -54,7 +54,8 @@ static const char *config_keys[] = "IgnoreSelected", "ReportByDevice", "ReportReserved", - "ReportInodes" + "ReportInodes", + "ReportPercentage" }; static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); @@ -64,6 +65,7 @@ static ignorelist_t *il_fstype = NULL; static _Bool by_device = 0; static _Bool report_inodes = 0; +static _Bool report_percentage = 0; static int df_init (void) { @@ -132,6 +134,15 @@ static int df_config (const char *key, const char *value) return (0); } + else if (strcasecmp (key, "ReportPercentage") == 0) + { + if (IS_TRUE (value)) + report_percentage = 1; + else + report_percentage = 0; + + return (0); + } return (-1); } @@ -210,7 +221,7 @@ static int df_read (void) 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) @@ -218,13 +229,13 @@ static int df_read (void) 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); continue; } - } - else + } + else { if (strcmp (mnt_ptr->dir, "/") == 0) { @@ -274,12 +285,30 @@ static int df_read (void) 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 (report_percentage && (statbuf.f_blocks > 0)) + { + uint64_t blk_total = (uint64_t) statbuf.f_blocks; + char plugin_instance[DATA_MAX_NAME_LEN]; + + ssnprintf (plugin_instance, sizeof (plugin_instance), + "%s-bytes", disk_name); + + df_submit_one (plugin_instance, "percent", "free", + 100.0 * ((gauge_t) blk_free) / ((gauge_t) blk_total)); + df_submit_one (plugin_instance, "percent", "reserved", + 100.0 * ((gauge_t) blk_reserved) / ((gauge_t) blk_total)); + df_submit_one (plugin_instance, "percent", "used", + 100.0 * ((gauge_t) blk_used) / ((gauge_t) blk_total)); + } + else if (!report_percentage) + { + 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)); + } /* inode handling */ if (report_inodes) @@ -297,13 +326,31 @@ static int df_read (void) 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 (report_percentage && (statbuf.f_files > 0)) + { + uint64_t inode_total = (uint64_t) statbuf.f_files; + char plugin_instance[DATA_MAX_NAME_LEN]; + + ssnprintf (plugin_instance, sizeof (plugin_instance), + "%s-inodes", disk_name); + + df_submit_one (plugin_instance, "percent", "free", + 100.0 * ((gauge_t) inode_free) / ((gauge_t) inode_total)); + df_submit_one (plugin_instance, "percent", "reserved", + 100.0 * ((gauge_t) inode_reserved) / ((gauge_t) inode_total)); + df_submit_one (plugin_instance, "percent", "used", + 100.0 * ((gauge_t) inode_used) / ((gauge_t) inode_total)); + } + else if (!report_percentage) + { + 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 new file mode 100644 index 00000000..6ef3a7b2 --- /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 + **/ + +#include + +#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 new file mode 100644 index 00000000..570da51b --- /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 + **/ + +#include "collectd.h" +#include "plugin.h" +#include "common.h" +#include "utils_ignorelist.h" + +#include +#include +#include +#include +#include + +#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;irf_name); + sfree (rf->rf_name); destroy_callback ((callback_func_t *) rf); rf = NULL; continue; @@ -830,8 +833,52 @@ void plugin_set_dir (const char *dir) } } +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; @@ -843,15 +890,38 @@ int plugin_load (const char *type, uint32_t flags) 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); @@ -898,13 +968,14 @@ int plugin_load (const char *type, uint32_t flags) 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); } } @@ -912,7 +983,7 @@ int plugin_load (const char *type, uint32_t flags) if (filename[0] == 0) ERROR ("plugin_load: Could not find plugin \"%s\" in %s", - type, dir); + plugin_name, dir); return (ret); } @@ -1048,7 +1119,7 @@ int plugin_register_read (const char *name, 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 (); @@ -1080,7 +1151,7 @@ int plugin_register_complex_read (const char *group, const char *name, 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); @@ -1657,6 +1728,8 @@ void plugin_shutdown_all (void) destroy_all_callbacks (&list_notification); destroy_all_callbacks (&list_shutdown); destroy_all_callbacks (&list_log); + + plugin_free_loaded (); } /* void plugin_shutdown_all */ int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */ diff --git a/src/plugin.h b/src/plugin.h index 635ff308..8f0c6d86 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -223,7 +223,8 @@ void plugin_set_dir (const char *dir); * 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/snmp.c b/src/snmp.c index cff38a40..4f849320 100644 --- a/src/snmp.c +++ b/src/snmp.c @@ -1378,9 +1378,8 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data) /* Calculate the current suffix. This is later used to check that the * suffix is increasing. This also checks if we left the subtree */ - int ret; - ret = csnmp_oid_suffix (&suffix, &vb_name, data->values + i); - if (ret != 0) + status = csnmp_oid_suffix (&suffix, &vb_name, data->values + i); + if (status != 0) { DEBUG ("snmp plugin: host = %s; data = %s; i = %i; " "Value probably left its subtree.", diff --git a/src/thermal.c b/src/thermal.c index 603f85bb..27c92bc7 100644 --- a/src/thermal.c +++ b/src/thermal.c @@ -80,12 +80,12 @@ static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir, 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 fa24e6e2..950f6b0d 100644 --- a/src/types.db +++ b/src/types.db @@ -6,6 +6,7 @@ apache_requests value:DERIVE:0:U 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 @@ -110,6 +111,7 @@ node_octets rx:DERIVE:0:U, tx: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 @@ -166,6 +168,7 @@ timeleft 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 @@ -174,6 +177,7 @@ total_time_in_ms 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 @@ -187,6 +191,7 @@ voltage value:GAUGE:U: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 602f47af..f7bca416 100644 --- a/src/varnish.c +++ b/src/varnish.c @@ -23,110 +23,6 @@ * Florian octo Forster **/ -/** - * 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" @@ -151,15 +47,28 @@ struct user_config_s { _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; /* }}} */ @@ -238,13 +147,30 @@ static void varnish_monitor (const user_config_t *conf, /* {{{ */ 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 } @@ -267,7 +193,14 @@ static void varnish_monitor (const user_config_t *conf, /* {{{ */ #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) @@ -290,6 +223,14 @@ static void varnish_monitor (const user_config_t *conf, /* {{{ */ 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) @@ -302,6 +243,80 @@ static void varnish_monitor (const user_config_t *conf, /* {{{ */ 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 */ @@ -358,6 +373,32 @@ static void varnish_monitor (const user_config_t *conf, /* {{{ */ 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 */ @@ -376,6 +417,22 @@ static void varnish_monitor (const user_config_t *conf, /* {{{ */ 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 */ @@ -393,6 +450,11 @@ static void varnish_monitor (const user_config_t *conf, /* {{{ */ 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 */ @@ -486,16 +548,30 @@ static int varnish_config_apply_default (user_config_t *conf) /* {{{ */ 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 */ @@ -580,12 +656,27 @@ static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */ 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) @@ -596,8 +687,14 @@ static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */ 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 @@ -612,15 +709,28 @@ static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */ && !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 "