src/tests/mock/.deps/
src/tests/.dirstamp
src/tests/mock/.dirstamp
+test*.log
# new daemon repo
src/daemon/.deps/
END
# graph various ranges
- foreach my $span qw(1hour 1day 1week 1month){
+ foreach my $span (qw(1hour 1day 1week 1month)){
system("mkdir -p $IMG_DIR/" . dirname($bn));
my $img = "$IMG_DIR/${bn}-$span$IMG_SFX";
check_PROGRAMS =
TESTS =
+noinst_LTLIBRARIES += liblatency.la
+liblatency_la_SOURCES = utils_latency.c utils_latency.h
+check_PROGRAMS += test_utils_latency
+TESTS += test_utils_latency
+test_utils_latency_SOURCES = utils_latency_test.c testing.h
+test_utils_latency_LDADD = liblatency.la daemon/libcommon.la daemon/libplugin_mock.la -lm
+
noinst_LTLIBRARIES += liblookup.la
liblookup_la_SOURCES = utils_vl_lookup.c utils_vl_lookup.h
liblookup_la_LIBADD = daemon/libavltree.la
if BUILD_PLUGIN_STATSD
pkglib_LTLIBRARIES += statsd.la
-statsd_la_SOURCES = statsd.c \
- utils_latency.h utils_latency.c
+statsd_la_SOURCES = statsd.c
statsd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-statsd_la_LIBADD = -lpthread -lm
+statsd_la_LIBADD = liblatency.la -lpthread -lm
endif
if BUILD_PLUGIN_SWAP
xmlFree (zone_name);
zone_name = NULL;
- if (j >= views->zones_num)
+ if (j >= view->zones_num)
return (0);
zone_name = view->zones[j];
#@BUILD_PLUGIN_BATTERY_TRUE@LoadPlugin battery
#@BUILD_PLUGIN_BIND_TRUE@LoadPlugin bind
#@BUILD_PLUGIN_CEPH_TRUE@LoadPlugin ceph
+#@BUILD_PLUGIN_CGROUPS_TRUE@LoadPlugin cgroups
#@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack
#@BUILD_PLUGIN_CONTEXTSWITCH_TRUE@LoadPlugin contextswitch
-#@BUILD_PLUGIN_CGROUPS_TRUE@LoadPlugin cgroups
@BUILD_PLUGIN_CPU_TRUE@@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
#@BUILD_PLUGIN_CPUFREQ_TRUE@LoadPlugin cpufreq
@LOAD_PLUGIN_CSV@LoadPlugin csv
#@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
@BUILD_PLUGIN_INTERFACE_TRUE@@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
#@BUILD_PLUGIN_IPC_TRUE@@BUILD_PLUGIN_IPC_TRUE@LoadPlugin ipc
-#@BUILD_PLUGIN_IPTABLES_TRUE@LoadPlugin iptables
#@BUILD_PLUGIN_IPMI_TRUE@LoadPlugin ipmi
+#@BUILD_PLUGIN_IPTABLES_TRUE@LoadPlugin iptables
#@BUILD_PLUGIN_IPVS_TRUE@LoadPlugin ipvs
#@BUILD_PLUGIN_IRQ_TRUE@LoadPlugin irq
#@BUILD_PLUGIN_JAVA_TRUE@LoadPlugin java
#@BUILD_PLUGIN_MEMCACHEC_TRUE@LoadPlugin memcachec
#@BUILD_PLUGIN_MEMCACHED_TRUE@LoadPlugin memcached
@BUILD_PLUGIN_MEMORY_TRUE@@BUILD_PLUGIN_MEMORY_TRUE@LoadPlugin memory
+#@BUILD_PLUGIN_MIC_TRUE@LoadPlugin mic
#@BUILD_PLUGIN_MODBUS_TRUE@LoadPlugin modbus
#@BUILD_PLUGIN_MQTT_TRUE@LoadPlugin mqtt
#@BUILD_PLUGIN_MULTIMETER_TRUE@LoadPlugin multimeter
#@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_VIRT_TRUE@LoadPlugin virt
#@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem
#@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
Port "6379"
Timeout 1000
Prefix "collectd/"
+ Database 1
</Node>
</Plugin>
C<ZRANGEBYSCORE> I<Redis> command. Additionnally, all the identifiers of these
I<Sorted Sets> are kept in a I<Set> called C<collectd/values> (or
C<${prefix}/values> if the B<Prefix> option was specified) and can be retrieved
-using the C<SMEMBERS> I<Redis> command. See
+using the C<SMEMBERS> I<Redis> command. You can specify the database to use
+with the B<Database> parameter (default is C<0>). See
L<http://redis.io/commands#sorted_set> and L<http://redis.io/commands#set> for
details.
like C<collectd/cpu-0/cpu-user>. When setting this to something different, it
is recommended but not required to include a trailing slash in I<Prefix>.
+=item B<Database> I<Index>
+
+This index selects the redis database to use for writing operations. Defaults to C<0>.
+
=back
=head2 Plugin C<write_riemann>
sbin_PROGRAMS = collectd
-noinst_LTLIBRARIES = libavltree.la libcommon.la libheap.la libplugin_mock.la
+noinst_LTLIBRARIES = libavltree.la libcommon.la libheap.la libmetadata.la libplugin_mock.la
libavltree_la_SOURCES = utils_avltree.c utils_avltree.h
libheap_la_SOURCES = utils_heap.c utils_heap.h
+libmetadata_la_SOURCES = meta_data.c meta_data.h
+
libplugin_mock_la_SOURCES = plugin_mock.c utils_cache_mock.c utils_time_mock.c
collectd_SOURCES = collectd.c collectd.h \
collectd_CFLAGS = $(AM_CFLAGS)
collectd_LDFLAGS = -export-dynamic
collectd_LDADD = libavltree.la libcommon.la libheap.la -lm $(COMMON_LIBS)
-collectd_DEPENDENCIES =
+collectd_DEPENDENCIES = libavltree.la libcommon.la libheap.la libmetadata.la
# The daemon needs to call sg_init, so we need to link it against libstatgrab,
# too. -octo
collectd_LDADD += -loconfig
endif
-check_PROGRAMS = test_common test_utils_avltree test_utils_heap test_utils_subst
-TESTS = test_common test_utils_avltree test_utils_heap test_utils_subst
+check_PROGRAMS = test_common test_meta_data test_utils_avltree test_utils_heap test_utils_subst
+TESTS = test_common test_meta_data test_utils_avltree test_utils_heap test_utils_subst
test_common_SOURCES = common_test.c ../testing.h
test_common_LDADD = libcommon.la libplugin_mock.la $(COMMON_LIBS)
+test_meta_data_SOURCES = meta_data_test.c ../testing.h
+test_meta_data_LDADD = libmetadata.la libplugin_mock.la $(COMMON_LIBS)
+
test_utils_avltree_SOURCES = utils_avltree_test.c ../testing.h
test_utils_avltree_LDADD = libavltree.la $(COMMON_LIBS)
#ifdef KERNEL_LINUX
int notify_upstart (void)
{
- const char *upstart_job = getenv("UPSTART_JOB");
+ char const *upstart_job = getenv("UPSTART_JOB");
if (upstart_job == NULL)
return 0;
if (strcmp(upstart_job, "collectd") != 0)
+ {
+ WARNING ("Environment specifies unexpected UPSTART_JOB=\"%s\", expected \"collectd\". Ignoring the variable.", upstart_job);
return 0;
+ }
- WARNING ("supervised by upstart, will stop to signal readyness");
+ NOTICE("Upstart detected, stopping now to signal readyness.");
raise(SIGSTOP);
unsetenv("UPSTART_JOB");
int notify_systemd (void)
{
- int fd = -1;
- const char *notifysocket = getenv("NOTIFY_SOCKET");
+ int fd;
+ const char *notifysocket;
struct sockaddr_un su;
- struct iovec iov;
- struct msghdr hdr;
+ size_t su_size;
+ char buffer[] = "READY=1\n";
+ notifysocket = getenv ("NOTIFY_SOCKET");
if (notifysocket == NULL)
return 0;
- if ((strchr("@/", notifysocket[0])) == NULL ||
- strlen(notifysocket) < 2)
+ if ((strlen (notifysocket) < 2)
+ || ((notifysocket[0] != '@') && (notifysocket[0] != '/')))
+ {
+ ERROR ("invalid notification socket NOTIFY_SOCKET=\"%s\": path must be absolute", notifysocket);
return 0;
+ }
+ NOTICE ("Systemd detected, trying to signal readyness.");
+
+ unsetenv ("NOTIFY_SOCKET");
- WARNING ("supervised by systemd, will signal readyness");
- if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
- WARNING ("cannot contact systemd socket %s", notifysocket);
+ fd = socket (AF_UNIX, SOCK_DGRAM, /* protocol = */ 0);
+ if (fd < 0) {
+ char errbuf[1024];
+ ERROR ("creating UNIX socket failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
return 0;
}
- bzero(&su, sizeof(su));
+ memset (&su, 0, sizeof (su));
su.sun_family = AF_UNIX;
- sstrncpy (su.sun_path, notifysocket, sizeof(su.sun_path));
-
- if (notifysocket[0] == '@')
+ if (notifysocket[0] != '@')
+ {
+ /* regular UNIX socket */
+ sstrncpy (su.sun_path, notifysocket, sizeof (su.sun_path));
+ su_size = sizeof (su);
+ }
+ else
+ {
+#if KERNEL_LINUX
+ /* Linux abstract namespace socket: specify address as "\0foo", i.e.
+ * start with a null byte. Since null bytes have no special meaning in
+ * that case, we have to set su_size correctly to cover only the bytes
+ * that are part of the address. */
+ sstrncpy (su.sun_path, notifysocket, sizeof (su.sun_path));
su.sun_path[0] = 0;
+ su_size = sizeof (sa_family_t) + strlen (notifysocket);
+ if (su_size > sizeof (su))
+ su_size = sizeof (su);
+#else
+ ERROR ("Systemd socket uses Linux abstract namespace notation (\"%s\"), "
+ "but I don't appear to be running on Linux.", notifysocket);
+ return 0;
+#endif
+ }
- bzero(&iov, sizeof(iov));
- iov.iov_base = "READY=1";
- iov.iov_len = strlen("READY=1");
-
- bzero(&hdr, sizeof(hdr));
- hdr.msg_name = &su;
- hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
- strlen(notifysocket);
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
-
- unsetenv("NOTIFY_SOCKET");
- if (sendmsg(fd, &hdr, MSG_NOSIGNAL) < 0) {
- WARNING ("cannot send notification to systemd");
+ if (sendto (fd, buffer, strlen (buffer), MSG_NOSIGNAL, (void *) &su, (socklen_t) su_size) < 0)
+ {
+ char errbuf[1024];
+ ERROR ("sendto(\"%s\") failed: %s", notifysocket,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
close(fd);
return 0;
}
+
close(fd);
return 1;
}
assert ((0 > status) || (nleft >= (size_t)status));
- nleft = nleft - status;
- ptr = ptr + status;
+ nleft = nleft - ((size_t) status);
+ ptr = ptr + ((size_t) status);
}
return (0);
if (status < 0)
return (status);
- nleft = nleft - status;
- ptr = ptr + status;
+ nleft = nleft - ((size_t) status);
+ ptr = ptr + ((size_t) status);
}
return (0);
}
assert (buffer[buffer_size - 1] == 0);
- return (strlen (buffer));
+ return ((int) strlen (buffer));
}
int strsubstitute (char *str, char c_from, char c_to)
* Join the components together again
*/
dir[0] = '/';
- if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute,
- fields, i + 1, "/") < 0)
+ if (strjoin (dir + path_is_absolute, (size_t) (dir_len - path_is_absolute),
+ fields, (size_t) (i + 1), "/") < 0)
{
ERROR ("strjoin failed: `%s', component #%i", file_orig, i);
return (-1);
};
int status = parse_values (cases[i].buffer, &vl, &ds);
- OK(status == cases[i].status);
+ EXPECT_INTEQ (cases[i].status, status);
if (status != 0)
continue;
- OK(cases[i].value == vl.values[0].gauge);
+ DBLEQ (cases[i].value, vl.values[0].gauge);
}
return (0);
--- /dev/null
+/**
+ * collectd - src/daemon/meta_data_test.c
+ * Copyright (C) 2015 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ */
+
+#include "testing.h"
+#include "collectd.h"
+#include "common.h" /* for STATIC_ARRAY_SIZE */
+#include "meta_data.h"
+
+DEF_TEST(base)
+{
+ meta_data_t *m;
+
+ char *s;
+ int64_t si;
+ uint64_t ui;
+ double d;
+ _Bool b;
+
+ CHECK_NOT_NULL (m = meta_data_create ());
+
+ /* all of these are absent */
+ OK(meta_data_get_string (m, "string", &s) != 0);
+ OK(meta_data_get_signed_int (m, "signed_int", &si) != 0);
+ OK(meta_data_get_unsigned_int (m, "unsigned_int", &ui) != 0);
+ OK(meta_data_get_double (m, "double", &d) != 0);
+ OK(meta_data_get_boolean (m, "boolean", &b) != 0);
+
+ /* populate structure */
+ CHECK_ZERO (meta_data_add_string (m, "string", "foobar"));
+ OK(meta_data_exists (m, "string"));
+ OK(meta_data_type (m, "string") == MD_TYPE_STRING);
+
+ CHECK_ZERO (meta_data_add_signed_int (m, "signed_int", -1));
+ OK(meta_data_exists (m, "signed_int"));
+ OK(meta_data_type (m, "signed_int") == MD_TYPE_SIGNED_INT);
+
+ CHECK_ZERO (meta_data_add_unsigned_int (m, "unsigned_int", 1));
+ OK(meta_data_exists (m, "unsigned_int"));
+ OK(meta_data_type (m, "unsigned_int") == MD_TYPE_UNSIGNED_INT);
+
+ CHECK_ZERO (meta_data_add_double (m, "double", 47.11));
+ OK(meta_data_exists (m, "double"));
+ OK(meta_data_type (m, "double") == MD_TYPE_DOUBLE);
+
+ CHECK_ZERO (meta_data_add_boolean (m, "boolean", 1));
+ OK(meta_data_exists (m, "boolean"));
+ OK(meta_data_type (m, "boolean") == MD_TYPE_BOOLEAN);
+
+ /* retrieve and check all values */
+ CHECK_ZERO (meta_data_get_string (m, "string", &s));
+ STREQ ("foobar", s);
+ sfree (s);
+
+ CHECK_ZERO (meta_data_get_signed_int (m, "signed_int", &si));
+ EXPECT_INTEQ (-1, (int) si);
+
+ CHECK_ZERO (meta_data_get_unsigned_int (m, "unsigned_int", &ui));
+ EXPECT_INTEQ (1, (int) ui);
+
+ CHECK_ZERO (meta_data_get_double (m, "double", &d));
+ DBLEQ (47.11, d);
+
+ CHECK_ZERO (meta_data_get_boolean (m, "boolean", &b));
+ OK1 (b, "b evaluates to true");
+
+ /* retrieving the wrong type always fails */
+ EXPECT_INTEQ (-2, meta_data_get_boolean (m, "string", &b));
+ EXPECT_INTEQ (-2, meta_data_get_string (m, "signed_int", &s));
+ EXPECT_INTEQ (-2, meta_data_get_string (m, "unsigned_int", &s));
+ EXPECT_INTEQ (-2, meta_data_get_string (m, "double", &s));
+ EXPECT_INTEQ (-2, meta_data_get_string (m, "boolean", &s));
+
+ /* replace existing keys */
+ CHECK_ZERO (meta_data_add_signed_int (m, "string", 666));
+ OK(meta_data_type (m, "string") == MD_TYPE_SIGNED_INT);
+
+ CHECK_ZERO (meta_data_add_signed_int (m, "signed_int", 666));
+ CHECK_ZERO (meta_data_get_signed_int (m, "signed_int", &si));
+ EXPECT_INTEQ (666, (int) si);
+
+ /* deleting keys */
+ CHECK_ZERO (meta_data_delete (m, "signed_int"));
+ EXPECT_INTEQ (-2, meta_data_delete (m, "doesnt exist"));
+
+ meta_data_destroy (m);
+ return 0;
+}
+
+int main (void)
+{
+ RUN_TEST(base);
+
+ END_TEST;
+}
+
+/* vim: set sw=2 sts=2 et : */
#include "utils_cache.h"
-gauge_t *uc_get_rate (const data_set_t *ds, const value_list_t *vl)
+gauge_t *uc_get_rate (__attribute((unused)) data_set_t const *ds,
+ __attribute((unused)) value_list_t const *vl)
{
return (NULL);
}
cdtime_t cdtime (void)
{
- return (0);
+ return (1542455354518929408);
}
* beginning of the message. */
ptr = NULL;
errno = 0;
- res.status = strtol (buffer, &ptr, 0);
+ res.status = (int) strtol (buffer, &ptr, 0);
if ((errno != 0) || (ptr == &buffer[0]))
{
lcc_set_errno (c, errno);
int lcc_server_set_interface (lcc_server_t *srv, char const *interface) /* {{{ */
{
- int if_index;
+ unsigned int if_index;
int status;
if ((srv == NULL) || (interface == NULL))
memset (&mreq, 0, sizeof (mreq));
mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
mreq.imr_address.s_addr = ntohl (INADDR_ANY);
- mreq.imr_ifindex = if_index;
+ mreq.imr_ifindex = (int) if_index;
#else
struct ip_mreq mreq;
/* else: Not a multicast interface. */
#if defined(SO_BINDTODEVICE)
- status = setsockopt (srv->fd, SOL_SOCKET, SO_BINDTODEVICE,
- interface, strlen (interface) + 1);
+ status = setsockopt (srv->fd, SOL_SOCKET, SO_BINDTODEVICE, interface,
+ (socklen_t) (strlen (interface) + 1));
if (status != 0)
return (-1);
#endif
yyset_in (fh);
if (NULL == c_file) {
- int status;
-
status = snprintf (file, sizeof (file), "<fd#%d>", fileno (fh));
- if ((status < 0) || (status >= sizeof (file))) {
+ if ((status < 0) || (((size_t) status) >= sizeof (file))) {
c_file = "<unknown>";
}
else {
{
int i;
- ci_copy->values = (oconfig_value_t *) calloc (ci_orig->values_num,
- sizeof (*ci_copy->values));
+ ci_copy->values = (oconfig_value_t *) calloc ((size_t) ci_orig->values_num,
+ sizeof (*ci_copy->values));
if (ci_copy->values == NULL)
{
fprintf (stderr, "calloc failed.\n");
ci_copy->values[i].type = ci_orig->values[i].type;
if (ci_copy->values[i].type == OCONFIG_TYPE_STRING)
{
- ci_copy->values[i].value.string
- = strdup (ci_orig->values[i].value.string);
- if (ci_copy->values[i].value.string == NULL)
- {
- fprintf (stderr, "strdup failed.\n");
- oconfig_free (ci_copy);
- return (NULL);
- }
+ ci_copy->values[i].value.string = strdup (ci_orig->values[i].value.string);
+ if (ci_copy->values[i].value.string == NULL)
+ {
+ fprintf (stderr, "strdup failed.\n");
+ oconfig_free (ci_copy);
+ return (NULL);
+ }
}
else /* ci_copy->values[i].type != OCONFIG_TYPE_STRING) */
{
- ci_copy->values[i].value = ci_orig->values[i].value;
+ ci_copy->values[i].value = ci_orig->values[i].value;
}
}
} /* }}} if (ci_orig->values_num > 0) */
{
int i;
- ci_copy->children = (oconfig_item_t *) calloc (ci_orig->children_num,
- sizeof (*ci_copy->children));
+ ci_copy->children = (oconfig_item_t *) calloc ((size_t) ci_orig->children_num,
+ sizeof (*ci_copy->children));
if (ci_copy->children == NULL)
{
fprintf (stderr, "calloc failed.\n");
status = sockent_server_listen (se);
if (status != 0)
{
- ERROR ("network plugin: network_config_add_server: sockent_server_listen failed.");
+ ERROR ("network plugin: network_config_add_listen: sockent_server_listen failed.");
sockent_destroy (se);
return (-1);
}
/**
* collectd - src/tests/macros.h
- * Copyright (C) 2013 Florian octo Forster
+ * Copyright (C) 2013-2015 Florian octo Forster
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
static int fail_count__ = 0;
static int check_count__ = 0;
+#ifndef DBL_PRECISION
+# define DBL_PRECISION 1e-12
+#endif
+
#define DEF_TEST(func) static int test_##func ()
#define RUN_TEST(func) do { \
#define OK1(cond, text) do { \
_Bool result = (cond); \
printf ("%s %i - %s\n", result ? "ok" : "not ok", ++check_count__, text); \
+ if (!result) { return -1; } \
} while (0)
#define OK(cond) OK1(cond, #cond)
printf ("ok %i - %s evaluates to \"%s\"\n", ++check_count__, #actual, expect); \
} while (0)
+#define EXPECT_INTEQ(expect, actual) do { \
+ if ((expect) != (actual)) {\
+ printf ("not ok %i - %s incorrect: expected %d, got %d\n", \
+ ++check_count__, #actual, expect, actual); \
+ return (-1); \
+ } \
+ printf ("ok %i - %s evaluates to %d\n", ++check_count__, #actual, expect); \
+} while (0)
+
#define DBLEQ(expect, actual) do { \
- if ((isnan (expect) && !isnan (actual)) || ((expect) != (actual))) {\
+ double e = (expect); double a = (actual); \
+ if (isnan (e) && !isnan (a)) { \
printf ("not ok %i - %s incorrect: expected %.15g, got %.15g\n", \
- ++check_count__, #actual, expect, actual); \
+ ++check_count__, #actual, e, a); \
+ return (-1); \
+ } else if (!isnan (e) && (((e-a) < -DBL_PRECISION) || ((e-a) > DBL_PRECISION))) { \
+ printf ("not ok %i - %s incorrect: expected %.15g, got %.15g\n", \
+ ++check_count__, #actual, e, a); \
return (-1); \
} \
- printf ("ok %i - %s evaluates to %.15g\n", ++check_count__, #actual, expect); \
+ printf ("ok %i - %s evaluates to %.15g\n", ++check_count__, #actual, e); \
} while (0)
#define CHECK_NOT_NULL(expr) do { \
#include "common.h"
#include <math.h>
+#include <limits.h>
#ifndef HISTOGRAM_NUM_BINS
# define HISTOGRAM_NUM_BINS 1000
#endif
-static const int HISTOGRAM_DEFAULT_BIN_WIDTH = 1;
+#ifndef HISTOGRAM_DEFAULT_BIN_WIDTH
+/* 1048576 = 2^20 ^= 1/1024 s */
+# define HISTOGRAM_DEFAULT_BIN_WIDTH 1048576
+#endif
struct latency_counter_s
{
cdtime_t min;
cdtime_t max;
- int bin_width;
+ cdtime_t bin_width;
int histogram[HISTOGRAM_NUM_BINS];
};
*
* So, if the required bin width is 300, then new bin width will be 512 as it is
* the next nearest power of 2.
-*
*/
-void change_bin_width (latency_counter_t *lc, size_t val) /* {{{ */
+void change_bin_width (latency_counter_t *lc, cdtime_t latency) /* {{{ */
{
- int i=0;
/* This function is called because the new value is above histogram's range.
* First find the required bin width:
* requiredBinWidth = (value + 1) / numBins
* then get the next nearest power of 2
* newBinWidth = 2^(ceil(log2(requiredBinWidth)))
*/
- double required_bin_width = (double)(val + 1) / HISTOGRAM_NUM_BINS;
- double required_bin_width_logbase2 = log(required_bin_width) / log(2.0);
- int new_bin_width = (int)(pow(2.0, ceil( required_bin_width_logbase2)));
- int old_bin_width = lc->bin_width;
+ double required_bin_width = ((double) (latency + 1)) / ((double) HISTOGRAM_NUM_BINS);
+ double required_bin_width_logbase2 = log (required_bin_width) / log (2.0);
+ cdtime_t new_bin_width = (cdtime_t) (pow (2.0, ceil (required_bin_width_logbase2)) + .5);
+ cdtime_t old_bin_width = lc->bin_width;
+
lc->bin_width = new_bin_width;
- /*
- * bin width has been increased, now iterate through all bins and move the
- * old bin's count to new bin.
- */
+ /* bin_width has been increased, now iterate through all bins and move the
+ * old bin's count to new bin. */
if (lc->num > 0) // if the histogram has data then iterate else skip
{
- double width_change_ratio = old_bin_width / new_bin_width;
- for (i=0; i<HISTOGRAM_NUM_BINS; i++)
+ double width_change_ratio = ((double) old_bin_width) / ((double) new_bin_width);
+ size_t i;
+
+ for (i = 0; i < HISTOGRAM_NUM_BINS; i++)
{
- int new_bin = (int)(i * width_change_ratio);
+ size_t new_bin = (size_t) (((double) i) * width_change_ratio);
if (i == new_bin)
continue;
+ assert (new_bin < i);
+
lc->histogram[new_bin] += lc->histogram[i];
lc->histogram[i] = 0;
}
- DEBUG("utils_latency: change_bin_width: fixed all bins");
}
- DEBUG("utils_latency: change_bin_width: val-[%zu], oldBinWidth-[%d], "
- "newBinWidth-[%d], required_bin_width-[%f], "
- "required_bin_width_logbase2-[%f]",
- val, old_bin_width, new_bin_width, required_bin_width,
- required_bin_width_logbase2);
-
+ DEBUG("utils_latency: change_bin_width: latency = %.3f; "
+ "old_bin_width = %.3f; new_bin_width = %.3f;",
+ CDTIME_T_TO_DOUBLE (latency),
+ CDTIME_T_TO_DOUBLE (old_bin_width),
+ CDTIME_T_TO_DOUBLE (new_bin_width));
} /* }}} void change_bin_width */
latency_counter_t *latency_counter_create () /* {{{ */
void latency_counter_add (latency_counter_t *lc, cdtime_t latency) /* {{{ */
{
- size_t latency_ms;
+ cdtime_t bin;
- if ((lc == NULL) || (latency == 0))
+ if ((lc == NULL) || (latency == 0) || (latency > ((cdtime_t) LLONG_MAX)))
return;
lc->sum += latency;
/* A latency of _exactly_ 1.0 ms should be stored in the buffer 0, so
* subtract one from the cdtime_t value so that exactly 1.0 ms get sorted
* accordingly. */
- latency_ms = (size_t) CDTIME_T_TO_MS (latency - 1);
-
- int bin = (int)(latency_ms / lc->bin_width);
+ bin = (latency - 1) / lc->bin_width;
if (bin >= HISTOGRAM_NUM_BINS)
{
- change_bin_width(lc, latency_ms);
- bin = (int)(latency_ms / lc->bin_width);
+ change_bin_width (lc, latency);
+ bin = (latency - 1) / lc->bin_width;
if (bin >= HISTOGRAM_NUM_BINS)
{
- ERROR("utils_latency: latency_counter_add: Invalid bin %d", bin);
+ ERROR ("utils_latency: latency_counter_add: Invalid bin %lu", bin);
return;
}
}
if (lc == NULL)
return;
- int bin_width = lc->bin_width;
+ cdtime_t bin_width = lc->bin_width;
memset (lc, 0, sizeof (*lc));
/* preserve bin width */
return (DOUBLE_TO_CDTIME_T (average));
} /* }}} cdtime_t latency_counter_get_average */
-cdtime_t latency_counter_get_percentile (latency_counter_t *lc,
+cdtime_t latency_counter_get_percentile (latency_counter_t *lc, /* {{{ */
double percent)
{
double percent_upper;
double percent_lower;
- double ms_upper;
- double ms_lower;
- double ms_interpolated;
+ double p;
+ cdtime_t latency_lower;
+ cdtime_t latency_interpolated;
int sum;
size_t i;
assert (percent_upper >= percent);
assert (percent_lower < percent);
- ms_upper = (double) ( (i + 1) * lc->bin_width );
- ms_lower = (double) ( i * lc->bin_width );
if (i == 0)
- return (MS_TO_CDTIME_T (ms_upper));
+ return (lc->bin_width);
+
+ latency_lower = ((cdtime_t) i) * lc->bin_width;
+ p = (percent - percent_lower) / (percent_upper - percent_lower);
- ms_interpolated = (((percent_upper - percent) * ms_lower)
- + ((percent - percent_lower) * ms_upper))
- / (percent_upper - percent_lower);
+ latency_interpolated = latency_lower
+ + DOUBLE_TO_CDTIME_T (p * CDTIME_T_TO_DOUBLE (lc->bin_width));
- return (MS_TO_CDTIME_T (ms_interpolated));
+ DEBUG ("latency_counter_get_percentile: latency_interpolated = %.3f",
+ CDTIME_T_TO_DOUBLE (latency_interpolated));
+ return (latency_interpolated);
} /* }}} cdtime_t latency_counter_get_percentile */
/* vim: set sw=2 sts=2 et fdm=marker : */
--- /dev/null
+/**
+ * collectd - src/utils_latency_test.c
+ * Copyright (C) 2015 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ */
+
+#define DBL_PRECISION 1e-9
+
+#include "testing.h"
+#include "collectd.h"
+#include "common.h" /* for STATIC_ARRAY_SIZE */
+#include "utils_time.h"
+#include "utils_latency.h"
+
+DEF_TEST(simple)
+{
+ struct {
+ double val;
+ double min;
+ double max;
+ double sum;
+ double avg;
+ } cases[] = {
+ /* val min max sum avg */
+ {0.5, 0.5, 0.5, 0.5, 0.5},
+ {0.3, 0.3, 0.5, 0.8, 0.4},
+ {0.7, 0.3, 0.7, 1.5, 0.5},
+ {2.5, 0.3, 2.5, 4.0, 1.0},
+ { -1, 0.3, 2.5, 4.0, 1.0},
+ };
+ size_t i;
+ latency_counter_t *l;
+
+ CHECK_NOT_NULL (l = latency_counter_create ());
+
+ for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+ latency_counter_add (l, DOUBLE_TO_CDTIME_T (cases[i].val));
+
+ DBLEQ (cases[i].min, CDTIME_T_TO_DOUBLE (latency_counter_get_min (l)));
+ DBLEQ (cases[i].max, CDTIME_T_TO_DOUBLE (latency_counter_get_max (l)));
+ DBLEQ (cases[i].sum, CDTIME_T_TO_DOUBLE (latency_counter_get_sum (l)));
+ DBLEQ (cases[i].avg, CDTIME_T_TO_DOUBLE (latency_counter_get_average (l)));
+ }
+
+ latency_counter_destroy (l);
+ return 0;
+}
+
+DEF_TEST(percentile)
+{
+ size_t i;
+ latency_counter_t *l;
+
+ CHECK_NOT_NULL (l = latency_counter_create ());
+
+ for (i = 0; i < 100; i++) {
+ latency_counter_add (l, TIME_T_TO_CDTIME_T (((time_t) i) + 1));
+ }
+
+ DBLEQ ( 1.0, CDTIME_T_TO_DOUBLE (latency_counter_get_min (l)));
+ DBLEQ (100.0, CDTIME_T_TO_DOUBLE (latency_counter_get_max (l)));
+ DBLEQ (100.0 * 101.0 / 2.0, CDTIME_T_TO_DOUBLE (latency_counter_get_sum (l)));
+ DBLEQ ( 50.5, CDTIME_T_TO_DOUBLE (latency_counter_get_average (l)));
+
+ DBLEQ (50.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 50.0)));
+ DBLEQ (80.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 80.0)));
+ DBLEQ (95.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 95.0)));
+ DBLEQ (99.0, CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (l, 99.0)));
+
+ CHECK_ZERO (latency_counter_get_percentile (l, -1.0));
+ CHECK_ZERO (latency_counter_get_percentile (l, 101.0));
+
+ latency_counter_destroy (l);
+ return 0;
+}
+
+int main (void)
+{
+ RUN_TEST(simple);
+ RUN_TEST(percentile);
+
+ END_TEST;
+}
+
+/* vim: set sw=2 sts=2 et : */
identifier_t *class = user_class;
identifier_t *obj;
- OK(expect_new_obj);
+ assert (expect_new_obj);
memcpy (&last_class_ident, class, sizeof (last_class_ident));
return ((void *) obj);
}
-static void checked_lookup_add (lookup_t *obj, /* {{{ */
+static int checked_lookup_add (lookup_t *obj, /* {{{ */
char const *host,
char const *plugin, char const *plugin_instance,
char const *type, char const *type_instance,
memmove (user_class, &ident, sizeof (ident));
OK(lookup_add (obj, &ident, group_by, user_class) == 0);
-} /* }}} void test_add */
+ return 0;
+} /* }}} int checked_lookup_add */
static int checked_lookup_search (lookup_t *obj,
char const *host,
return (status);
}
-static lookup_t *checked_lookup_create (void)
-{
- lookup_t *obj = lookup_create (
- lookup_class_callback,
- lookup_obj_callback,
- (void *) free,
- (void *) free);
- OK(obj != NULL);
- return (obj);
-}
-
DEF_TEST(group_by_specific_host)
{
- lookup_t *obj = checked_lookup_create ();
+ lookup_t *obj;
+ CHECK_NOT_NULL (obj = lookup_create (
+ lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
checked_lookup_add (obj, "/.*/", "test", "", "test", "/.*/", LU_GROUP_BY_HOST);
checked_lookup_search (obj, "host0", "test", "", "test", "0",
DEF_TEST(group_by_any_host)
{
- lookup_t *obj = checked_lookup_create ();
+ lookup_t *obj;
+ CHECK_NOT_NULL (obj = lookup_create (
+ lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
checked_lookup_add (obj, "/.*/", "/.*/", "/.*/", "test", "/.*/", LU_GROUP_BY_HOST);
checked_lookup_search (obj, "host0", "plugin0", "", "test", "0",
DEF_TEST(multiple_lookups)
{
- lookup_t *obj = checked_lookup_create ();
+ lookup_t *obj;
int status;
+ CHECK_NOT_NULL (obj = lookup_create (
+ lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
+
checked_lookup_add (obj, "/.*/", "plugin0", "", "test", "/.*/", LU_GROUP_BY_HOST);
checked_lookup_add (obj, "/.*/", "/.*/", "", "test", "ti0", LU_GROUP_BY_HOST);
DEF_TEST(regex)
{
- lookup_t *obj = checked_lookup_create ();
+ lookup_t *obj;
+ CHECK_NOT_NULL (obj = lookup_create (
+ lookup_class_callback, lookup_obj_callback, (void *) free, (void *) free));
checked_lookup_add (obj, "/^db[0-9]\\./", "cpu", "/.*/", "cpu", "/.*/",
LU_GROUP_BY_TYPE_INSTANCE);
status = VSM_n_Arg (vd, conf->instance);
if (status < 0)
{
+ VSM_Delete (vd);
ERROR ("varnish plugin: VSM_n_Arg (\"%s\") failed "
"with status %i.",
conf->instance, status);
if (VSM_Open (vd))
#endif
{
- ERROR ("varnish plugin: Unable to load statistics.");
+ VSM_Delete (vd);
+ ERROR ("varnish plugin: Unable to open connection.");
return (-1);
}
#else /* if HAVE_VARNISH_V4 */
stats = VSC_Main(vd, NULL);
#endif
+ if (!stats)
+ {
+ VSM_Delete (vd);
+ ERROR ("varnish plugin: Unable to get statistics.");
+
+ return (-1);
+ }
+
varnish_monitor (conf, stats);
- VSM_Close (vd);
+ VSM_Delete (vd);
return (0);
} /* }}} */
int port;
struct timeval timeout;
char *prefix;
+ int database;
redisContext *conn;
pthread_mutex_t lock;
pthread_mutex_unlock (&node->lock);
return (-1);
}
+
+ rr = redisCommand(node->conn, "SELECT %d", node->database);
+ if (rr == NULL)
+ WARNING("SELECT command error. database:%d message:%s", node->database, node->conn->errstr);
+ else
+ freeReplyObject (rr);
}
rr = redisCommand (node->conn, "ZADD %s %s %s", key, time, value);
node->timeout.tv_usec = 1000;
node->conn = NULL;
node->prefix = NULL;
+ node->database = 0;
pthread_mutex_init (&node->lock, /* attr = */ NULL);
status = cf_util_get_string_buffer (ci, node->name, sizeof (node->name));
else if (strcasecmp ("Prefix", child->key) == 0) {
status = cf_util_get_string (child, &node->prefix);
}
+ else if (strcasecmp ("Database", child->key) == 0) {
+ status = cf_util_get_int (child, &node->database);
+ }
else
WARNING ("write_redis plugin: Ignoring unknown config option \"%s\".",
child->key);