Merge branch 'master' into sp/amqp
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 6 Aug 2010 13:02:57 +0000 (15:02 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 6 Aug 2010 13:02:57 +0000 (15:02 +0200)
src/Makefile.am
src/collectd-flush.c [new file with mode: 0644]
src/collectd-flush.pod [new file with mode: 0644]
src/common.c
src/common.h
src/utils_cmd_putval.c
src/utils_cmd_putval.h
src/write_http.c

index 723ca7b..222d916 100644 (file)
@@ -21,7 +21,7 @@ AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
 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 \
@@ -105,6 +105,19 @@ endif
 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 = 
diff --git a/src/collectd-flush.c b/src/collectd-flush.c
new file mode 100644 (file)
index 0000000..71457e4
--- /dev/null
@@ -0,0 +1,176 @@
+/**
+ * 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);
+}
diff --git a/src/collectd-flush.pod b/src/collectd-flush.pod
new file mode 100644 (file)
index 0000000..cf7b178
--- /dev/null
@@ -0,0 +1,71 @@
+=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
index 2598036..08653dc 100644 (file)
@@ -29,6 +29,7 @@
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
+#include "utils_cache.h"
 
 #if HAVE_PTHREAD_H
 # include <pthread.h>
@@ -802,6 +803,75 @@ int format_name (char *ret, int ret_len,
        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)
index 229f709..63ecca3 100644 (file)
@@ -258,6 +258,9 @@ int format_name (char *ret, int ret_len,
 #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,
index ec2b5f8..15cd939 100644 (file)
@@ -227,3 +227,29 @@ int handle_putval (FILE *fh, char *buffer)
        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 */
index 8460b13..9c92fd3 100644 (file)
 
 #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 */
index ab8757e..bac8e98 100644 (file)
@@ -270,76 +270,6 @@ static void wh_callback_free (void *data) /* {{{ */
         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)
 {
@@ -366,7 +296,7 @@ static int wh_write_command (const data_set_t *ds, const value_list_t *vl, /* {{
 
         /* 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");