summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 70e16e5)
raw | patch | inline | side by side (parent: 70e16e5)
author | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Wed, 16 Mar 2011 21:51:35 +0000 (22:51 +0100) | ||
committer | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Wed, 16 Mar 2011 21:53:42 +0000 (22:53 +0100) |
src/collectd-unixsock.pod | patch | blob | history | |
src/utils_cmd_listval.c | patch | blob | history | |
src/utils_parse_option.c | patch | blob | history |
index 83802a14f7a0ba2576c94f0b223b1ddc07b54f67..265c41c783e8d52f8a083ac4510153cbe00bc9ee 100644 (file)
<- | 1 Value found
<- | value=1.260000e+00
-=item B<LISTVAL>
+=item B<LISTVAL> [I<OptionList>]
Returns a list of the values available in the value cache together with the
time of the last update, so that querying applications can issue a B<GETVAL>
<- | 1182204284 myhost/cpu-0/cpu-user
...
+Valid options are B<host>, B<plugin>, B<plugin_instance>, B<type> and
+B<type_instance>. Each option takes a regular expression as its argument. If at
+least one regular expression is supplied, only values where each appropriate
+part of the identifier satisfies the given regular expression are returned.
+
+Example:
+ -> | LISTVAL plugin_instance="^$"
+ <- | 5 Matching values
+ <- | 1300311250.802 myhost/load/load
+ <- | 1300311250.802 myhost/memory/memory-buffered
+ <- | 1300311250.802 myhost/memory/memory-cached
+ <- | 1300311250.804 myhost/memory/memory-free
+ <- | 1300311250.802 myhost/memory/memory-used
+
+Regular expressions follow the I<Extended Regular Expression> syntax (ERE)
+described in L<regex(7)> and will match case-sensitive. It is recommended to
+enclose the regular expression in double quotes. Please note that you will
+need to escape the backslash and double quote characters in this case. To
+request all values from hosts with the German top level domain ".de", for
+example, use:
+ LISTVAL host="\\.de$"
+
=item B<PUTVAL> I<Identifier> [I<OptionList>] I<Valuelist>
Submits one or more values (identified by I<Identifier>, see below) to the
index ef66af56c408d8ae1ab300386875c7d57fe93189..078a5275a88fa8d39af3095ebd6c312f539d2b1a 100644 (file)
--- a/src/utils_cmd_listval.c
+++ b/src/utils_cmd_listval.c
/**
* collectd - src/utils_cms_listval.c
- * Copyright (C) 2008 Florian octo Forster
+ * Copyright (C) 2008-2011 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
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Author:
- * Florian octo Forster <octo at verplant.org>
+ * Florian "octo" Forster <octo at collectd.org>
**/
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include <regex.h>
+
#include "utils_cmd_listval.h"
#include "utils_cache.h"
#include "utils_parse_option.h"
-#define free_everything_and_return(status) do { \
+/* Not very nice, but oh so handy ... */
+#define FREE_EVERYTHING_AND_RETURN(status) do { \
size_t j; \
for (j = 0; j < number; j++) { \
sfree(names[j]); \
} \
sfree(names); \
sfree(times); \
+ if (have_re_host) { regfree (&re_host); } \
+ if (have_re_plugin) { regfree (&re_plugin); } \
+ if (have_re_plugin_instance) { regfree (&re_plugin_instance); } \
+ if (have_re_type) { regfree (&re_type); } \
+ if (have_re_type_instance) { regfree (&re_type_instance); } \
return (status); \
} while (0)
if (fprintf (fh, __VA_ARGS__) < 0) { \
char errbuf[1024]; \
WARNING ("handle_listval: failed to write to socket #%i: %s", \
- fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
- free_everything_and_return (-1); \
+ fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf))); \
+ FREE_EVERYTHING_AND_RETURN (-1); \
}
int handle_listval (FILE *fh, char *buffer)
size_t i;
int status;
+ regex_t re_host;
+ regex_t re_plugin;
+ regex_t re_plugin_instance;
+ regex_t re_type;
+ regex_t re_type_instance;
+ _Bool have_re_host = 0;
+ _Bool have_re_plugin = 0;
+ _Bool have_re_plugin_instance = 0;
+ _Bool have_re_type = 0;
+ _Bool have_re_type_instance = 0;
+
DEBUG ("utils_cmd_listval: handle_listval (fh = %p, buffer = %s);",
(void *) fh, buffer);
if (status != 0)
{
print_to_socket (fh, "-1 Cannot parse command.\n");
- free_everything_and_return (-1);
+ FREE_EVERYTHING_AND_RETURN (-1);
}
assert (command != NULL);
if (strcasecmp ("LISTVAL", command) != 0)
{
print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
- free_everything_and_return (-1);
+ FREE_EVERYTHING_AND_RETURN (-1);
}
- if (*buffer != 0)
+ /* Parse the options which may still be contained in the buffer. Valid
+ * options are "host", "plugin", "plugin_instance", "type" and
+ * "type_instance"; each option takes a regular expression as argument which
+ * is used to filter the returned identifiers. */
+ while (*buffer != 0)
{
- print_to_socket (fh, "-1 Garbage after end of command: %s\n", buffer);
- free_everything_and_return (-1);
- }
+ char *opt_key;
+ char *opt_value;
+ regex_t *re;
+ _Bool *have_re;
+
+ opt_key = NULL;
+ opt_value = NULL;
+ status = parse_option (&buffer, &opt_key, &opt_value);
+ if (status != 0)
+ {
+ print_to_socket (fh, "-1 Parsing options failed.\n");
+ FREE_EVERYTHING_AND_RETURN (-1);
+ }
+ if (strcasecmp ("host", opt_key) == 0)
+ {
+ re = &re_host;
+ have_re = &have_re_host;
+ }
+ else if (strcasecmp ("plugin", opt_key) == 0)
+ {
+ re = &re_plugin;
+ have_re = &have_re_plugin;
+ }
+ else if (strcasecmp ("plugin_instance", opt_key) == 0)
+ {
+ re = &re_plugin_instance;
+ have_re = &have_re_plugin_instance;
+ }
+ else if (strcasecmp ("type", opt_key) == 0)
+ {
+ re = &re_type;
+ have_re = &have_re_type;
+ }
+ else if (strcasecmp ("type_instance", opt_key) == 0)
+ {
+ re = &re_type_instance;
+ have_re = &have_re_type_instance;
+ }
+ else
+ {
+ print_to_socket (fh, "-1 Unknown option: %s\n", opt_key);
+ FREE_EVERYTHING_AND_RETURN (-1);
+ }
+
+ /* Free a previous regular expression */
+ if (*have_re)
+ {
+ NOTICE ("listval command: More than one match for part \"%s\". "
+ "Only the last regular expression will be used to search "
+ "for matching value lists!",
+ opt_key);
+ regfree (re);
+ *have_re = 0;
+ }
+
+ /* Compile the regular expression. */
+ status = regcomp (re, opt_value, REG_EXTENDED | REG_NOSUB);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ regerror (status, re, errbuf, sizeof (errbuf));
+ errbuf[sizeof (errbuf) - 1] = 0;
+ print_to_socket (fh, "-1 Compiling %s regex failed: %s\n",
+ opt_key, errbuf);
+ FREE_EVERYTHING_AND_RETURN (-1);
+ }
+ *have_re = 1;
+ } /* while (*buffer != 0) */
+
+ /* Get a list of values from the cache. */
status = uc_get_names (&names, ×, &number);
if (status != 0)
{
DEBUG ("command listval: uc_get_names failed with status %i", status);
print_to_socket (fh, "-1 uc_get_names failed.\n");
- free_everything_and_return (-1);
+ FREE_EVERYTHING_AND_RETURN (-1);
+ }
+
+ /* If no regex has been specified, take the easy way out. This will avoid a
+ * lot of pointless if-blocks. */
+ if (!have_re_host
+ && !have_re_plugin
+ && !have_re_plugin_instance
+ && !have_re_type
+ && !have_re_type_instance)
+ {
+ print_to_socket (fh, "%i Value%s found\n",
+ (int) number, (number == 1) ? "" : "s");
+ for (i = 0; i < number; i++)
+ print_to_socket (fh, "%.3f %s\n", CDTIME_T_TO_DOUBLE (times[i]),
+ names[i]);
}
+ else /* At least one regular expression is present. */
+ {
+ char *matching_names[number];
+ cdtime_t matching_times[number];
+ size_t matching_number = 0;
+
+ /* We need to figure out how many values we're going to return for the
+ * status line first. We save all matched values in the above arrays to
+ * avoid doing the matching twice. */
+ for (i = 0; i < number; i++)
+ {
+ value_list_t vl = VALUE_LIST_INIT;
- print_to_socket (fh, "%i Value%s found\n",
- (int) number, (number == 1) ? "" : "s");
- for (i = 0; i < number; i++)
- print_to_socket (fh, "%.3f %s\n", CDTIME_T_TO_DOUBLE (times[i]),
- names[i]);
+ status = parse_identifier_vl (names[i], &vl);
+ if (status != 0)
+ continue;
+
+ /* If a regex exists and doesn't match, ignore this value and continue
+ * with the next one. */
+ if (have_re_host && (regexec (&re_host,
+ /* string = */ vl.host,
+ /* nmatch = */ 0,
+ /* pmatch = */ NULL,
+ /* flags = */ 0) == REG_NOMATCH))
+ continue;
+ if (have_re_plugin && (regexec (&re_plugin,
+ /* string = */ vl.plugin,
+ /* nmatch = */ 0,
+ /* pmatch = */ NULL,
+ /* flags = */ 0) == REG_NOMATCH))
+ continue;
+ if (have_re_plugin_instance && (regexec (&re_plugin_instance,
+ /* string = */ vl.plugin_instance,
+ /* nmatch = */ 0,
+ /* pmatch = */ NULL,
+ /* flags = */ 0) == REG_NOMATCH))
+ continue;
+ if (have_re_type && (regexec (&re_type,
+ /* string = */ vl.type,
+ /* nmatch = */ 0,
+ /* pmatch = */ NULL,
+ /* flags = */ 0) == REG_NOMATCH))
+ continue;
+ if (have_re_type_instance && (regexec (&re_type_instance,
+ /* string = */ vl.type_instance,
+ /* nmatch = */ 0,
+ /* pmatch = */ NULL,
+ /* flags = */ 0) == REG_NOMATCH))
+ continue;
+
+ matching_names[matching_number] = names[i];
+ matching_times[matching_number] = times[i];
+ matching_number++;
+ }
+
+ print_to_socket (fh, "%zu Matching value%s\n",
+ matching_number, (matching_number == 1) ? "" : "s");
+ for (i = 0; i < matching_number; i++)
+ print_to_socket (fh, "%.3f %s\n",
+ CDTIME_T_TO_DOUBLE (matching_times[i]),
+ matching_names[i]);
+ }
- free_everything_and_return (0);
+ FREE_EVERYTHING_AND_RETURN (0);
} /* int handle_listval */
-/* vim: set sw=2 sts=2 ts=8 : */
+/* vim: set sw=2 sts=2 ts=8 et : */
index 2168cd1af3d624801146905b853adb0c92db3d7b..6bb9d1f293d94eaeb9747315bae9da6085220339 100644 (file)
--- a/src/utils_parse_option.c
+++ b/src/utils_parse_option.c
/* Look for the equal sign */
buffer = key;
- while (isalnum ((int) *buffer))
+ while (isalnum ((int) *buffer) || (*buffer == '_'))
buffer++;
if ((*buffer != '=') || (buffer == key))
return (1);