collectdctl: Added support for the ‘putval’ command.
authorSebastian Harl <sh@tokkee.org>
Mon, 9 Aug 2010 19:54:09 +0000 (21:54 +0200)
committerSebastian Harl <sh@tokkee.org>
Mon, 9 Aug 2010 19:54:09 +0000 (21:54 +0200)
src/collectdctl.c
src/collectdctl.pod

index 68b1675..adf45c9 100644 (file)
@@ -59,6 +59,7 @@ static void exit_usage (const char *name, int status) {
       " * getval <identifier>\n"
       " * flush [timeout=<seconds>] [plugin=<name>] [identifier=<id>]\n"
       " * listval\n"
+      " * putval <identifier> [interval=<seconds>] <value-list(s)>\n"
 
       "\nIdentifiers:\n\n"
 
@@ -355,6 +356,156 @@ static int listval (lcc_connection_t *c, int argc, char **argv)
 #undef BAIL_OUT
 } /* listval */
 
+static int putval (lcc_connection_t *c, int argc, char **argv)
+{
+  lcc_value_list_t vl = LCC_VALUE_LIST_INIT;
+
+  /* 64 ought to be enough for anybody ;-) */
+  value_t values[64];
+  int     values_types[64];
+  size_t  values_len = 0;
+
+  int status;
+  int i;
+
+  assert (strcasecmp (argv[0], "putval") == 0);
+
+  if (argc < 3) {
+    fprintf (stderr, "ERROR: putval: Missing identifier "
+        "and/or value list.\n");
+    return (-1);
+  }
+
+  vl.values       = values;
+  vl.values_types = values_types;
+
+  status = parse_identifier (c, argv[1], &vl.identifier);
+  if (status != 0)
+    return (status);
+
+  for (i = 2; i < argc; ++i) {
+    char *tmp;
+
+    tmp = strchr (argv[i], (int)'=');
+
+    if (tmp != NULL) { /* option */
+      char *key   = argv[i];
+      char *value = tmp;
+
+      *value = '\0';
+      ++value;
+
+      if (strcasecmp (key, "interval") == 0) {
+        char *endptr;
+
+        vl.interval = strtol (value, &endptr, 0);
+
+        if (endptr == value) {
+          fprintf (stderr, "ERROR: Failed to parse interval as number: %s.\n",
+              value);
+          return (-1);
+        }
+        else if ((endptr != NULL) && (*endptr != '\0')) {
+          fprintf (stderr, "WARNING: Ignoring trailing garbage after "
+              "interval: %s.\n", endptr);
+        }
+      }
+      else {
+        fprintf (stderr, "ERROR: putval: Unknown option `%s'.\n", key);
+        return (-1);
+      }
+    }
+    else { /* value list */
+      char *value;
+
+      tmp = strchr (argv[i], (int)':');
+
+      if (tmp == NULL) {
+        fprintf (stderr, "ERROR: putval: Invalid value list: %s.\n",
+            argv[i]);
+        return (-1);
+      }
+
+      *tmp = '\0';
+      ++tmp;
+
+      if (strcasecmp (argv[i], "N") == 0) {
+        vl.time = 0;
+      }
+      else {
+        char *endptr;
+
+        vl.time = strtol (argv[i], &endptr, 0);
+
+        if (endptr == value) {
+          fprintf (stderr, "ERROR: Failed to parse time as number: %s.\n",
+              argv[i]);
+          return (-1);
+        }
+        else if ((endptr != NULL) && (*endptr != '\0')) {
+          fprintf (stderr, "ERROR: Garbage after time: %s.\n", endptr);
+          return (-1);
+        }
+      }
+
+      values_len = 0;
+      value = tmp;
+      while (value != 0) {
+        char *dot, *endptr;
+
+        tmp = strchr (argv[i], (int)':');
+
+        if (tmp != NULL) {
+          *tmp = '\0';
+          ++tmp;
+        }
+
+        /* This is a bit of a hack, but parsing types.db just does not make
+         * much sense imho -- the server might have different types defined
+         * anyway. Also, lcc uses the type information for formatting the
+         * number only, so the real meaning does not matter. -tokkee */
+        dot = strchr (value, (int)'.');
+        if (dot) { /* floating point value */
+          values[values_len].gauge = strtod (value, &endptr);
+          values_types[values_len] = LCC_TYPE_GAUGE;
+        }
+        else { /* integer */
+          values[values_len].counter = strtol (value, &endptr, 0);
+          values_types[values_len] = LCC_TYPE_COUNTER;
+        }
+        ++values_len;
+
+        if (endptr == value) {
+          fprintf (stderr, "ERROR: Failed to parse value as number: %s.\n",
+              argv[i]);
+          return (-1);
+        }
+        else if ((endptr != NULL) && (*endptr != '\0')) {
+          fprintf (stderr, "ERROR: Garbage after value: %s.\n", endptr);
+          return (-1);
+        }
+
+        value = tmp;
+      }
+
+      assert (values_len >= 1);
+      vl.values_len = values_len;
+
+      status = lcc_putval (c, &vl);
+      if (status != 0) {
+        fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+        return (-1);
+      }
+    }
+  }
+
+  if (values_len == 0) {
+    fprintf (stderr, "ERROR: putval: Missing value list(s).\n");
+    return (-1);
+  }
+  return (0);
+} /* putval */
+
 int main (int argc, char **argv) {
   char address[1024] = "unix:"DEFAULT_SOCK;
 
@@ -402,6 +553,8 @@ int main (int argc, char **argv) {
     status = flush (c, argc - optind, argv + optind);
   else if (strcasecmp (argv[optind], "listval") == 0)
     status = listval (c, argc - optind, argv + optind);
+  else if (strcasecmp (argv[optind], "putval") == 0)
+    status = putval (c, argc - optind, argv + optind);
   else {
     fprintf (stderr, "%s: invalid command: %s\n", argv[0], argv[optind]);
     return (1);
index aff67ef..65d4e05 100644 (file)
@@ -83,6 +83,18 @@ C<unixsock> plugin. Each value is printed on its own line. I.E<nbsp>e., this
 command returns a list of valid identifiers that may be used with the other
 commands.
 
+=item B<putval> I<E<lt>identifierE<gt>> [B<interval=>I<E<lt>secondsE<gt>>]
+I<E<lt>value-list(s)E<gt>>
+
+Submit one or more values (identified by I<E<lt>identifierE<gt>>, see below)
+to the daemon which will then dispatch them to the write plugins. B<interval>
+specifies the interval (in seconds) used to collect the values following that
+option. It defaults to the default of the running collectd instance receiving
+the data. Multiple I<E<lt>value-list(s)E<gt>> (see below) may be specified.
+Each of them will be submitted to the daemon. The values have to match the
+data-set definition specified by the type as given in the identifier (see
+L<types.db(5)> for details).
+
 =back
 
 =head1 IDENTIFIERS
@@ -100,6 +112,16 @@ Hostname defaults to the local (non-fully qualified) hostname if omitted. No
 error is returned if the specified identifier does not exist (this is a
 limitation in the C<libcollectdclient> library).
 
+=head1 VALUE-LIST
+
+A value list describes one data-set as handled by collectd. It is a colon
+(C<:>) separated list of the time and the values. Each value is either given
+as an integer if the data-type is a counter, or as a double if the data-type
+is a gauge value. The number of values and the data-types have to match the
+type specified in the identifier (see L<types.db(5)> for details). The time is
+specified as epoch (i.E<nbsp>e., standard UNIX time) or as a literal C<N>
+which will be interpreted as now.
+
 =head1 EXAMPLES
 
 =over 4
@@ -120,9 +142,10 @@ collectd instance.
 
 =head1 SEE ALSO
 
-L<collectd(1)>
-L<collectd.conf(5)>
-L<collectd-unixsock(5)>
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<collectd-unixsock(5)>,
+L<types.db(5)>
 
 =head1 AUTHOR