From: Florian Forster Date: Wed, 27 Sep 2017 20:24:21 +0000 (+0200) Subject: Merge remote-tracking branch 'github/pr/2449' X-Git-Tag: collectd-5.8.0~72 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=df6a1dedda953cb34fc4d16d390c823021d0916d;hp=81eeac695e82db28b2e5a38ca0947650c43cf028 Merge remote-tracking branch 'github/pr/2449' --- diff --git a/Makefile.am b/Makefile.am index 24c5b8c0..04636b3f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1680,7 +1680,9 @@ endif if BUILD_PLUGIN_TURBOSTAT pkglib_LTLIBRARIES += turbostat.la -turbostat_la_SOURCES = src/turbostat.c +turbostat_la_SOURCES = \ + src/turbostat.c \ + src/msr-index.h turbostat_la_LDFLAGS = $(PLUGIN_LDFLAGS) endif diff --git a/configure.ac b/configure.ac index 8f2a9ab3..55f78d8a 100644 --- a/configure.ac +++ b/configure.ac @@ -521,32 +521,6 @@ if test "x$ac_system" = "xLinux"; then ]] ) # For the turbostat plugin - AC_CHECK_HEADERS([asm/msr-index.h], - [have_asm_msrindex_h="yes"], - [have_asm_msrindex_h="no"] - ) - - if test "x$have_asm_msrindex_h" = "xyes"; then - AC_CACHE_CHECK([whether asm/msr-index.h has MSR_PKG_C10_RESIDENCY], - [c_cv_have_usable_asm_msrindex_h], - [ - AC_COMPILE_IFELSE( - [ - AC_LANG_PROGRAM( - [[#include]], - [[ - int y = MSR_PKG_C10_RESIDENCY; - return(y); - ]] - ) - ], - [c_cv_have_usable_asm_msrindex_h="yes"], - [c_cv_have_usable_asm_msrindex_h="no"], - ) - ] - ) - fi - AC_CHECK_HEADERS([cpuid.h], [have_cpuid_h="yes"], [have_cpuid_h="no (cpuid.h not found)"] @@ -6227,7 +6201,7 @@ if test "x$ac_system" = "xLinux"; then plugin_ipvs="yes" fi - if test "x$c_cv_have_usable_asm_msrindex_h" = "xyes" && test "x$have_cpuid_h" = "xyes"; then + if test "x$have_cpuid_h" = "xyes"; then plugin_turbostat="yes" fi diff --git a/src/collectd.conf.in b/src/collectd.conf.in index a35fb732..bde168c1 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -591,12 +591,16 @@ # # +# #Plugin "foo" # Instance "foodir" # Name "*.conf" # MTime "-5m" # Size "+10k" # Recursive true # IncludeHidden false +# #FilesSizeType "bytes" +# #FilesCountType "files" +# #TypeInstance "instance" # # @@ -1404,6 +1408,7 @@ # Bucket 0.5 1.0 # -> bucket-latency-foo-0.5_1 # Bucket 1.0 2.0 # -> bucket-latency-foo-1_2 # Bucket 2.0 0 # -> bucket-latency-foo-2_inf +# #BucketType "bucket" # # Type "latency" # Instance "foo" @@ -1533,7 +1538,7 @@ # CollectPurge false # Varnish 2 only # CollectSession false # CollectSHM true -# CollectSMA false # Varnish 2 only +# CollectSMA false # Varnish 2 & 4 only # CollectSMS false # CollectSM false # Varnish 2 only # CollectStruct false @@ -1542,6 +1547,11 @@ # CollectVCL false # CollectVSM false # Varnish 4 only # CollectWorkers false +# CollectLock false # Varnish 4 only +# CollectMempool false # Varnish 4 only +# CollectManagement false # Varnish 4 only +# CollectSMF false # Varnish 4 only +# CollectVBE false # Varnish 4 only # # diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 4b0ddee7..91d53817 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -2743,12 +2743,16 @@ blocks, the following options are recognized: =over 4 +=item B I + +Use I as the plugin name when submitting values. +Defaults to B. + =item B I -Sets the plugin instance to I. That instance name must be unique, but -it's your responsibility, the plugin doesn't check for that. If not given, the -instance is set to the directory name with all slashes replaced by underscores -and all leading underscores removed. +Sets the plugin instance to I. If not given, the instance is set to +the directory name with all slashes replaced by underscores and all leading +underscores removed. Empty value is allowed. =item B I @@ -2794,6 +2798,21 @@ Controls whether or not to include "hidden" files and directories in the count. "Hidden" files and directories are those, whose name begins with a dot. Defaults to I, i.e. by default hidden files and directories are ignored. +=item B I + +Sets the type used to dispatch files combined size. Empty value ("") disables +reporting. Defaults to B. + +=item B I + +Sets the type used to dispatch number of files. Empty value ("") disables +reporting. Defaults to B. + +=item B I + +Sets the I used to dispatch values. Defaults to an empty string +(no plugin instance). + =back =head2 Plugin C @@ -7704,6 +7723,7 @@ user using (extended) regular expressions, as described in L. Percentile 99 Bucket 0 100 + #BucketType "bucket" Type "latency" Instance "foo" @@ -7823,6 +7843,7 @@ B Percentile 99 Bucket 0 100 + BucketType "bucket" =over 4 @@ -7859,11 +7880,17 @@ the following schema: Bucket 20 50 Bucket 50 0 -Metrics are reported with the I C and the I +Metrics are reported with the I set by B option (C +by default) and the I CTypeE[-EInstanceE]-Elower_boundE_Eupper_boundE>. This option may be repeated to calculate more than one rate. +=item B I + +Sets the type used to dispatch B metrics. +Optional, by default C will be used. + =back =back @@ -8215,9 +8242,9 @@ collections. The different bits of this bit mask accepted by this plugin are: Boolean enabling the use of logical core numbering for per core statistics. When enabled, CnE> is used as plugin instance, where I is a -sequential number assigned by the kernel. Otherwise, CnE> is used -where I is the n-th core of the socket, causing name conflicts when there is -more than one socket. +dynamic number assigned by the kernel. Otherwise, CnE> is used +if there is only one package and CnE-coreEmE> if there is +more than one, where I is the n-th core of package I. =back @@ -8323,6 +8350,11 @@ Synopsis: CollectVCL false CollectVSM false CollectWorkers false + CollectLock false + CollectMempool false + CollectManagement false + CollectSMF false + CollectVBE false @@ -8398,7 +8430,10 @@ log messages which is flushed to disk when full. True by default. =item B B|B malloc or umem (umem_alloc(3MALLOC) based) storage statistics. The umem storage -component is Solaris specific. Only available with Varnish 2.x. False by +component is Solaris specific. +Note: SMA and SMF share counters, enable only the one used by the Varnish +instance. +Only available with Varnish 2.x. False by default. =item B B|B @@ -8408,7 +8443,8 @@ component is used internally only. False by default. =item B B|B -file (memory mapped file) storage statistics. Only available with Varnish 2.x. +file (memory mapped file) storage statistics. Only available with Varnish 2.x., +in varnish 4.x. use CollectSMF. False by default. =item B B|B @@ -8439,6 +8475,29 @@ statistics subsystems). Only available with Varnish 4.x. False by default. Collect statistics about worker threads. False by default. +=item B B|B + +Backend counters. Only available with Varnish 4.x. False by default. + +=item B B|B + +file (memory mapped file) storage statistics. Only available with Varnish 4.x. +Note: SMA and SMF share counters, enable only the one used by the Varnish +instance. +Used to be called SM in Varnish 2.x. False by default. + +=item B B|B + +Management process counters. Only available with Varnish 4.x. False by default. + +=item B B|B + +Lock counters. Only available with Varnish 4.x. False by default. + +=item B B|B + +Memory pool counters. Only available with Varnish 4.x. False by default. + =back =head2 Plugin C diff --git a/src/daemon/common.c b/src/daemon/common.c index 3ae61d85..6c856a6b 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -269,7 +269,8 @@ ssize_t swrite(int fd, const void *buf, size_t count) { if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { /* if recv returns zero (even though poll() said there is data to be * read), that means the connection has been closed */ - return errno ? errno : -1; + errno = ECONNRESET; + return -1; } } diff --git a/src/filecount.c b/src/filecount.c index a2ec8e82..5b812b88 100644 --- a/src/filecount.c +++ b/src/filecount.c @@ -37,7 +37,11 @@ struct fc_directory_conf_s { char *path; + char *plugin_name; char *instance; + char *files_size_type; + char *files_num_type; + char *type_instance; int options; @@ -58,31 +62,56 @@ typedef struct fc_directory_conf_s fc_directory_conf_t; static fc_directory_conf_t **directories = NULL; static size_t directories_num = 0; +void fc_free_dir(fc_directory_conf_t *dir) { + sfree(dir->path); + sfree(dir->plugin_name); + sfree(dir->instance); + sfree(dir->files_size_type); + sfree(dir->files_num_type); + sfree(dir->type_instance); + sfree(dir->name); + + sfree(dir); +} /* void fc_free_dir */ + static void fc_submit_dir(const fc_directory_conf_t *dir) { value_list_t vl = VALUE_LIST_INIT; - vl.values = &(value_t){.gauge = (gauge_t)dir->files_num}; - vl.values_len = 1; - sstrncpy(vl.plugin, "filecount", sizeof(vl.plugin)); - sstrncpy(vl.plugin_instance, dir->instance, sizeof(vl.plugin_instance)); - sstrncpy(vl.type, "files", sizeof(vl.type)); + sstrncpy(vl.plugin, dir->plugin_name, sizeof(vl.plugin)); + if (dir->instance != NULL) + sstrncpy(vl.plugin_instance, dir->instance, sizeof(vl.plugin_instance)); + if (dir->type_instance != NULL) + sstrncpy(vl.type_instance, dir->type_instance, sizeof(vl.type_instance)); - plugin_dispatch_values(&vl); + vl.values_len = 1; - vl.values = &(value_t){.gauge = (gauge_t)dir->files_size}; - sstrncpy(vl.type, "bytes", sizeof(vl.type)); + if (dir->files_num_type != NULL) { + vl.values = &(value_t){.gauge = (gauge_t)dir->files_num}; + sstrncpy(vl.type, dir->files_num_type, sizeof(vl.type)); + plugin_dispatch_values(&vl); + } - plugin_dispatch_values(&vl); + if (dir->files_size_type != NULL) { + vl.values = &(value_t){.gauge = (gauge_t)dir->files_size}; + sstrncpy(vl.type, dir->files_size_type, sizeof(vl.type)); + plugin_dispatch_values(&vl); + } } /* void fc_submit_dir */ /* * Config: * * + * Plugin "foo" * Instance "foobar" * Name "*.conf" * MTime -3600 * Size "+10M" + * Recursive true + * IncludeHidden false + * FilesSizeType "bytes" + * FilesCountType "files" + * TypeInstance "instance" * * * @@ -94,7 +123,6 @@ static void fc_submit_dir(const fc_directory_conf_t *dir) { static int fc_config_set_instance(fc_directory_conf_t *dir, const char *str) { char buffer[1024]; char *ptr; - char *copy; sstrncpy(buffer, str, sizeof(buffer)); for (ptr = buffer; *ptr != 0; ptr++) @@ -104,10 +132,7 @@ static int fc_config_set_instance(fc_directory_conf_t *dir, const char *str) { for (ptr = buffer; *ptr == '_'; ptr++) /* do nothing */; - if (*ptr == 0) - return -1; - - copy = strdup(ptr); + char *copy = strdup(ptr); if (copy == NULL) return -1; @@ -130,15 +155,13 @@ static int fc_config_add_dir_instance(fc_directory_conf_t *dir, static int fc_config_add_dir_name(fc_directory_conf_t *dir, oconfig_item_t *ci) { - char *temp; - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING("filecount plugin: The `Name' config option needs exactly one " "string argument."); return -1; } - temp = strdup(ci->values[0].value.string); + char *temp = strdup(ci->values[0].value.string); if (temp == NULL) { ERROR("filecount plugin: strdup failed."); return -1; @@ -152,9 +175,6 @@ static int fc_config_add_dir_name(fc_directory_conf_t *dir, static int fc_config_add_dir_mtime(fc_directory_conf_t *dir, oconfig_item_t *ci) { - char *endptr; - double temp; - if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) && (ci->values[0].type != OCONFIG_TYPE_NUMBER))) { WARNING("filecount plugin: The `MTime' config option needs exactly one " @@ -168,8 +188,8 @@ static int fc_config_add_dir_mtime(fc_directory_conf_t *dir, } errno = 0; - endptr = NULL; - temp = strtod(ci->values[0].value.string, &endptr); + char *endptr = NULL; + double temp = strtod(ci->values[0].value.string, &endptr); if ((errno != 0) || (endptr == NULL) || (endptr == ci->values[0].value.string)) { WARNING("filecount plugin: Converting `%s' to a number failed.", @@ -220,9 +240,6 @@ static int fc_config_add_dir_mtime(fc_directory_conf_t *dir, static int fc_config_add_dir_size(fc_directory_conf_t *dir, oconfig_item_t *ci) { - char *endptr; - double temp; - if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) && (ci->values[0].type != OCONFIG_TYPE_NUMBER))) { WARNING("filecount plugin: The `Size' config option needs exactly one " @@ -236,8 +253,8 @@ static int fc_config_add_dir_size(fc_directory_conf_t *dir, } errno = 0; - endptr = NULL; - temp = strtod(ci->values[0].value.string, &endptr); + char *endptr = NULL; + double temp = strtod(ci->values[0].value.string, &endptr); if ((errno != 0) || (endptr == NULL) || (endptr == ci->values[0].value.string)) { WARNING("filecount plugin: Converting `%s' to a number failed.", @@ -303,9 +320,6 @@ static int fc_config_add_dir_option(fc_directory_conf_t *dir, } /* int fc_config_add_dir_option */ static int fc_config_add_dir(oconfig_item_t *ci) { - fc_directory_conf_t *dir; - int status; - if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING("filecount plugin: `Directory' needs exactly one string " "argument."); @@ -313,7 +327,7 @@ static int fc_config_add_dir(oconfig_item_t *ci) { } /* Initialize `dir' */ - dir = calloc(1, sizeof(*dir)); + fc_directory_conf_t *dir = calloc(1, sizeof(*dir)); if (dir == NULL) { ERROR("filecount plugin: calloc failed."); return -1; @@ -322,23 +336,36 @@ static int fc_config_add_dir(oconfig_item_t *ci) { dir->path = strdup(ci->values[0].value.string); if (dir->path == NULL) { ERROR("filecount plugin: strdup failed."); - sfree(dir); + fc_free_dir(dir); return -1; } - fc_config_set_instance(dir, dir->path); - dir->options = FC_RECURSIVE; dir->name = NULL; + dir->plugin_name = strdup("filecount"); + dir->instance = NULL; + dir->type_instance = NULL; dir->mtime = 0; dir->size = 0; - status = 0; + dir->files_size_type = strdup("bytes"); + dir->files_num_type = strdup("files"); + + if (dir->plugin_name == NULL || dir->files_size_type == NULL || + dir->files_num_type == NULL) { + ERROR("filecount plugin: strdup failed."); + fc_free_dir(dir); + return -1; + } + + int status = 0; for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *option = ci->children + i; - if (strcasecmp("Instance", option->key) == 0) + if (strcasecmp("Plugin", option->key) == 0) + status = cf_util_get_string(option, &dir->plugin_name); + else if (strcasecmp("Instance", option->key) == 0) status = fc_config_add_dir_instance(dir, option); else if (strcasecmp("Name", option->key) == 0) status = fc_config_add_dir_name(dir, option); @@ -350,6 +377,12 @@ static int fc_config_add_dir(oconfig_item_t *ci) { status = fc_config_add_dir_option(dir, option, FC_RECURSIVE); else if (strcasecmp("IncludeHidden", option->key) == 0) status = fc_config_add_dir_option(dir, option, FC_HIDDEN); + else if (strcasecmp("FilesSizeType", option->key) == 0) + status = cf_util_get_string(option, &dir->files_size_type); + else if (strcasecmp("FilesCountType", option->key) == 0) + status = cf_util_get_string(option, &dir->files_num_type); + else if (strcasecmp("TypeInstance", option->key) == 0) + status = cf_util_get_string(option, &dir->type_instance); else { WARNING("filecount plugin: fc_config_add_dir: " "Option `%s' not allowed here.", @@ -361,28 +394,52 @@ static int fc_config_add_dir(oconfig_item_t *ci) { break; } /* for (ci->children) */ - if (status == 0) { - fc_directory_conf_t **temp; + if (status != 0) { + fc_free_dir(dir); + return -1; + } - temp = realloc(directories, sizeof(*directories) * (directories_num + 1)); - if (temp == NULL) { - ERROR("filecount plugin: realloc failed."); - status = -1; - } else { - directories = temp; - directories[directories_num] = dir; - directories_num++; + /* Set default plugin instance */ + if (dir->instance == NULL) { + fc_config_set_instance(dir, dir->path); + if (dir->instance == NULL || strlen(dir->instance) == 0) { + ERROR("filecount plugin: failed to build plugin instance name."); + fc_free_dir(dir); + return -1; } } - if (status != 0) { - sfree(dir->name); + /* Handle disabled types */ + if (strlen(dir->instance) == 0) sfree(dir->instance); - sfree(dir->path); - sfree(dir); + + if (strlen(dir->files_size_type) == 0) + sfree(dir->files_size_type); + + if (strlen(dir->files_num_type) == 0) + sfree(dir->files_num_type); + + if (dir->files_size_type == NULL && dir->files_num_type == NULL) { + WARNING("filecount plugin: Both `FilesSizeType' and `FilesCountType ' " + "are disabled for '%s'. There's no types to report.", + dir->path); + fc_free_dir(dir); + return -1; + } + + /* Ready to add it to list */ + fc_directory_conf_t **temp = + realloc(directories, sizeof(*directories) * (directories_num + 1)); + if (temp == NULL) { + ERROR("filecount plugin: realloc failed."); + fc_free_dir(dir); return -1; } + directories = temp; + directories[directories_num] = dir; + directories_num++; + return 0; } /* int fc_config_add_dir */ @@ -414,14 +471,13 @@ static int fc_read_dir_callback(const char *dirname, const char *filename, fc_directory_conf_t *dir = user_data; char abs_path[PATH_MAX]; struct stat statbuf; - int status; if (dir == NULL) return -1; snprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, filename); - status = lstat(abs_path, &statbuf); + int status = lstat(abs_path, &statbuf); if (status != 0) { ERROR("filecount plugin: stat (%s) failed.", abs_path); return -1; @@ -478,15 +534,13 @@ static int fc_read_dir_callback(const char *dirname, const char *filename, } /* int fc_read_dir_callback */ static int fc_read_dir(fc_directory_conf_t *dir) { - int status; - dir->files_num = 0; dir->files_size = 0; if (dir->mtime != 0) dir->now = time(NULL); - status = + int status = walk_directory(dir->path, fc_read_dir_callback, dir, /* include hidden */ (dir->options & FC_HIDDEN) ? 1 : 0); if (status != 0) { diff --git a/src/memcached.c b/src/memcached.c index 3502e355..90f323f8 100644 --- a/src/memcached.c +++ b/src/memcached.c @@ -5,6 +5,7 @@ * Copyright (C) 2009 Doug MacEachern * Copyright (C) 2009 Franck Lombardi * Copyright (C) 2012 Nicolas Szalay + * Copyright (C) 2017 Pavel Rochnyak * * 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 @@ -26,6 +27,7 @@ * Doug MacEachern * Franck Lombardi * Nicolas Szalay + * Pavel Rochnyak **/ #include "collectd.h" @@ -38,8 +40,12 @@ #include #include +#include + #define MEMCACHED_DEF_HOST "127.0.0.1" #define MEMCACHED_DEF_PORT "11211" +#define MEMCACHED_CONNECT_TIMEOUT 10000 +#define MEMCACHED_IO_TIMEOUT 5000 struct memcached_s { char *name; @@ -47,6 +53,7 @@ struct memcached_s { char *socket; char *connhost; char *connport; + int fd; }; typedef struct memcached_s memcached_t; @@ -57,6 +64,12 @@ static void memcached_free(void *arg) { if (st == NULL) return; + if (st->fd >= 0) { + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; + } + sfree(st->name); sfree(st->host); sfree(st->socket); @@ -86,7 +99,15 @@ static int memcached_connect_unix(memcached_t *st) { if (status != 0) { shutdown(fd, SHUT_RDWR); close(fd); - fd = -1; + return -1; + } + + /* switch to non-blocking mode */ + int flags = fcntl(fd, F_GETFL); + status = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (status != 0) { + close(fd); + return -1; } return fd; @@ -124,16 +145,47 @@ static int memcached_connect_inet(memcached_t *st) { continue; } + /* switch socket to non-blocking mode */ + int flags = fcntl(fd, F_GETFL); + status = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (status != 0) { + close(fd); + fd = -1; + continue; + } + /* connect to the memcached daemon */ status = (int)connect(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); - if (status != 0) { + if (status != 0 && errno != EINPROGRESS) { shutdown(fd, SHUT_RDWR); close(fd); fd = -1; continue; } - /* A socket could be opened and connecting succeeded. We're done. */ + /* Wait until connection establishes */ + struct pollfd pollfd = { + .fd = fd, .events = POLLOUT, + }; + do + status = poll(&pollfd, 1, MEMCACHED_CONNECT_TIMEOUT); + while (status < 0 && errno == EINTR); + if (status <= 0) { + close(fd); + fd = -1; + continue; + } + + /* Check if all is good */ + int socket_error; + status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&socket_error, + &(socklen_t){sizeof(socket_error)}); + if (status != 0 || socket_error != 0) { + close(fd); + fd = -1; + continue; + } + /* A socket is opened and connection succeeded. We're done. */ break; } @@ -141,32 +193,55 @@ static int memcached_connect_inet(memcached_t *st) { return fd; } /* int memcached_connect_inet */ -static int memcached_connect(memcached_t *st) { +static void memcached_connect(memcached_t *st) { + if (st->fd >= 0) + return; + if (st->socket != NULL) - return memcached_connect_unix(st); + st->fd = memcached_connect_unix(st); else - return memcached_connect_inet(st); + st->fd = memcached_connect_inet(st); + + if (st->fd >= 0) + INFO("memcached plugin: Instance \"%s\": connection established.", + st->name); } static int memcached_query_daemon(char *buffer, size_t buffer_size, memcached_t *st) { - int fd, status; + int status; size_t buffer_fill; - fd = memcached_connect(st); - if (fd < 0) { + memcached_connect(st); + if (st->fd < 0) { ERROR("memcached plugin: Instance \"%s\" could not connect to daemon.", st->name); return -1; } - status = (int)swrite(fd, "stats\r\n", strlen("stats\r\n")); + struct pollfd pollfd = { + .fd = st->fd, .events = POLLOUT, + }; + + do + status = poll(&pollfd, 1, MEMCACHED_IO_TIMEOUT); + while (status < 0 && errno == EINTR); + + if (status <= 0) { + ERROR("memcached plugin: poll() failed for write() call."); + close(st->fd); + st->fd = -1; + return -1; + } + + status = (int)swrite(st->fd, "stats\r\n", strlen("stats\r\n")); if (status != 0) { char errbuf[1024]; - ERROR("memcached plugin: write(2) failed: %s", + ERROR("memcached plugin: Instance \"%s\": write(2) failed: %s", st->name, sstrerror(errno, errbuf, sizeof(errbuf))); - shutdown(fd, SHUT_RDWR); - close(fd); + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; return -1; } @@ -174,27 +249,48 @@ static int memcached_query_daemon(char *buffer, size_t buffer_size, memset(buffer, 0, buffer_size); buffer_fill = 0; - while ((status = (int)recv(fd, buffer + buffer_fill, - buffer_size - buffer_fill, /* flags = */ 0)) != - 0) { + pollfd.events = POLLIN; + while (1) { + do + status = poll(&pollfd, 1, MEMCACHED_IO_TIMEOUT); + while (status < 0 && errno == EINTR); + + if (status <= 0) { + ERROR("memcached plugin: Instance \"%s\": Timeout reading from socket", + st->name); + close(st->fd); + st->fd = -1; + return -1; + } + + do + status = (int)recv(st->fd, buffer + buffer_fill, + buffer_size - buffer_fill, /* flags = */ 0); + while (status < 0 && errno == EINTR); + char const end_token[5] = {'E', 'N', 'D', '\r', '\n'}; if (status < 0) { char errbuf[1024]; - if ((errno == EAGAIN) || (errno == EINTR)) + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) continue; - ERROR("memcached: Error reading from socket: %s", - sstrerror(errno, errbuf, sizeof(errbuf))); - shutdown(fd, SHUT_RDWR); - close(fd); + ERROR("memcached plugin: Instance \"%s\": Error reading from socket: %s", + st->name, sstrerror(errno, errbuf, sizeof(errbuf))); + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; return -1; } buffer_fill += (size_t)status; if (buffer_fill > buffer_size) { buffer_fill = buffer_size; - WARNING("memcached plugin: Message was truncated."); + WARNING("memcached plugin: Instance \"%s\": Message was truncated.", + st->name); + shutdown(st->fd, SHUT_RDWR); + close(st->fd); + st->fd = -1; break; } @@ -206,12 +302,11 @@ static int memcached_query_daemon(char *buffer, size_t buffer_size, status = 0; if (buffer_fill == 0) { - WARNING("memcached plugin: No data returned by memcached."); + WARNING("memcached plugin: Instance \"%s\": No data returned by memcached.", + st->name); status = -1; } - shutdown(fd, SHUT_RDWR); - close(fd); return status; } /* int memcached_query_daemon */ @@ -377,6 +472,13 @@ static int memcached_read(user_data_t *user_data) { } else if (FIELD_IS("listen_disabled_num")) { submit_derive("connections", "listen_disabled", atof(fields[2]), st); } + /* + * Total number of connections opened since the server started running + * Report this as connection rate. + */ + else if (FIELD_IS("total_connections")) { + submit_derive("connections", "opened", atof(fields[2]), st); + } /* * Commands @@ -562,6 +664,8 @@ static int config_add_instance(oconfig_item_t *ci) { st->connhost = NULL; st->connport = NULL; + st->fd = -1; + if (strcasecmp(ci->key, "Instance") == 0) status = cf_util_get_string(ci, &st->name); @@ -639,6 +743,8 @@ static int memcached_init(void) { st->connhost = NULL; st->connport = NULL; + st->fd = -1; + status = memcached_add_read_callback(st); if (status == 0) memcached_have_instances = 1; diff --git a/src/msr-index.h b/src/msr-index.h new file mode 100644 index 00000000..2adca577 --- /dev/null +++ b/src/msr-index.h @@ -0,0 +1,88 @@ +/* + * Partial header file imported from the linux kernel + * (arch/x86/include/asm/msr-index.h) + * as it is not provided by the kernel sources anymore + * + * Only the minimal blocks of macro have been included + * ---- + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * ---- + */ + +#ifndef _ASM_X86_MSR_INDEX_H +#define _ASM_X86_MSR_INDEX_H + +/* + * CPU model specific register (MSR) numbers. + * + * Do not add new entries to this file unless the definitions are shared + * between multiple compilation units. + */ + +/* Intel MSRs. Some also available on other CPUs */ + +/* C-state Residency Counters */ +#define MSR_PKG_C3_RESIDENCY 0x000003f8 +#define MSR_PKG_C6_RESIDENCY 0x000003f9 +#define MSR_ATOM_PKG_C6_RESIDENCY 0x000003fa +#define MSR_PKG_C7_RESIDENCY 0x000003fa +#define MSR_CORE_C3_RESIDENCY 0x000003fc +#define MSR_CORE_C6_RESIDENCY 0x000003fd +#define MSR_CORE_C7_RESIDENCY 0x000003fe +#define MSR_KNL_CORE_C6_RESIDENCY 0x000003ff +#define MSR_PKG_C2_RESIDENCY 0x0000060d +#define MSR_PKG_C8_RESIDENCY 0x00000630 +#define MSR_PKG_C9_RESIDENCY 0x00000631 +#define MSR_PKG_C10_RESIDENCY 0x00000632 + +/* Run Time Average Power Limiting (RAPL) Interface */ + +#define MSR_RAPL_POWER_UNIT 0x00000606 + +#define MSR_PKG_POWER_LIMIT 0x00000610 +#define MSR_PKG_ENERGY_STATUS 0x00000611 +#define MSR_PKG_PERF_STATUS 0x00000613 +#define MSR_PKG_POWER_INFO 0x00000614 + +#define MSR_DRAM_POWER_LIMIT 0x00000618 +#define MSR_DRAM_ENERGY_STATUS 0x00000619 +#define MSR_DRAM_PERF_STATUS 0x0000061b +#define MSR_DRAM_POWER_INFO 0x0000061c + +#define MSR_PP0_POWER_LIMIT 0x00000638 +#define MSR_PP0_ENERGY_STATUS 0x00000639 +#define MSR_PP0_POLICY 0x0000063a +#define MSR_PP0_PERF_STATUS 0x0000063b + +#define MSR_PP1_POWER_LIMIT 0x00000640 +#define MSR_PP1_ENERGY_STATUS 0x00000641 +#define MSR_PP1_POLICY 0x00000642 + + + +/* Intel defined MSRs. */ +#define MSR_IA32_TSC 0x00000010 +#define MSR_SMI_COUNT 0x00000034 + +#define MSR_IA32_MPERF 0x000000e7 +#define MSR_IA32_APERF 0x000000e8 + +#define MSR_IA32_THERM_STATUS 0x0000019c + +#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 + +#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 + + +#endif /* _ASM_X86_MSR_INDEX_H */ diff --git a/src/turbostat.c b/src/turbostat.c index 1049fb2a..e4419b85 100644 --- a/src/turbostat.c +++ b/src/turbostat.c @@ -41,7 +41,7 @@ #include "plugin.h" #include "utils_time.h" -#include +#include "msr-index.h" #include #ifdef HAVE_SYS_CAPABILITY_H #include @@ -585,7 +585,10 @@ static int submit_counters(struct thread_data *t, struct core_data *c, /* If not using logical core numbering, set core id */ if (!config_lcn) { - snprintf(name, sizeof(name), "core%02d", c->core_id); + if (topology.num_packages > 1) + snprintf(name, sizeof(name), "pkg%02d-core%02d", p->package_id, c->core_id); + else + snprintf(name, sizeof(name), "core%02d", c->core_id); } if (do_core_cstate & (1 << 3)) diff --git a/src/types.db b/src/types.db index 87a82ee0..577d28f1 100644 --- a/src/types.db +++ b/src/types.db @@ -191,6 +191,7 @@ ping value:GAUGE:0:65535 ping_droprate value:GAUGE:0:100 ping_stddev value:GAUGE:0:65535 players value:GAUGE:0:1000000 +pools value:GAUGE:0:U power value:GAUGE:U:U pressure value:GAUGE:0:U protocol_counter value:DERIVE:0:U diff --git a/src/uptime.c b/src/uptime.c index 8b83cf9b..d51aa391 100644 --- a/src/uptime.c +++ b/src/uptime.c @@ -25,8 +25,7 @@ #include "plugin.h" #if KERNEL_LINUX -#define UPTIME_FILE "/proc/uptime" -/* Using /proc filesystem to retrieve the boot time, Linux only. */ +#include /* #endif KERNEL_LINUX */ #elif HAVE_LIBKSTAT @@ -53,8 +52,6 @@ /* * Global variables */ -/* boottime always used, no OS distinction */ -static time_t boottime; #if HAVE_LIBKSTAT extern kstat_ctl_t *kc; @@ -72,8 +69,6 @@ static void uptime_submit(gauge_t value) { plugin_dispatch_values(&vl); } -static int uptime_init(void) /* {{{ */ -{ /* * On most unix systems the uptime is calculated by looking at the boot * time (stored in unix time, since epoch) and the current one. We are @@ -84,32 +79,21 @@ static int uptime_init(void) /* {{{ */ * the boot time, the plugin is unregistered and there is no chance to * try again later. Nevertheless, this is very unlikely to happen. */ - +static time_t uptime_get_sys(void) { /* {{{ */ + time_t result; #if KERNEL_LINUX - FILE *fh = fopen(UPTIME_FILE, "r"); - if (fh == NULL) { + struct sysinfo info; + int status; + + status = sysinfo(&info); + if (status != 0) { char errbuf[1024]; - ERROR("uptime plugin: Cannot open " UPTIME_FILE ": %s", + ERROR("uptime plugin: Error calling sysinfo: %s", sstrerror(errno, errbuf, sizeof(errbuf))); return -1; } - double uptime_seconds = 0.0; - if (fscanf(fh, "%lf", &uptime_seconds) != 1) { - ERROR("uptime plugin: No value read from " UPTIME_FILE ""); - fclose(fh); - return -1; - } - - fclose(fh); - - if (uptime_seconds == 0.0) { - ERROR("uptime plugin: uptime read from " UPTIME_FILE ", " - "but it is zero!"); - return -1; - } - - boottime = time(NULL) - (long)uptime_seconds; + result = (time_t)info.uptime; /* #endif KERNEL_LINUX */ #elif HAVE_LIBKSTAT @@ -143,13 +127,13 @@ static int uptime_init(void) /* {{{ */ return -1; } - boottime = (time_t)knp->value.ui32; - - if (boottime == 0) { + if (knp->value.ui32 == 0) { ERROR("uptime plugin: kstat_data_lookup returned success, " "but `boottime' is zero!"); return -1; } + + result = time(NULL) - (time_t)knp->value.ui32; /* #endif HAVE_LIBKSTAT */ #elif HAVE_SYS_SYSCTL_H @@ -170,13 +154,13 @@ static int uptime_init(void) /* {{{ */ return -1; } - boottime = boottv.tv_sec; - - if (boottime == 0) { + if (boottv.tv_sec == 0) { ERROR("uptime plugin: sysctl(3) returned success, " "but `boottime' is zero!"); return -1; } + + result = time(NULL) - boottv.tv_sec; /* #endif HAVE_SYS_SYSCTL_H */ #elif HAVE_PERFSTAT @@ -196,18 +180,18 @@ static int uptime_init(void) /* {{{ */ if (hertz <= 0) hertz = HZ; - boottime = time(NULL) - cputotal.lbolt / hertz; + result = cputotal.lbolt / hertz; #endif /* HAVE_PERFSTAT */ - return 0; -} /* }}} int uptime_init */ + return result; +} /* }}} int uptime_get_sys */ static int uptime_read(void) { gauge_t uptime; time_t elapsed; /* calculate the amount of time elapsed since boot, AKA uptime */ - elapsed = time(NULL) - boottime; + elapsed = uptime_get_sys(); uptime = (gauge_t)elapsed; @@ -217,6 +201,5 @@ static int uptime_read(void) { } void module_register(void) { - plugin_register_init("uptime", uptime_init); plugin_register_read("uptime", uptime_read); } /* void module_register */ diff --git a/src/utils_latency_config.c b/src/utils_latency_config.c index 0f8c2a26..5eb5b6d9 100644 --- a/src/utils_latency_config.c +++ b/src/utils_latency_config.c @@ -105,6 +105,8 @@ int latency_config(latency_config_t *conf, oconfig_item_t *ci, status = latency_config_add_percentile(conf, child, plugin); else if (strcasecmp("Bucket", child->key) == 0) status = latency_config_add_bucket(conf, child, plugin); + else if (strcasecmp("BucketType", child->key) == 0) + status = cf_util_get_string(child, &conf->bucket_type); else WARNING("%s plugin: \"%s\" is not a valid option within a \"%s\" block.", plugin, child->key, ci->key); @@ -137,6 +139,14 @@ int latency_config_copy(latency_config_t *dst, const latency_config_t src) { return ENOMEM; } + if (src.bucket_type != NULL) { + dst->bucket_type = strdup(src.bucket_type); + if (dst->bucket_type == NULL) { + latency_config_free(*dst); + return ENOMEM; + } + } + memmove(dst->percentile, src.percentile, dst->percentile_num * sizeof(*dst->percentile)); memmove(dst->buckets, src.buckets, dst->buckets_num * sizeof(*dst->buckets)); @@ -147,4 +157,5 @@ int latency_config_copy(latency_config_t *dst, const latency_config_t src) { void latency_config_free(latency_config_t conf) { sfree(conf.percentile); sfree(conf.buckets); + sfree(conf.bucket_type); } /* void latency_config_free */ diff --git a/src/utils_latency_config.h b/src/utils_latency_config.h index 9a7a11af..7008fd00 100644 --- a/src/utils_latency_config.h +++ b/src/utils_latency_config.h @@ -44,6 +44,7 @@ typedef struct { latency_bucket_t *buckets; size_t buckets_num; + char *bucket_type; /* _Bool lower; diff --git a/src/utils_match.c b/src/utils_match.c index df70fbec..d3edb57c 100644 --- a/src/utils_match.c +++ b/src/utils_match.c @@ -294,7 +294,7 @@ void match_value_reset(cu_match_value_t *mv) { /* Reset GAUGE metrics only and except GAUGE_PERSIST. */ if ((mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) && !(mv->ds_type & UTILS_MATCH_CF_GAUGE_PERSIST)) { - mv->value.gauge = NAN; + mv->value.gauge = (mv->ds_type & UTILS_MATCH_CF_GAUGE_INC) ? 0 : NAN; mv->values_num = 0; } } /* }}} void match_value_reset */ diff --git a/src/utils_tail_match.c b/src/utils_tail_match.c index 242cc384..65655dcd 100644 --- a/src/utils_tail_match.c +++ b/src/utils_tail_match.c @@ -137,7 +137,11 @@ static int latency_submit_match(cu_match_t *match, void *user_data) { } /* Submit buckets */ - sstrncpy(vl.type, "bucket", sizeof(vl.type)); + if (data->latency_config.bucket_type != NULL) + sstrncpy(vl.type, data->latency_config.bucket_type, sizeof(vl.type)); + else + sstrncpy(vl.type, "bucket", sizeof(vl.type)); + for (size_t i = 0; i < data->latency_config.buckets_num; i++) { latency_bucket_t bucket = data->latency_config.buckets[i]; diff --git a/src/varnish.c b/src/varnish.c index 7c5a9ef0..910d1e77 100644 --- a/src/varnish.c +++ b/src/varnish.c @@ -21,6 +21,7 @@ * Jérôme Renard * Marc Fournier * Florian octo Forster + * Denes Matetelki **/ #include "collectd.h" @@ -69,6 +70,8 @@ struct user_config_s { _Bool collect_sms; #if HAVE_VARNISH_V2 _Bool collect_sm; +#endif +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 _Bool collect_sma; #endif _Bool collect_struct; @@ -80,6 +83,11 @@ struct user_config_s { _Bool collect_workers; #if HAVE_VARNISH_V4 _Bool collect_vsm; + _Bool collect_lck; + _Bool collect_mempool; + _Bool collect_mgt; + _Bool collect_smf; + _Bool collect_vbe; #endif }; typedef struct user_config_s user_config_t; /* }}} */ @@ -182,6 +190,14 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "client_req") == 0) return varnish_submit_derive(conf->instance, "connections", "connections", "received", val); +#ifdef HAVE_VARNISH_V4 + else if (strcmp(name, "client_req_400") == 0) + return varnish_submit_derive(conf->instance, "connections", "connections", + "error_400", val); + else if (strcmp(name, "client_req_417") == 0) + return varnish_submit_derive(conf->instance, "connections", "connections", + "error_417", val); +#endif } #ifdef HAVE_VARNISH_V3 @@ -286,6 +302,20 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "fetch_304") == 0) return varnish_submit_derive(conf->instance, "fetch", "http_requests", "no_body_304", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "fetch_no_thread") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "no_thread", val); + else if (strcmp(name, "fetch_none") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "none", val); + else if (strcmp(name, "busy_sleep") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "busy_sleep", val); + else if (strcmp(name, "busy_wakeup") == 0) + return varnish_submit_derive(conf->instance, "fetch", "http_requests", + "busy_wakeup", val); +#endif } if (conf->collect_hcb) { @@ -331,6 +361,14 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "n_objoverflow") == 0) return varnish_submit_derive(conf->instance, "objects", "total_objects", "workspace_overflow", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "exp_mailed") == 0) + return varnish_submit_derive(conf->instance, "struct", "objects", + "exp_mailed", val); + else if (strcmp(name, "exp_received") == 0) + return varnish_submit_derive(conf->instance, "struct", "objects", + "exp_received", val); +#endif } #if HAVE_VARNISH_V3 @@ -381,6 +419,34 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "bans_dups") == 0) return varnish_submit_derive(conf->instance, "ban", "total_operations", "duplicate", val); + else if (strcmp(name, "bans_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "tested", val); + else if (strcmp(name, "bans_lurker_contention") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_contention", val); + else if (strcmp(name, "bans_lurker_obj_killed") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_obj_killed", val); + else if (strcmp(name, "bans_lurker_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_tested", val); + else if (strcmp(name, "bans_lurker_tests_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "lurker_tests_tested", val); + else if (strcmp(name, "bans_obj_killed") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "obj_killed", val); + else if (strcmp(name, "bans_persisted_bytes") == 0) + return varnish_submit_gauge(conf->instance, "ban", "total_bytes", + "persisted_bytes", val); + else if (strcmp(name, "bans_persisted_fragmentation") == 0) + return varnish_submit_gauge(conf->instance, "ban", "total_bytes", + "persisted_fragmentation", val); + else if (strcmp(name, "bans_tests_tested") == 0) + return varnish_submit_derive(conf->instance, "ban", "total_operations", + "tests_tested", val); + } #endif @@ -415,6 +481,14 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "sess_herd") == 0) return varnish_submit_derive(conf->instance, "session", "total_operations", "herd", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "sess_closed_err") == 0) + return varnish_submit_derive(conf->instance, "session", + "total_operations", "closed_err", val); + else if (strcmp(name, "sess_dropped") == 0) + return varnish_submit_derive(conf->instance, "session", + "total_operations", "dropped_for_thread", val); +#endif } if (conf->collect_shm) { @@ -613,6 +687,15 @@ static int varnish_monitor(void *priv, else if (strcmp(name, "n_wrk_lqueue") == 0) return varnish_submit_derive(conf->instance, "workers", "total_requests", "queue_length", val); +#if HAVE_VARNISH_V4 + else if (strcmp(name, "pools") == 0) + return varnish_submit_gauge(conf->instance, "workers", "pools", + "pools", val); + else if (strcmp(name, "busy_killed") == 0) + return varnish_submit_derive(conf->instance, "workers", "http_requests", + "busy_killed", val); + +#endif } #if HAVE_VARNISH_V4 @@ -631,6 +714,159 @@ static int varnish_monitor(void *priv, return varnish_submit_derive(conf->instance, "vsm", "total_bytes", "overflowed", val); } + + if (conf->collect_vbe) { + /* @TODO figure out the collectd type for bitmap + if (strcmp(name, "happy") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "bitmap", "happy_hprobes", val); + */ + if (strcmp(name, "bereq_hdrbytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "bereq_hdrbytes", val); + else if (strcmp(name, "bereq_bodybytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "bereq_bodybytes", val); + else if (strcmp(name, "beresp_hdrbytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "beresp_hdrbytes", val); + else if (strcmp(name, "beresp_bodybytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "beresp_bodybytes", val); + else if (strcmp(name, "pipe_hdrbytes") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "pipe_hdrbytes", val); + else if (strcmp(name, "pipe_out") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "pipe_out", val); + else if (strcmp(name, "pipe_in") == 0) + return varnish_submit_derive(conf->instance, "vbe", + "total_bytes", "pipe_in", val); + else if (strcmp(name, "conn") == 0) + return varnish_submit_derive(conf->instance, "vbe", "connections", + "c_conns", val); + else if (strcmp(name, "req") == 0) + return varnish_submit_gauge(conf->instance, "vbe", "http_requests", + "b_reqs", val); + } + + /* All Stevedores support these counters */ + if (conf->collect_sma || conf->collect_smf) { + + char category[4]; + if (conf->collect_sma) + strncpy(category, "sma", 4); + else + strncpy(category, "smf", 4); + + if (strcmp(name, "c_req") == 0) + return varnish_submit_derive(conf->instance, category, + "total_operations", "alloc_req", val); + else if (strcmp(name, "c_fail") == 0) + return varnish_submit_derive(conf->instance, category, + "total_operations", "alloc_fail", val); + else if (strcmp(name, "c_bytes") == 0) + return varnish_submit_derive(conf->instance, category, + "total_bytes", "bytes_allocated", val); + else if (strcmp(name, "c_freed") == 0) + return varnish_submit_derive(conf->instance, category, + "total_bytes", "bytes_freed", val); + else if (strcmp(name, "g_alloc") == 0) + return varnish_submit_gauge(conf->instance, category, + "total_operations", "alloc_outstanding", val); + else if (strcmp(name, "g_bytes") == 0) + return varnish_submit_gauge(conf->instance, category, "bytes", + "bytes_outstanding", val); + else if (strcmp(name, "g_space") == 0) + return varnish_submit_gauge(conf->instance, category, "bytes", + "bytes_available", val); + } + + /* No SMA specific counters */ + + if (conf->collect_smf) { + if (strcmp(name, "g_smf") == 0) + return varnish_submit_gauge(conf->instance, "smf", "objects", + "n_struct_smf", val); + else if (strcmp(name, "g_smf_frag") == 0) + return varnish_submit_gauge(conf->instance, "smf", "objects", + "n_small_free_smf", val); + else if (strcmp(name, "g_smf_large") == 0) + return varnish_submit_gauge(conf->instance, "smf", "objects", + "n_large_free_smf", val); + } + + if (conf->collect_mgt) { + if (strcmp(name, "uptime") == 0) + return varnish_submit_gauge(conf->instance, "mgt", "uptime", + "mgt_proc_uptime", val); + else if (strcmp(name, "child_start") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_start", val); + else if (strcmp(name, "child_exit") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_exit", val); + else if (strcmp(name, "child_stop") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_stop", val); + else if (strcmp(name, "child_died") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_died", val); + else if (strcmp(name, "child_dump") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_dump", val); + else if (strcmp(name, "child_panic") == 0) + return varnish_submit_derive(conf->instance, "mgt", + "total_operations", "child_panic", val); + } + + if (conf->collect_lck) { + if (strcmp(name, "creat") == 0) + return varnish_submit_derive(conf->instance, "lck", "objects", + "created", val); + else if (strcmp(name, "destroy") == 0) + return varnish_submit_derive(conf->instance, "lck", "objects", + "destroyed", val); + else if (strcmp(name, "locks") == 0) + return varnish_submit_derive(conf->instance, "lck", "total_operations", + "lock_ops", val); + } + + if (conf->collect_mempool) { + if (strcmp(name, "live") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "objects", + "in_use", val); + else if (strcmp(name, "pool") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "objects", + "in_pool", val); + else if (strcmp(name, "sz_wanted") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "bytes", + "size_requested", val); + else if (strcmp(name, "sz_actual") == 0) + return varnish_submit_gauge(conf->instance, "mempool", "bytes", + "size_allocated", val); + else if (strcmp(name, "allocs") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "total_operations", "allocations", val); + else if (strcmp(name, "frees") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "total_operations", "frees", val); + else if (strcmp(name, "recycle") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "recycled", val); + else if (strcmp(name, "timeout") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "timed_out", val); + else if (strcmp(name, "toosmall") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "too_small", val); + else if (strcmp(name, "surplus") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "surplus", val); + else if (strcmp(name, "randry") == 0) + return varnish_submit_derive(conf->instance, "mempool", + "objects", "ran_dry", val); + } #endif return 0; @@ -1100,6 +1336,8 @@ static int varnish_config_apply_default(user_config_t *conf) /* {{{ */ conf->collect_shm = 1; #if HAVE_VARNISH_V2 conf->collect_sm = 0; +#endif +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 conf->collect_sma = 0; #endif conf->collect_sms = 0; @@ -1112,6 +1350,11 @@ static int varnish_config_apply_default(user_config_t *conf) /* {{{ */ conf->collect_workers = 0; #if HAVE_VARNISH_V4 conf->collect_vsm = 0; + conf->collect_lck = 0; + conf->collect_mempool = 0; + conf->collect_mgt = 0; + conf->collect_smf = 0; + conf->collect_vbe = 0; #endif return 0; @@ -1223,11 +1466,11 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ else if (strcasecmp("CollectSMS", child->key) == 0) cf_util_get_boolean(child, &conf->collect_sms); else if (strcasecmp("CollectSMA", child->key) == 0) -#if HAVE_VARNISH_V2 +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 cf_util_get_boolean(child, &conf->collect_sma); #else WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", - child->key, "v2"); + child->key, "v2 and v4"); #endif else if (strcasecmp("CollectSM", child->key) == 0) #if HAVE_VARNISH_V2 @@ -1258,6 +1501,48 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", child->key, "v4"); #endif + else if (strcasecmp("CollectLock", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_lck); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectMempool", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_mempool); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectManagement", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_mgt); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectSMF", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_smf); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectSMF", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_smf); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif + else if (strcasecmp("CollectVBE", child->key) == 0) +#if HAVE_VARNISH_V4 + cf_util_get_boolean(child, &conf->collect_vbe); +#else + WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.", + child->key, "v4"); +#endif else { WARNING("Varnish plugin: Ignoring unknown " "configuration option: \"%s\". Did " @@ -1280,7 +1565,10 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ #endif && !conf->collect_session && !conf->collect_shm && !conf->collect_sms #if HAVE_VARNISH_V2 - && !conf->collect_sma && !conf->collect_sm + && !conf->collect_sm +#endif +#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 + && !conf->collect_sma #endif && !conf->collect_struct && !conf->collect_totals #if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 @@ -1288,7 +1576,8 @@ static int varnish_config_instance(const oconfig_item_t *ci) /* {{{ */ #endif && !conf->collect_vcl && !conf->collect_workers #if HAVE_VARNISH_V4 - && !conf->collect_vsm + && !conf->collect_vsm && !conf->collect_vbe && !conf->collect_smf + && !conf->collect_mgt && !conf->collect_lck && !conf->collect_mempool #endif ) { WARNING("Varnish plugin: No metric has been configured for " diff --git a/src/write_redis.c b/src/write_redis.c index 5a029de2..7dd5029c 100644 --- a/src/write_redis.c +++ b/src/write_redis.c @@ -45,6 +45,7 @@ struct wr_node_s { char *prefix; int database; int max_set_size; + int max_set_duration; _Bool store_rates; redisContext *conn; @@ -125,6 +126,20 @@ static int wr_write(const data_set_t *ds, /* {{{ */ freeReplyObject(rr); } + if (node->max_set_duration > 0) { + /* + * remove element, scored less than 'current-max_set_duration' + * '(%d' indicates 'less than' in redis CLI. + */ + rr = redisCommand(node->conn, "ZREMRANGEBYSCORE %s -1 (%d", key, + (time - node->max_set_duration) + 1); + if (rr == NULL) + WARNING("ZREMRANGEBYSCORE command error. key:%s message:%s", key, + node->conn->errstr); + else + freeReplyObject(rr); + } + /* TODO(octo): This is more overhead than necessary. Use the cache and * metadata to determine if it is a new metric and call SADD only once for * each metric. */ @@ -175,6 +190,7 @@ static int wr_config_node(oconfig_item_t *ci) /* {{{ */ node->prefix = NULL; node->database = 0; node->max_set_size = -1; + node->max_set_duration = -1; node->store_rates = 1; pthread_mutex_init(&node->lock, /* attr = */ NULL); @@ -205,6 +221,8 @@ static int wr_config_node(oconfig_item_t *ci) /* {{{ */ status = cf_util_get_int(child, &node->database); } else if (strcasecmp("MaxSetSize", child->key) == 0) { status = cf_util_get_int(child, &node->max_set_size); + } else if (strcasecmp("MaxSetDuration", child->key) == 0) { + status = cf_util_get_int(child, &node->max_set_duration); } else if (strcasecmp("StoreRates", child->key) == 0) { status = cf_util_get_boolean(child, &node->store_rates); } else diff --git a/src/zfs_arc.c b/src/zfs_arc.c index 730d3048..e589184c 100644 --- a/src/zfs_arc.c +++ b/src/zfs_arc.c @@ -35,6 +35,10 @@ /* * Global variables */ +static value_to_rate_state_t arc_hits_state; +static value_to_rate_state_t arc_misses_state; +static value_to_rate_state_t l2_hits_state; +static value_to_rate_state_t l2_misses_state; #if defined(KERNEL_LINUX) #include "utils_llist.h" @@ -313,14 +317,25 @@ static int za_read(void) { za_read_derive(ksp, "mru_hits", "cache_result", "mru-hit"); za_read_derive(ksp, "mru_ghost_hits", "cache_result", "mru_ghost-hit"); + cdtime_t now = cdtime(); + /* Ratios */ - 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"); + if ((value_to_rate(&arc_hits, (value_t){.derive = get_zfs_value(ksp, "hits")}, + DS_TYPE_DERIVE, now, &arc_hits_state) == 0) && + (value_to_rate(&arc_misses, + (value_t){.derive = get_zfs_value(ksp, "misses")}, + DS_TYPE_DERIVE, now, &arc_misses_state) == 0)) { + za_submit_ratio("arc", arc_hits, arc_misses); + } - za_submit_ratio("arc", arc_hits, arc_misses); - za_submit_ratio("L2", l2_hits, l2_misses); + if ((value_to_rate(&l2_hits, + (value_t){.derive = get_zfs_value(ksp, "l2_hits")}, + DS_TYPE_DERIVE, now, &l2_hits_state) == 0) && + (value_to_rate(&l2_misses, + (value_t){.derive = get_zfs_value(ksp, "l2_misses")}, + DS_TYPE_DERIVE, now, &l2_misses_state) == 0)) { + za_submit_ratio("L2", l2_hits, l2_misses); + } /* I/O */ value_t l2_io[] = {