AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
sbin_PROGRAMS = collectd collectdmon
-bin_PROGRAMS = collectd-nagios
+bin_PROGRAMS = collectd-nagios collectd-flush
collectd_SOURCES = collectd.c collectd.h \
common.c common.h \
collectd_nagios_LDADD += libcollectdclient/libcollectdclient.la
collectd_nagios_DEPENDENCIES = libcollectdclient/libcollectdclient.la
+
+collectd_flush_SOURCES = collectd-flush.c
+collectd_flush_LDADD =
+if BUILD_WITH_LIBSOCKET
+collectd_flush_LDADD += -lsocket
+endif
+if BUILD_AIX
+collectd_flush_LDADD += -lm
+endif
+collectd_flush_LDADD += libcollectdclient/libcollectdclient.la
+collectd_flush_DEPENDENCIES = libcollectdclient/libcollectdclient.la
+
+
pkglib_LTLIBRARIES =
BUILT_SOURCES =
--- /dev/null
+/**
+ * collectd-flush - src/collectd-flush.c
+ * Copyright (C) 2010 Håkon J Dugstad Johnsen
+ *
+ * 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:
+ * Håkon J Dugstad Johnsen <hakon-dugstad.johnsen at telenor.com>
+ **/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "libcollectdclient/client.h"
+
+extern char *optarg;
+
+static int flush (
+ const char *address,
+ const char *plugin,
+ const char *ident_str,
+ int timeout)
+{
+ lcc_connection_t *connection;
+ lcc_identifier_t ident;
+
+ /* Pointer which is passed to lcc_flush.
+ * Either a null pointer or it points to ident */
+ lcc_identifier_t *identp;
+ int status;
+
+ connection = NULL;
+ status = lcc_connect(address, &connection);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: Connecting to daemon at %s failed: %s.\n",
+ address, strerror (errno));
+ return 1;
+ }
+
+ identp = NULL;
+ if (ident_str != NULL && *ident_str != '\0') {
+ status = lcc_string_to_identifier (connection, &ident, ident_str);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: Creating and identifier failed: %s.\n",
+ lcc_strerror(connection));
+ LCC_DESTROY (connection);
+
+ return 1;
+ }
+ identp = &ident;
+ }
+
+ status = lcc_flush (connection, plugin, identp, timeout);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: Flushing failed: %s.\n",
+ lcc_strerror (connection));
+ LCC_DESTROY (connection);
+
+ return 1;
+ }
+
+ LCC_DESTROY (connection);
+
+ return 0;
+}
+
+void usage (const char *name) {
+ fprintf (stderr, "Usage: %s [options]\n"
+ "\n"
+ "Valid options are:\n"
+ " -h, --help Display this help message.\n"
+ " -s, --socket=<socket> Path to collectd's UNIX socket. Default: /var/run/collectd-unixsock\n"
+ " -p, --plugin=<plugin> Plugin to flush _to_ (not from). Example: rrdtool\n"
+ " -i, --identifier=<identifier>\n"
+ " Only flush data specified by <identifier>, which has the format: \n"
+ "\n"
+ " [<hostname>/]<plugin>[-<plugin_instance>]/<type>[-<type_instance>]\n"
+ "\n"
+ " Hostname defaults to the local hostname if omitted.\n"
+ " No error is returned if the specified identifier does not exist.\n"
+ " Examples: uptime/uptime\n"
+ " somehost/cpu-0/cpu-wait\n"
+ " -t, --timeout=<timeout> Only flush values older than this timeout.\n", name);
+}
+
+/*
+ * Count how many occurences there are of a char in a string.
+ */
+int charoccurences (const char *str, char chr) {
+ int count = 0;
+ while (*str != '\0') {
+ if (*str == chr) {
+ count++;
+ }
+ str++;
+ }
+
+ return count;
+}
+
+int main (int argc, char **argv) {
+ char address[1024] = "unix:/var/run/collectd-unixsock";
+ char *plugin = NULL;
+ char ident_str[1024] = "";
+ int timeout = -1;
+ char hostname[1024];
+ char c;
+
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, 'h'},
+ {"socket", required_argument, 0, 's'},
+ {"plugin", required_argument, 0, 'p'},
+ {"identifier", required_argument, 0, 'i'},
+ {"timeout", required_argument, 0, 't'}
+ };
+ int option_index = 0;
+
+
+ while ((c = getopt_long (argc, argv, "s:p:i:ht:", long_options, &option_index)) != -1) {
+ switch (c) {
+ case 's':
+ snprintf (address, sizeof (address), "unix:%s", optarg);
+ break;
+ case 'p':
+ plugin = optarg;
+ break;
+ case 'i':
+ if(charoccurences(optarg, '/') == 1) {
+ /* The user has omitted the hostname part of the identifier
+ * (there is only one '/' in the identifier)
+ * Let's add the local hostname */
+ if(gethostname(hostname, sizeof(hostname)) != 0) {
+ fprintf (stderr, "Could not get local hostname: %s", strerror(errno));
+ return 1;
+ }
+ /* Make sure hostname is zero-terminated */
+ hostname[sizeof(hostname)-1] = '\0';
+ snprintf (ident_str, sizeof (ident_str), "%s/%s", hostname, optarg);
+ /* Make sure ident_str is zero terminated */
+ ident_str[sizeof(ident_str)-1] = '\0';
+ } else {
+ strncpy(ident_str, optarg, sizeof (ident_str));
+ /* Make sure identifier is zero terminated */
+ ident_str[sizeof(ident_str)-1] = '\0';
+ }
+ break;
+ case 't':
+ timeout = atoi (optarg);
+ break;
+ case 'h':
+ usage (argv[0]);
+ return 0;
+ default:
+ usage (argv[0]);
+ return 1;
+ }
+ }
+
+ return flush(address, plugin, ident_str, timeout);
+}
--- /dev/null
+=head1 NAME
+
+collectd-flush - Small command line utility to flush collectd
+
+=head1 SYNOPSIS
+
+collectd-flush I<[options]>
+
+=head1 DESCRIPTION
+
+This small command line utitilty uses C<libcollectdclient> to flush collectd
+through a socket from the L<unixsock plugin>. Useful if you want to be sure
+you have the latest values in your RRD files before graphing them or copying
+them somewhere else.
+
+=head1 ARGUMENTS AND OPTIONS
+
+The following arguments and options are understood by collectd-flush. The order
+of the arguments generally doesn't matter, as long as no argument is passed
+more than once.
+
+=over 4
+
+=item B<-h>, B<--help>
+
+Display information about the options.
+
+=item B<-s>, B<--socket=>I<socket>
+
+Path to the UNIX socket opened by collectd's C<unixsock plugin>.
+Default: /var/run/collectd-unixsock
+
+=item B<-p>, B<--plugin=>I<plugin>
+
+Plugin to flush I<to>. Example: B<rrdtool>.
+
+=item B<-i>, B<--identifier=>I<identifier>
+
+If this option is present, only the data specified by I<identifier> will be flushed.
+I<identifier> has the following format:
+
+[I<hostname>/]I<plugin>[-I<plugin_instance>]/I<type>[-I<type_instance>]
+
+Examples:
+ somehost/cpu-0/cpu-idle
+ uptime/uptime
+ otherhost/memory/memory-used
+
+Hostname defaults to the local hostname if omitted. No error is returned if the
+specified identifier does not exist (this is a limitation in the
+C<libcollectdclient> library).You can only specify one identifier each time you
+run this program (even though L<collectd-unixsock(5)> supports multiple
+identifiers).
+
+=item B<-t>, B<--timeout=>I<timeout>
+
+Only flush values older than I<timeout>.
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>
+L<collectd.conf(5)>
+L<collectd-unixsock(5)>
+
+=head1 AUTHOR
+
+Håkon J Dugstad Johnsen E<lt>hakon-dugstad.johnsenE<nbsp>atE<nbsp>telenor.comE<gt>
+
+=cut
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_cache.h"
#if HAVE_PTHREAD_H
# include <pthread.h>
return (0);
} /* int format_name */
+int format_values (char *ret, size_t ret_len, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl,
+ _Bool store_rates)
+{
+ size_t offset = 0;
+ int status;
+ int i;
+ gauge_t *rates = NULL;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ memset (ret, 0, ret_len);
+
+#define BUFFER_ADD(...) do { \
+ status = ssnprintf (ret + offset, ret_len - offset, \
+ __VA_ARGS__); \
+ if (status < 1) \
+ { \
+ sfree (rates); \
+ return (-1); \
+ } \
+ else if (((size_t) status) >= (ret_len - offset)) \
+ { \
+ sfree (rates); \
+ return (-1); \
+ } \
+ else \
+ offset += ((size_t) status); \
+} while (0)
+
+ BUFFER_ADD ("%lu", (unsigned long) vl->time);
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_GAUGE)
+ BUFFER_ADD (":%f", vl->values[i].gauge);
+ else if (store_rates)
+ {
+ if (rates == NULL)
+ rates = uc_get_rate (ds, vl);
+ if (rates == NULL)
+ {
+ WARNING ("format_values: "
+ "uc_get_rate failed.");
+ return (-1);
+ }
+ BUFFER_ADD (":%g", rates[i]);
+ }
+ else if (ds->ds[i].type == DS_TYPE_COUNTER)
+ BUFFER_ADD (":%llu", vl->values[i].counter);
+ else if (ds->ds[i].type == DS_TYPE_DERIVE)
+ BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
+ else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+ BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
+ else
+ {
+ ERROR ("format_values plugin: Unknown data source type: %i",
+ ds->ds[i].type);
+ sfree (rates);
+ return (-1);
+ }
+ } /* for ds->ds_num */
+
+#undef BUFFER_ADD
+
+ sfree (rates);
+ return (0);
+} /* }}} int format_values */
+
int parse_identifier (char *str, char **ret_host,
char **ret_plugin, char **ret_plugin_instance,
char **ret_type, char **ret_type_instance)
#define FORMAT_VL(ret, ret_len, vl) \
format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
(vl)->type, (vl)->type_instance)
+int format_values (char *ret, size_t ret_len,
+ const data_set_t *ds, const value_list_t *vl,
+ _Bool store_rates);
int parse_identifier (char *str, char **ret_host,
char **ret_plugin, char **ret_plugin_instance,
return (0);
} /* int handle_putval */
+int create_putval (char *ret, size_t ret_len, /* {{{ */
+ const data_set_t *ds, const value_list_t *vl)
+{
+ char buffer_ident[6 * DATA_MAX_NAME_LEN];
+ char buffer_values[1024];
+ int status;
+
+ status = FORMAT_VL (buffer_ident, sizeof (buffer_ident), vl);
+ if (status != 0)
+ return (status);
+ escape_string (buffer_ident, sizeof (buffer_ident));
+
+ status = format_values (buffer_values, sizeof (buffer_values),
+ ds, vl, /* store rates = */ 0);
+ if (status != 0)
+ return (status);
+ escape_string (buffer_values, sizeof (buffer_values));
+
+ ssnprintf (ret, ret_len,
+ "PUTVAL %s interval=%i %s",
+ buffer_ident,
+ (vl->interval > 0) ? vl->interval : interval_g,
+ buffer_values);
+
+ return (0);
+} /* }}} int create_putval */
#include <stdio.h>
+#include "plugin.h"
+
int handle_putval (FILE *fh, char *buffer);
+int create_putval (char *ret, size_t ret_len,
+ const data_set_t *ds, const value_list_t *vl);
+
#endif /* UTILS_CMD_PUTVAL_H */
sfree (cb);
} /* }}} void wh_callback_free */
-static int wh_value_list_to_string (char *buffer, /* {{{ */
- size_t buffer_size,
- const data_set_t *ds, const value_list_t *vl,
- wh_callback_t *cb)
-{
- size_t offset = 0;
- int status;
- int i;
- gauge_t *rates = NULL;
-
- assert (0 == strcmp (ds->type, vl->type));
-
- memset (buffer, 0, buffer_size);
-
-#define BUFFER_ADD(...) do { \
- status = ssnprintf (buffer + offset, buffer_size - offset, \
- __VA_ARGS__); \
- if (status < 1) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else if (((size_t) status) >= (buffer_size - offset)) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else \
- offset += ((size_t) status); \
-} while (0)
-
- BUFFER_ADD ("%lu", (unsigned long) vl->time);
-
- for (i = 0; i < ds->ds_num; i++)
- {
- if (ds->ds[i].type == DS_TYPE_GAUGE)
- BUFFER_ADD (":%f", vl->values[i].gauge);
- else if (cb->store_rates)
- {
- if (rates == NULL)
- rates = uc_get_rate (ds, vl);
- if (rates == NULL)
- {
- WARNING ("write_http plugin: "
- "uc_get_rate failed.");
- return (-1);
- }
- BUFFER_ADD (":%g", rates[i]);
- }
- else if (ds->ds[i].type == DS_TYPE_COUNTER)
- BUFFER_ADD (":%llu", vl->values[i].counter);
- else if (ds->ds[i].type == DS_TYPE_DERIVE)
- BUFFER_ADD (":%"PRIi64, vl->values[i].derive);
- else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
- BUFFER_ADD (":%"PRIu64, vl->values[i].absolute);
- else
- {
- ERROR ("write_http plugin: Unknown data source type: %i",
- ds->ds[i].type);
- sfree (rates);
- return (-1);
- }
- } /* for ds->ds_num */
-
-#undef BUFFER_ADD
-
- sfree (rates);
- return (0);
-} /* }}} int wh_value_list_to_string */
-
static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{{ */
wh_callback_t *cb)
{
/* Convert the values to an ASCII representation and put that into
* `values'. */
- status = wh_value_list_to_string (values, sizeof (values), ds, vl, cb);
+ status = format_values (values, sizeof (values), ds, vl, cb->store_rates);
if (status != 0) {
ERROR ("write_http plugin: error with "
"wh_value_list_to_string");