X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fstatsd.c;h=1512b866a870a12da60a3fce6f969c48b3e9bda9;hb=78154d2a5ae84e8f45d4f9ce6a7519add74b4b30;hp=b8fee175574334521120642c78714e80d2db6e84;hpb=74f51aa494578a5b1cbd8a93597374c62db39640;p=collectd.git diff --git a/src/statsd.c b/src/statsd.c index b8fee175..1512b866 100644 --- a/src/statsd.c +++ b/src/statsd.c @@ -34,6 +34,11 @@ #include #include +/* AIX doesn't have MSG_DONTWAIT */ +#ifndef MSG_DONTWAIT +# define MSG_DONTWAIT MSG_NONBLOCK +#endif + #ifndef STATSD_DEFAULT_NODE # define STATSD_DEFAULT_NODE NULL #endif @@ -54,7 +59,7 @@ typedef enum metric_type_e metric_type_t; struct statsd_metric_s { metric_type_t type; - int64_t value; + double value; latency_counter_t *latency; c_avl_tree_t *set; unsigned long updates_num; @@ -79,8 +84,13 @@ static _Bool conf_delete_sets = 0; static double *conf_timer_percentile = NULL; static size_t conf_timer_percentile_num = 0; +static _Bool conf_timer_lower = 0; +static _Bool conf_timer_upper = 0; +static _Bool conf_timer_sum = 0; +static _Bool conf_timer_count = 0; + /* Must hold metrics_lock when calling this function. */ -static statsd_metric_t *statsd_metric_lookup_unsafe (char const *name, +static statsd_metric_t *statsd_metric_lookup_unsafe (char const *name, /* {{{ */ metric_type_t type) { char key[DATA_MAX_NAME_LEN + 2]; @@ -136,7 +146,7 @@ static statsd_metric_t *statsd_metric_lookup_unsafe (char const *name, return (metric); } /* }}} statsd_metric_lookup_unsafe */ -static int statsd_metric_set (char const *name, int64_t value, /* {{{ */ +static int statsd_metric_set (char const *name, double value, /* {{{ */ metric_type_t type) { statsd_metric_t *metric; @@ -158,7 +168,7 @@ static int statsd_metric_set (char const *name, int64_t value, /* {{{ */ return (0); } /* }}} int statsd_metric_set */ -static int statsd_metric_add (char const *name, int64_t delta, /* {{{ */ +static int statsd_metric_add (char const *name, double delta, /* {{{ */ metric_type_t type) { statsd_metric_t *metric; @@ -180,6 +190,46 @@ static int statsd_metric_add (char const *name, int64_t delta, /* {{{ */ return (0); } /* }}} int statsd_metric_add */ +static void statsd_metric_free (statsd_metric_t *metric) /* {{{ */ +{ + if (metric == NULL) + return; + + if (metric->latency != NULL) + { + latency_counter_destroy (metric->latency); + metric->latency = NULL; + } + + if (metric->set != NULL) + { + void *key; + void *value; + + while (c_avl_pick (metric->set, &key, &value) == 0) + { + sfree (key); + assert (value == NULL); + } + + c_avl_destroy (metric->set); + metric->set = NULL; + } + + sfree (metric); +} /* }}} void statsd_metric_free */ + +static int statsd_parse_value (char const *str, value_t *ret_value) /* {{{ */ +{ + char *endptr = NULL; + + ret_value->gauge = (gauge_t) strtod (str, &endptr); + if ((str == endptr) || ((endptr != NULL) && (*endptr != 0))) + return (-1); + + return (0); +} /* }}} int statsd_parse_value */ + static int statsd_handle_counter (char const *name, /* {{{ */ char const *value_str, char const *extra) @@ -194,7 +244,7 @@ static int statsd_handle_counter (char const *name, /* {{{ */ scale.gauge = 1.0; if (extra != NULL) { - status = parse_value (extra + 1, &scale, DS_TYPE_GAUGE); + status = statsd_parse_value (extra + 1, &scale); if (status != 0) return (status); @@ -202,16 +252,12 @@ static int statsd_handle_counter (char const *name, /* {{{ */ return (-1); } - value.derive = 1; - status = parse_value (value_str, &value, DS_TYPE_DERIVE); + value.gauge = 1.0; + status = statsd_parse_value (value_str, &value); if (status != 0) return (status); - if (value.derive < 1) - return (-1); - - return (statsd_metric_add (name, - (int64_t) (((gauge_t) value.derive) / scale.gauge), + return (statsd_metric_add (name, (double) (value.gauge / scale.gauge), STATSD_COUNTER)); } /* }}} int statsd_handle_counter */ @@ -221,31 +267,47 @@ static int statsd_handle_gauge (char const *name, /* {{{ */ value_t value; int status; - value.derive = 0; - status = parse_value (value_str, &value, DS_TYPE_DERIVE); + value.gauge = 0; + status = statsd_parse_value (value_str, &value); if (status != 0) return (status); if ((value_str[0] == '+') || (value_str[0] == '-')) - return (statsd_metric_add (name, (int64_t) value.derive, STATSD_GAUGE)); + return (statsd_metric_add (name, (double) value.gauge, STATSD_GAUGE)); else - return (statsd_metric_set (name, (int64_t) value.derive, STATSD_GAUGE)); + return (statsd_metric_set (name, (double) value.gauge, STATSD_GAUGE)); } /* }}} int statsd_handle_gauge */ static int statsd_handle_timer (char const *name, /* {{{ */ - char const *value_str) + char const *value_str, + char const *extra) { statsd_metric_t *metric; value_t value_ms; + value_t scale; cdtime_t value; int status; + if ((extra != NULL) && (extra[0] != '@')) + return (-1); + + scale.gauge = 1.0; + if (extra != NULL) + { + status = statsd_parse_value (extra + 1, &scale); + if (status != 0) + return (status); + + if (!isfinite (scale.gauge) || (scale.gauge <= 0.0) || (scale.gauge > 1.0)) + return (-1); + } + value_ms.derive = 0; - status = parse_value (value_str, &value_ms, DS_TYPE_DERIVE); + status = statsd_parse_value (value_str, &value_ms); if (status != 0) return (status); - value = MS_TO_CDTIME_T (value_ms.derive); + value = MS_TO_CDTIME_T (value_ms.gauge / scale.gauge); pthread_mutex_lock (&metrics_lock); @@ -355,15 +417,15 @@ static int statsd_parse_line (char *buffer) /* {{{ */ if (strcmp ("c", type) == 0) return (statsd_handle_counter (name, value, extra)); + else if (strcmp ("ms", type) == 0) + return (statsd_handle_timer (name, value, extra)); - /* extra is only valid for counters */ + /* extra is only valid for counters and timers */ if (extra != NULL) return (-1); if (strcmp ("g", type) == 0) return (statsd_handle_gauge (name, value)); - else if (strcmp ("ms", type) == 0) - return (statsd_handle_timer (name, value)); else if (strcmp ("s", type) == 0) return (statsd_handle_set (name, value)); else @@ -372,22 +434,32 @@ static int statsd_parse_line (char *buffer) /* {{{ */ static void statsd_parse_buffer (char *buffer) /* {{{ */ { - char *dummy; - char *saveptr = NULL; - char *ptr; - - for (dummy = buffer; - (ptr = strtok_r (dummy, "\r\n", &saveptr)) != NULL; - dummy = NULL) + while (buffer != NULL) { - char *line_orig = sstrdup (ptr); + char orig[64]; + char *next; int status; - status = statsd_parse_line (ptr); + next = strchr (buffer, '\n'); + if (next != NULL) + { + *next = 0; + next++; + } + + if (*buffer == 0) + { + buffer = next; + continue; + } + + sstrncpy (orig, buffer, sizeof (orig)); + + status = statsd_parse_line (buffer); if (status != 0) - ERROR ("statsd plugin: Unable to parse line: \"%s\"", line_orig); + ERROR ("statsd plugin: Unable to parse line: \"%s\"", orig); - sfree (line_orig); + buffer = next; } } /* }}} void statsd_parse_buffer */ @@ -608,6 +680,14 @@ 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 ("TimerLower", child->key) == 0) + cf_util_get_boolean (child, &conf_timer_lower); + else if (strcasecmp ("TimerUpper", child->key) == 0) + cf_util_get_boolean (child, &conf_timer_upper); + else if (strcasecmp ("TimerSum", child->key) == 0) + cf_util_get_boolean (child, &conf_timer_sum); + else if (strcasecmp ("TimerCount", child->key) == 0) + cf_util_get_boolean (child, &conf_timer_count); else if (strcasecmp ("TimerPercentile", child->key) == 0) statsd_config_timer_percentile (child); else @@ -622,7 +702,7 @@ static int statsd_init (void) /* {{{ */ { pthread_mutex_lock (&metrics_lock); if (metrics_tree == NULL) - metrics_tree = c_avl_create ((void *) strcasecmp); + metrics_tree = c_avl_create ((void *) strcmp); if (!network_thread_running) { @@ -697,25 +777,62 @@ 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 = 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 = 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 = have_events + ? CDTIME_T_TO_DOUBLE (latency_counter_get_sum (metric->latency)) + : NAN; + plugin_dispatch_values (&vl); + } + for (i = 0; i < conf_timer_percentile_num; i++) { 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); + } + + /* Keep this at the end, since vl.type is set to "gauge" here. The + * vl.type's above are implicitly set to "latency". */ + if (conf_timer_count) { + sstrncpy (vl.type, "gauge", sizeof (vl.type)); + ssnprintf (vl.type_instance, sizeof (vl.type_instance), + "%s-count", name); + values[0].gauge = latency_counter_get_num (metric->latency); plugin_dispatch_values (&vl); } @@ -792,7 +909,7 @@ static int statsd_read (void) /* {{{ */ } sfree (name); - sfree (metric); + statsd_metric_free (metric); } pthread_mutex_unlock (&metrics_lock);