From: Florian Forster Date: Thu, 17 Sep 2009 08:16:40 +0000 (+0200) Subject: Merge branch 'collectd-4.8' X-Git-Tag: collectd-4.9.0~79 X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=5a4daa815531077fdf8b3e425b92f88fa0abb42a;hp=0384380080a39adb252a4d5dd3a6bf5c27f8faf8;p=collectd.git Merge branch 'collectd-4.8' --- diff --git a/configure.in b/configure.in index a58002a0..415ddd71 100644 --- a/configure.in +++ b/configure.in @@ -3800,6 +3800,7 @@ AC_PLUGIN([tail], [yes], [Parsing of logfiles]) AC_PLUGIN([tape], [$plugin_tape], [Tape drive statistics]) AC_PLUGIN([target_notification], [yes], [The notification target]) AC_PLUGIN([target_replace], [yes], [The replace target]) +AC_PLUGIN([target_scale],[yes], [The scale target]) AC_PLUGIN([target_set], [yes], [The set target]) AC_PLUGIN([tcpconns], [$plugin_tcpconns], [TCP connection statistics]) AC_PLUGIN([teamspeak2], [yes], [TeamSpeak2 server statistics]) @@ -4100,6 +4101,7 @@ Configuration: tape . . . . . . . . $enable_tape target_notification . $enable_target_notification target_replace . . . $enable_target_replace + target_scale . . . . $enable_target_scale target_set . . . . . $enable_target_set tcpconns . . . . . . $enable_tcpconns teamspeak2 . . . . . $enable_teamspeak2 diff --git a/src/Makefile.am b/src/Makefile.am index 2a836591..54befad7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -911,6 +911,14 @@ collectd_LDADD += "-dlopen" target_replace.la collectd_DEPENDENCIES += target_replace.la endif +if BUILD_PLUGIN_TARGET_SCALE +pkglib_LTLIBRARIES += target_scale.la +target_scale_la_SOURCES = target_scale.c +target_scale_la_LDFLAGS = -module -avoid-version +collectd_LDADD += "-dlopen" target_scale.la +collectd_DEPENDENCIES += target_scale.la +endif + if BUILD_PLUGIN_TARGET_SET pkglib_LTLIBRARIES += target_set.la target_set_la_SOURCES = target_set.c diff --git a/src/collectd-exec.pod b/src/collectd-exec.pod index b95779dd..81b3a2ec 100644 --- a/src/collectd-exec.pod +++ b/src/collectd-exec.pod @@ -230,6 +230,23 @@ associated with a certain value. =back +=head1 ENVIRONMENT + +The following environment variables are set by the plugin before calling +I: + +=over 4 + +=item COLLECTD_INTERVAL + +Value of the global interval setting. + +=item COLLECTD_HOSTNAME + +Hostname used by I to dispatch local values. + +=back + =head1 USING NAGIOS PLUGINS Though the interface is far from perfect, there are tons of plugins for Nagios. diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 43a322bf..7ae1da24 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -501,6 +501,10 @@ File that holds one or more SSL certificates. If you want to use HTTPS you will possibly need this option. What CA certificates come bundled with C and are checked by default depends on the distribution you use. +=item B B|B + +Measure response time for the request. Disabled by default. + =item BMatchE> One or more B blocks that define how to match information in the data diff --git a/src/curl.c b/src/curl.c index a43e7ed9..abf45c23 100644 --- a/src/curl.c +++ b/src/curl.c @@ -57,6 +57,7 @@ struct web_page_s /* {{{ */ int verify_peer; int verify_host; char *cacert; + int response_time; CURL *curl; char curl_errbuf[CURL_ERROR_SIZE]; @@ -424,6 +425,7 @@ static int cc_config_add_page (oconfig_item_t *ci) /* {{{ */ page->pass = NULL; page->verify_peer = 1; page->verify_host = 1; + page->response_time = 0; page->instance = strdup (ci->values[0].value.string); if (page->instance == NULL) @@ -449,6 +451,8 @@ static int cc_config_add_page (oconfig_item_t *ci) /* {{{ */ status = cc_config_set_boolean ("VerifyPeer", &page->verify_peer, child); else if (strcasecmp ("VerifyHost", child->key) == 0) status = cc_config_set_boolean ("VerifyHost", &page->verify_host, child); + else if (strcasecmp ("MeasureResponseTime", child->key) == 0) + status = cc_config_set_boolean (child->key, &page->response_time, child); else if (strcasecmp ("CACert", child->key) == 0) status = cc_config_add_string ("CACert", &page->cacert, child); else if (strcasecmp ("Match", child->key) == 0) @@ -473,11 +477,11 @@ static int cc_config_add_page (oconfig_item_t *ci) /* {{{ */ status = -1; } - if (page->matches == NULL) + if (page->matches == NULL && !page->response_time) { assert (page->instance != NULL); WARNING ("curl plugin: No (valid) `Match' block " - "within `Page' block `%s'.", page->instance); + "or MeasureResponseTime within `Page' block `%s'.", page->instance); status = -1; } @@ -577,10 +581,32 @@ static void cc_submit (const web_page_t *wp, const web_match_t *wm, /* {{{ */ plugin_dispatch_values (&vl); } /* }}} void cc_submit */ +static void cc_submit_response_time (const web_page_t *wp, double seconds) /* {{{ */ +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + values[0].gauge = seconds; + + vl.values = values; + vl.values_len = 1; + vl.time = time (NULL); + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "curl", sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance)); + sstrncpy (vl.type, "response_time", sizeof (vl.type)); + + plugin_dispatch_values (&vl); +} /* }}} void cc_submit_response_time */ + static int cc_read_page (web_page_t *wp) /* {{{ */ { web_match_t *wm; int status; + struct timeval start, end; + + if (wp->response_time) + gettimeofday (&start, NULL); wp->buffer_fill = 0; status = curl_easy_perform (wp->curl); @@ -591,6 +617,15 @@ static int cc_read_page (web_page_t *wp) /* {{{ */ return (-1); } + if (wp->response_time) + { + double secs = 0; + gettimeofday (&end, NULL); + secs += end.tv_sec - start.tv_sec; + secs += (end.tv_usec - start.tv_usec) / 1000000.0; + cc_submit_response_time (wp, secs); + } + for (wm = wp->matches; wm != NULL; wm = wm->next) { cu_match_value_t *mv; diff --git a/src/exec.c b/src/exec.c index 8719201e..acc6cf6f 100644 --- a/src/exec.c +++ b/src/exec.c @@ -265,6 +265,17 @@ static int exec_config (oconfig_item_t *ci) /* {{{ */ return (0); } /* int exec_config }}} */ +static void set_environment (void) /* {{{ */ +{ + char buffer[1024]; + + ssnprintf (buffer, sizeof (buffer), "%i", interval_g); + setenv ("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1); + + ssnprintf (buffer, sizeof (buffer), "%s", hostname_g); + setenv ("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1); +} /* }}} void set_environment */ + static void exec_child (program_list_t *pl) /* {{{ */ { int status; @@ -477,6 +488,8 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err) close (fd_pipe_err[1]); } + set_environment (); + /* Unblock all signals */ reset_signal_mask (); diff --git a/src/target_scale.c b/src/target_scale.c new file mode 100644 index 00000000..6b261c7c --- /dev/null +++ b/src/target_scale.c @@ -0,0 +1,420 @@ +/** + * collectd - src/target_scale.c + * Copyright (C) 2008-2009 Florian Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian Forster + **/ + +#include "collectd.h" +#include "common.h" +#include "filter_chain.h" + +#include "utils_cache.h" + +struct ts_data_s +{ + double factor; + double offset; +}; +typedef struct ts_data_s ts_data_t; + +static int ts_invoke_counter (const data_set_t *ds, value_list_t *vl, /* {{{ */ + ts_data_t *data, int dsrc_index) +{ + uint64_t curr_counter; + int status; + int failure; + + /* Required meta data */ + uint64_t prev_counter; + char key_prev_counter[128]; + uint64_t int_counter; + char key_int_counter[128]; + double int_fraction; + char key_int_fraction[128]; + + curr_counter = (uint64_t) vl->values[dsrc_index].counter; + + ssnprintf (key_prev_counter, sizeof (key_prev_counter), + "target_scale[%p,%i]:prev_counter", + (void *) data, dsrc_index); + ssnprintf (key_int_counter, sizeof (key_int_counter), + "target_scale[%p,%i]:int_counter", + (void *) data, dsrc_index); + ssnprintf (key_int_fraction, sizeof (key_int_fraction), + "target_scale[%p,%i]:int_fraction", + (void *) data, dsrc_index); + + prev_counter = curr_counter; + int_counter = 0; + int_fraction = 0.0; + + /* Query the meta data */ + failure = 0; + + status = uc_meta_data_get_unsigned_int (vl, key_prev_counter, + &prev_counter); + if (status != 0) + failure++; + + status = uc_meta_data_get_unsigned_int (vl, key_int_counter, &int_counter); + if (status != 0) + failure++; + + status = uc_meta_data_get_double (vl, key_int_fraction, &int_fraction); + if (status != 0) + failure++; + + if (failure == 0) + { + uint64_t difference; + double rate; + + /* Calcualte the rate */ + if (prev_counter > curr_counter) /* => counter overflow */ + { + if (prev_counter <= 4294967295UL) /* 32 bit overflow */ + difference = (4294967295UL - prev_counter) + curr_counter; + else /* 64 bit overflow */ + difference = (18446744073709551615ULL - prev_counter) + curr_counter; + } + else /* no overflow */ + { + difference = curr_counter - prev_counter; + } + rate = ((double) difference) / ((double) vl->interval); + + /* Modify the rate. */ + if (!isnan (data->factor)) + rate *= data->factor; + if (!isnan (data->offset)) + rate += data->offset; + + /* Calculate the internal counter. */ + int_fraction += (rate * ((double) vl->interval)); + difference = (uint64_t) int_fraction; + int_fraction -= ((double) difference); + int_counter += difference; + + assert (int_fraction >= 0.0); + assert (int_fraction < 1.0); + + DEBUG ("Target `scale': ts_invoke_counter: %"PRIu64" -> %g -> %"PRIu64 + "(+%g)", + curr_counter, rate, int_counter, int_fraction); + } + else /* (failure != 0) */ + { + int_counter = 0; + int_fraction = 0.0; + } + + vl->values[dsrc_index].counter = (counter_t) int_counter; + + /* Update to the new counter value */ + uc_meta_data_add_unsigned_int (vl, key_prev_counter, curr_counter); + uc_meta_data_add_unsigned_int (vl, key_int_counter, int_counter); + uc_meta_data_add_double (vl, key_int_fraction, int_fraction); + + + return (0); +} /* }}} int ts_invoke_counter */ + +static int ts_invoke_gauge (const data_set_t *ds, value_list_t *vl, /* {{{ */ + ts_data_t *data, int dsrc_index) +{ + if (!isnan (data->factor)) + vl->values[dsrc_index].gauge *= data->factor; + if (!isnan (data->offset)) + vl->values[dsrc_index].gauge += data->offset; + + return (0); +} /* }}} int ts_invoke_gauge */ + +static int ts_invoke_derive (const data_set_t *ds, value_list_t *vl, /* {{{ */ + ts_data_t *data, int dsrc_index) +{ + int64_t curr_derive; + int status; + int failure; + + /* Required meta data */ + int64_t prev_derive; + char key_prev_derive[128]; + int64_t int_derive; + char key_int_derive[128]; + double int_fraction; + char key_int_fraction[128]; + + curr_derive = (int64_t) vl->values[dsrc_index].derive; + + ssnprintf (key_prev_derive, sizeof (key_prev_derive), + "target_scale[%p,%i]:prev_derive", + (void *) data, dsrc_index); + ssnprintf (key_int_derive, sizeof (key_int_derive), + "target_scale[%p,%i]:int_derive", + (void *) data, dsrc_index); + ssnprintf (key_int_fraction, sizeof (key_int_fraction), + "target_scale[%p,%i]:int_fraction", + (void *) data, dsrc_index); + + prev_derive = curr_derive; + int_derive = 0; + int_fraction = 0.0; + + /* Query the meta data */ + failure = 0; + + status = uc_meta_data_get_signed_int (vl, key_prev_derive, + &prev_derive); + if (status != 0) + failure++; + + status = uc_meta_data_get_signed_int (vl, key_int_derive, &int_derive); + if (status != 0) + failure++; + + status = uc_meta_data_get_double (vl, key_int_fraction, &int_fraction); + if (status != 0) + failure++; + + if (failure == 0) + { + int64_t difference; + double rate; + + /* Calcualte the rate */ + difference = curr_derive - prev_derive; + rate = ((double) difference) / ((double) vl->interval); + + /* Modify the rate. */ + if (!isnan (data->factor)) + rate *= data->factor; + if (!isnan (data->offset)) + rate += data->offset; + + /* Calculate the internal derive. */ + int_fraction += (rate * ((double) vl->interval)); + if (int_fraction < 0.0) /* handle negative integer rounding correctly */ + difference = ((int64_t) int_fraction) - 1; + else + difference = (int64_t) int_fraction; + int_fraction -= ((double) difference); + int_derive += difference; + + assert (int_fraction >= 0.0); + assert (int_fraction < 1.0); + + DEBUG ("Target `scale': ts_invoke_derive: %"PRIu64" -> %g -> %"PRIu64 + "(+%g)", + curr_derive, rate, int_derive, int_fraction); + } + else /* (failure != 0) */ + { + int_derive = 0; + int_fraction = 0.0; + } + + vl->values[dsrc_index].derive = (derive_t) int_derive; + + /* Update to the new derive value */ + uc_meta_data_add_signed_int (vl, key_prev_derive, curr_derive); + uc_meta_data_add_signed_int (vl, key_int_derive, int_derive); + uc_meta_data_add_double (vl, key_int_fraction, int_fraction); + + return (0); +} /* }}} int ts_invoke_derive */ + +static int ts_invoke_absolute (const data_set_t *ds, value_list_t *vl, /* {{{ */ + ts_data_t *data, int dsrc_index) +{ + uint64_t curr_absolute; + double rate; + int status; + + /* Required meta data */ + double int_fraction; + char key_int_fraction[128]; + + curr_absolute = (uint64_t) vl->values[dsrc_index].absolute; + + ssnprintf (key_int_fraction, sizeof (key_int_fraction), + "target_scale[%p,%i]:int_fraction", + (void *) data, dsrc_index); + + int_fraction = 0.0; + + /* Query the meta data */ + status = uc_meta_data_get_double (vl, key_int_fraction, &int_fraction); + if (status != 0) + int_fraction = 0.0; + + rate = ((double) curr_absolute) / ((double) vl->interval); + + /* Modify the rate. */ + if (!isnan (data->factor)) + rate *= data->factor; + if (!isnan (data->offset)) + rate += data->offset; + + /* Calculate the new absolute. */ + int_fraction += (rate * ((double) vl->interval)); + curr_absolute = (uint64_t) int_fraction; + int_fraction -= ((double) curr_absolute); + + vl->values[dsrc_index].absolute = (absolute_t) curr_absolute; + + /* Update to the new absolute value */ + uc_meta_data_add_double (vl, key_int_fraction, int_fraction); + + return (0); +} /* }}} int ts_invoke_absolute */ + +static int ts_config_set_double (double *ret, oconfig_item_t *ci) /* {{{ */ +{ + if ((ci->values_num != 1) + || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) + { + WARNING ("scale target: The `%s' config option needs " + "exactly one numeric argument.", ci->key); + return (-1); + } + + *ret = ci->values[0].value.number; + DEBUG ("ts_config_set_double: *ret = %g", *ret); + + return (0); +} /* }}} int ts_config_set_double */ + +static int ts_destroy (void **user_data) /* {{{ */ +{ + if (user_data == NULL) + return (-EINVAL); + + free (*user_data); + *user_data = NULL; + + return (0); +} /* }}} int ts_destroy */ + +static int ts_create (const oconfig_item_t *ci, void **user_data) /* {{{ */ +{ + ts_data_t *data; + int status; + int i; + + data = (ts_data_t *) malloc (sizeof (*data)); + if (data == NULL) + { + ERROR ("ts_create: malloc failed."); + return (-ENOMEM); + } + memset (data, 0, sizeof (*data)); + + data->factor = NAN; + data->offset = NAN; + + status = 0; + for (i = 0; i < ci->children_num; i++) + { + oconfig_item_t *child = ci->children + i; + + if (strcasecmp ("Factor", child->key) == 0) + status = ts_config_set_double (&data->factor, child); + else if (strcasecmp ("Offset", child->key) == 0) + status = ts_config_set_double (&data->offset, child); + else + { + ERROR ("Target `scale': The `%s' configuration option is not understood " + "and will be ignored.", child->key); + status = 0; + } + + if (status != 0) + break; + } + + /* Additional sanity-checking */ + while (status == 0) + { + if (isnan (data->factor) && isnan (data->offset)) + { + ERROR ("Target `scale': You need to at least set either the `Factor' " + "or `Offset' option!"); + status = -1; + } + + break; + } + + if (status != 0) + { + ts_destroy ((void *) &data); + return (status); + } + + *user_data = data; + return (0); +} /* }}} int ts_create */ + +static int ts_invoke (const data_set_t *ds, value_list_t *vl, /* {{{ */ + notification_meta_t __attribute__((unused)) **meta, void **user_data) +{ + ts_data_t *data; + int i; + + if ((ds == NULL) || (vl == NULL) || (user_data == NULL)) + return (-EINVAL); + + data = *user_data; + if (data == NULL) + { + ERROR ("Target `scale': Invoke: `data' is NULL."); + return (-EINVAL); + } + + for (i = 0; i < ds->ds_num; i++) + { + if (ds->ds[i].type == DS_TYPE_COUNTER) + ts_invoke_counter (ds, vl, data, i); + else if (ds->ds[i].type == DS_TYPE_GAUGE) + ts_invoke_gauge (ds, vl, data, i); + else if (ds->ds[i].type == DS_TYPE_DERIVE) + ts_invoke_derive (ds, vl, data, i); + else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) + ts_invoke_absolute (ds, vl, data, i); + else + ERROR ("Target `scale': Ignoring unknown data source type %i", + ds->ds[i].type); + } + + return (FC_TARGET_CONTINUE); +} /* }}} int ts_invoke */ + +void module_register (void) +{ + target_proc_t tproc; + + memset (&tproc, 0, sizeof (tproc)); + tproc.create = ts_create; + tproc.destroy = ts_destroy; + tproc.invoke = ts_invoke; + fc_register_target ("scale", tproc); +} /* module_register */ + +/* vim: set sw=2 ts=2 tw=78 fdm=marker : */ + diff --git a/src/types.db b/src/types.db index 20df90eb..106de859 100644 --- a/src/types.db +++ b/src/types.db @@ -122,6 +122,7 @@ ps_state value:GAUGE:0:65535 ps_vm value:GAUGE:0:9223372036854775807 queue_length value:GAUGE:0:U records count:GAUGE:0:U +response_time value:GAUGE:0:U route_etx value:GAUGE:0:U route_metric value:GAUGE:0:U routes value:GAUGE:0:U