X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fstatsd.c;h=5b7a6f182e7cef26af41b8db2baeb26c55f95b47;hb=d0540d2ebaead6661de0ef29c0435c046c7ff4f7;hp=f6811b6fb29d4d82bdf2efcd1d4fceda8b69f0a6;hpb=15e7c7f36e8825a3f88854057eb7636df1fd6674;p=collectd.git diff --git a/src/statsd.c b/src/statsd.c index f6811b6f..5b7a6f18 100644 --- a/src/statsd.c +++ b/src/statsd.c @@ -1,19 +1,24 @@ /** * collectd - src/statsd.c - * * Copyright (C) 2013 Florian octo Forster * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * 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" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 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 @@ -30,7 +35,6 @@ #include #include -#include #include #include @@ -60,6 +64,7 @@ struct statsd_metric_s { metric_type_t type; double value; + derive_t counter; latency_counter_t *latency; c_avl_tree_t *set; unsigned long updates_num; @@ -84,6 +89,7 @@ static _Bool conf_delete_sets = 0; static double *conf_timer_percentile = NULL; static size_t conf_timer_percentile_num = 0; +static _Bool conf_counter_sum = 0; static _Bool conf_timer_lower = 0; static _Bool conf_timer_upper = 0; static _Bool conf_timer_sum = 0; @@ -121,14 +127,13 @@ static statsd_metric_t *statsd_metric_lookup_unsafe (char const *name, /* {{{ */ return (NULL); } - metric = malloc (sizeof (*metric)); + metric = calloc (1, sizeof (*metric)); if (metric == NULL) { - ERROR ("statsd plugin: malloc failed."); + ERROR ("statsd plugin: calloc failed."); sfree (key_copy); return (NULL); } - memset (metric, 0, sizeof (*metric)); metric->type = type; metric->latency = NULL; @@ -257,6 +262,8 @@ static int statsd_handle_counter (char const *name, /* {{{ */ if (status != 0) return (status); + /* Changes to the counter are added to (statsd_metric_t*)->value. ->counter is + * only updated in statsd_metric_submit_unsafe(). */ return (statsd_metric_add (name, (double) (value.gauge / scale.gauge), STATSD_COUNTER)); } /* }}} int statsd_handle_counter */ @@ -557,6 +564,7 @@ static int statsd_network_init (struct pollfd **ret_fds, /* {{{ */ if (tmp == NULL) { ERROR ("statsd plugin: realloc failed."); + close (fd); continue; } fds = tmp; @@ -680,6 +688,8 @@ static int statsd_config (oconfig_item_t *ci) /* {{{ */ cf_util_get_boolean (child, &conf_delete_gauges); else if (strcasecmp ("DeleteSets", child->key) == 0) cf_util_get_boolean (child, &conf_delete_sets); + else if (strcasecmp ("CounterSum", child->key) == 0) + cf_util_get_boolean (child, &conf_counter_sum); else if (strcasecmp ("TimerLower", child->key) == 0) cf_util_get_boolean (child, &conf_timer_lower); else if (strcasecmp ("TimerUpper", child->key) == 0) @@ -750,8 +760,7 @@ static int statsd_metric_clear_set_unsafe (statsd_metric_t *metric) /* {{{ */ } /* }}} int statsd_metric_clear_set_unsafe */ /* Must hold metrics_lock when calling this function. */ -static int statsd_metric_submit_unsafe (char const *name, /* {{{ */ - statsd_metric_t const *metric) +static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metric) /* {{{ */ { value_t values[1]; value_list_t vl = VALUE_LIST_INIT; @@ -777,39 +786,42 @@ static int statsd_metric_submit_unsafe (char const *name, /* {{{ */ else if (metric->type == STATSD_TIMER) { size_t i; + _Bool have_events = (metric->updates_num > 0); - if (metric->updates_num == 0) - return (0); - + /* Make sure all timer metrics share the *same* timestamp. */ vl.time = cdtime (); ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-average", name); - values[0].gauge = CDTIME_T_TO_DOUBLE ( - latency_counter_get_average (metric->latency)); + values[0].gauge = have_events + ? CDTIME_T_TO_DOUBLE (latency_counter_get_average (metric->latency)) + : NAN; plugin_dispatch_values (&vl); if (conf_timer_lower) { ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-lower", name); - values[0].gauge = CDTIME_T_TO_DOUBLE ( - latency_counter_get_min (metric->latency)); + values[0].gauge = have_events + ? CDTIME_T_TO_DOUBLE (latency_counter_get_min (metric->latency)) + : NAN; plugin_dispatch_values (&vl); } if (conf_timer_upper) { ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-upper", name); - values[0].gauge = CDTIME_T_TO_DOUBLE ( - latency_counter_get_max (metric->latency)); + values[0].gauge = have_events + ? CDTIME_T_TO_DOUBLE (latency_counter_get_max (metric->latency)) + : NAN; plugin_dispatch_values (&vl); } if (conf_timer_sum) { ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-sum", name); - values[0].gauge = CDTIME_T_TO_DOUBLE ( - latency_counter_get_sum (metric->latency)); + values[0].gauge = have_events + ? CDTIME_T_TO_DOUBLE (latency_counter_get_sum (metric->latency)) + : NAN; plugin_dispatch_values (&vl); } @@ -817,9 +829,9 @@ static int statsd_metric_submit_unsafe (char const *name, /* {{{ */ { ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s-percentile-%.0f", name, conf_timer_percentile[i]); - values[0].gauge = CDTIME_T_TO_DOUBLE ( - latency_counter_get_percentile ( - metric->latency, conf_timer_percentile[i])); + values[0].gauge = have_events + ? CDTIME_T_TO_DOUBLE (latency_counter_get_percentile (metric->latency, conf_timer_percentile[i])) + : NAN; plugin_dispatch_values (&vl); } @@ -843,8 +855,30 @@ static int statsd_metric_submit_unsafe (char const *name, /* {{{ */ else values[0].gauge = (gauge_t) c_avl_size (metric->set); } - else - values[0].derive = (derive_t) metric->value; + else { /* STATSD_COUNTER */ + gauge_t delta = nearbyint (metric->value); + + /* Etsy's statsd writes counters as two metrics: a rate and the change since + * the last write. Since collectd does not reset its DERIVE metrics to zero, + * this makes little sense, but we're dispatching a "count" metric here + * anyway - if requested by the user - for compatibility reasons. */ + if (conf_counter_sum) + { + sstrncpy (vl.type, "count", sizeof (vl.type)); + values[0].gauge = delta; + plugin_dispatch_values (&vl); + + /* restore vl.type */ + sstrncpy (vl.type, "derive", sizeof (vl.type)); + } + + /* Rather than resetting value to zero, subtract delta so we correctly keep + * track of residuals. */ + metric->value -= delta; + metric->counter += (derive_t) delta; + + values[0].derive = metric->counter; + } return (plugin_dispatch_values (&vl)); } /* }}} int statsd_metric_submit_unsafe */ @@ -934,7 +968,7 @@ static int statsd_shutdown (void) /* {{{ */ while (c_avl_pick (metrics_tree, &key, &value) == 0) { sfree (key); - sfree (value); + statsd_metric_free (value); } c_avl_destroy (metrics_tree); metrics_tree = NULL;