/*
* Global variables
*/
-static lcc_identifier_t *selector;
+/* Selection */
+static const char *re_host = NULL;
+static const char *re_plugin = NULL;
+static const char *re_plugin_instance = NULL;
+static const char *re_type = NULL;
+static const char *re_type_instance = NULL;
+/* Grouping */
+static uint16_t grouping = 0;
+
+/* Aggregation */
static int *aggregation_types = NULL;
static size_t aggregation_types_num = 0;
return (0);
} /* }}} int aggregation_type_add */
-static int group_name_from_ident (const lcc_identifier_t *selector, /* {{{ */
- const lcc_identifier_t *identifier,
+static int group_name_from_ident (const lcc_identifier_t *identifier, /* {{{ */
char *buffer, size_t buffer_size)
{
- if ((selector == NULL)
- || (identifier == NULL)
+ if ((identifier == NULL)
|| (buffer == NULL) || (buffer_size < 2))
return (EINVAL);
- /* Check if there is no "grouping" wildcard. If there isn't, return "all" as
- * the default value. */
- if ((strcmp ("+", selector->host) != 0)
- && (strcmp ("+", selector->plugin) != 0)
- && (strcmp ("+", selector->plugin_instance) != 0)
- && (strcmp ("+", selector->type) != 0)
- && (strcmp ("+", selector->type_instance) != 0))
+ if (grouping == 0)
{
- /* There is no wildcard at all => use the identifier. */
- if ((strcmp ("*", selector->host) != 0)
- && (strcmp ("*", selector->plugin) != 0)
- && (strcmp ("*", selector->plugin_instance) != 0)
- && (strcmp ("*", selector->type) != 0)
- && (strcmp ("*", selector->type_instance) != 0))
- lcc_identifier_to_string (/* connection = */ NULL,
- buffer, buffer_size, identifier);
- else /* there's wildcards but no grouping */
- strncpy (buffer, "all", buffer_size);
+ lcc_identifier_to_string (/* connection = */ NULL,
+ buffer, buffer_size, identifier);
buffer[buffer_size - 1] = 0;
return (0);
}
memset (buffer, 0, buffer_size);
-#define COPY_FIELD(field) do { \
- if (strcmp ("+", selector->field) != 0) \
- break; \
- if (buffer[0] == 0) \
- strncpy (buffer, identifier->field, buffer_size); \
- else \
+#define COPY_FIELD(field,index) do { \
+ if ((grouping & (1 << index)) != 0) \
{ \
- char tmp[buffer_size]; \
- snprintf (tmp, buffer_size, "%s/%s", buffer, identifier->field); \
- memcpy (buffer, tmp, buffer_size); \
+ if (buffer[0] == 0) \
+ strncpy (buffer, identifier->field, buffer_size); \
+ else \
+ { \
+ char tmp[buffer_size]; \
+ snprintf (tmp, buffer_size, "%s/%s", buffer, identifier->field); \
+ memcpy (buffer, tmp, buffer_size); \
+ } \
+ buffer[buffer_size - 1] = 0; \
} \
- buffer[buffer_size - 1] = 0; \
} while (0)
- COPY_FIELD (host);
- COPY_FIELD (plugin);
- COPY_FIELD (plugin_instance);
- COPY_FIELD (type);
- COPY_FIELD (type_instance);
+ COPY_FIELD (host, 0);
+ COPY_FIELD (plugin, 1);
+ COPY_FIELD (plugin_instance, 2);
+ COPY_FIELD (type, 3);
+ COPY_FIELD (type_instance, 4);
#undef COPY_FIELD
return (0);
} /* }}} int group_name_from_ident */
-static _Bool ident_matches_selector (const lcc_identifier_t *selector, /* {{{ */
- const lcc_identifier_t *identifier)
-{
- if ((selector == NULL) || (identifier == NULL))
- return (0);
-
- if ((strcmp (identifier->host, selector->host) != 0)
- && (strcmp ("*", selector->host) != 0)
- && (strcmp ("+", selector->host) != 0))
- return (0);
-
- if ((strcmp (identifier->plugin, selector->plugin) != 0)
- && (strcmp ("*", selector->plugin) != 0)
- && (strcmp ("+", selector->plugin) != 0))
- return (0);
-
- if ((strcmp (identifier->plugin_instance, selector->plugin_instance) != 0)
- && (strcmp ("*", selector->plugin_instance) != 0)
- && (strcmp ("+", selector->plugin_instance) != 0))
- return (0);
-
- if ((strcmp (identifier->type, selector->type) != 0)
- && (strcmp ("*", selector->type) != 0)
- && (strcmp ("+", selector->type) != 0))
- return (0);
-
- if ((strcmp (identifier->type_instance, selector->type_instance) != 0)
- && (strcmp ("*", selector->type_instance) != 0)
- && (strcmp ("+", selector->type_instance) != 0))
- return (0);
-
- return (1);
-} /* }}} _Bool ident_matches_selector */
-
static aggregation_group_t *aggregation_get_group ( const lcc_identifier_t *identifier) /* {{{ */
{
char group_name[LCC_NAME_LEN];
if (identifier == NULL)
return (NULL);
- status = group_name_from_ident (selector, identifier,
+ status = group_name_from_ident (identifier,
group_name, sizeof (group_name));
if (status != 0)
return (NULL);
int status;
size_t i;
- status = lcc_listval (c, &ret_ident, &ret_ident_num);
+ status = lcc_listval_with_selection (c,
+ re_host,
+ re_plugin,
+ re_plugin_instance,
+ re_type,
+ re_type_instance,
+ &ret_ident, &ret_ident_num);
if (status != 0)
{
- fprintf (stderr, "ERROR: lcc_listval: %s\n", lcc_strerror (c));
+ fprintf (stderr, "ERROR: lcc_listval_with_selection: %s\n",
+ lcc_strerror (c));
return (-1);
}
assert ((ret_ident != NULL) || (ret_ident_num == 0));
size_t ret_values_num = 0;
gauge_t *ret_values = NULL;
- if (!ident_matches_selector (selector, ret_ident + i))
- continue;
-
status = lcc_getval (c, ret_ident + i,
&ret_values_num, &ret_values, /* values_names = */ NULL);
if (status != 0)
for (j = 0; j < aggregation_types_num; j++)
printf ("------------+");
+ if (aggregation_types_num == 0)
+ printf ("------------+");
printf ("\n");
printf ("! %-*s !", name_len_max, "Name");
for (i = 0; i < aggregation_types_num; i++)
printf (" %10s !", aggr_type_to_string (aggregation_types[i]));
+ if (aggregation_types_num == 0)
+ printf (" %10s !", "Value");
printf ("\n");
print_horizontal_line (name_len_max);
printf (" %10g !", value);
}
+ if (aggregation_types_num == 0)
+ {
+ /* g->num may be zero if the value is NAN. */
+ assert (g->num < 2);
+ printf (" %10g !", g->min);
+ }
printf ("\n");
}
__attribute__((noreturn))
static void exit_usage (int status) /* {{{ */
{
- printf ("Usage: collectdctl show <selector> <aggregation> "
- "[<aggregation> ...]\n"
+ printf ("Usage: collectdctl show [<Selection>] [<Aggregation> <Grouping>]\n"
+ "\n"
+ "Selection:\n"
"\n"
- "Selector:\n"
- " A selector is an identifier, where each part may be replaced "
- "with either\n"
- " \"*\" or \"+\".\n"
+ " host=<regex> Regex for the host name.\n"
+ " plugin=<regex> Regex for the plugin.\n"
+ " plugin_instance=<regex> Regex for the plugin instance.\n"
+ " type=<regex> Regex for the type.\n"
+ " type_instance=<regex> Regex for the type instance.\n"
"\n"
"Aggregation:\n"
- " count\n"
- " min\n"
- " max\n"
- " avg\n"
+ "\n"
+ " aggregate=<aggr>[,<aggr>[...]] List of aggregations to use when\n"
+ " combining multiple values.\n"
+ " Valid aggregations are:\n"
+ " count, min, max, avg, sum, stddev\n"
+ "\n"
+ "Grouping:\n"
+ "\n"
+ " group=<field>[,<field>[...]] List of fields to group by.\n"
+ " Valid fields are:\n"
+ " host, plugin, plugin_instance,\n"
+ " type, type_instance\n"
"\n");
exit (status);
} /* }}} void exit_usage */
+static int parse_aggregate (const char *aggr) /* {{{ */
+{
+ char *aggr_copy;
+ char *dummy;
+ char *a;
+
+ aggr_copy = strdup (aggr);
+ if (aggr_copy == NULL)
+ return (ENOMEM);
+
+ free (aggregation_types);
+ aggregation_types = NULL;
+ aggregation_types_num = 0;
+
+ dummy = aggr_copy;
+ while ((a = strtok (dummy, ",")) != NULL)
+ {
+ int status;
+
+ dummy = NULL;
+
+ status = aggregation_type_add (a);
+ if (status != 0)
+ exit_usage (EXIT_FAILURE);
+ } /* while (strtok) */
+
+ free (aggr_copy);
+
+ return (0);
+} /* }}} int parse_group */
+
+static int parse_group (const char *group) /* {{{ */
+{
+ char *group_copy;
+ char *dummy;
+ char *g;
+
+ group_copy = strdup (group);
+ if (group_copy == NULL)
+ return (ENOMEM);
+
+ grouping = 0;
+
+ dummy = group_copy;
+ while ((g = strtok (dummy, ",")) != NULL)
+ {
+ int pos = 0;
+
+ dummy = NULL;
+
+ if (strcasecmp ("host", g) == 0)
+ pos = 0;
+ else if (strcasecmp ("plugin", g) == 0)
+ pos = 1;
+ else if ((strcasecmp ("plugin_instance", g) == 0)
+ || (strcasecmp ("plugininstance", g) == 0)
+ || (strcasecmp ("pinst", g) == 0))
+ pos = 2;
+ else if (strcasecmp ("type", g) == 0)
+ pos = 3;
+ else if ((strcasecmp ("type_instance", g) == 0)
+ || (strcasecmp ("typeinstance", g) == 0)
+ || (strcasecmp ("tinst", g) == 0))
+ pos = 4;
+ else
+ {
+ fprintf (stderr, "Unknown grouping field: \"%s\"\n", g);
+ exit_usage (EXIT_FAILURE);
+ }
+
+ grouping |= 1 << pos;
+ } /* while (strtok) */
+
+ free (group_copy);
+
+ return (0);
+} /* }}} int parse_group */
+
+static int parse_arg (const char *arg) /* {{{ */
+{
+ if (arg == NULL)
+ return (EINVAL);
+ else if (strncasecmp ("host=", arg, strlen ("host=")) == 0)
+ re_host = arg + strlen ("host=");
+ else if (strncasecmp ("plugin=", arg, strlen ("plugin=")) == 0)
+ re_plugin = arg + strlen ("plugin=");
+ else if (strncasecmp ("plugin_instance=", arg, strlen ("plugin_instance=")) == 0)
+ re_plugin_instance = arg + strlen ("plugin_instance=");
+ else if (strncasecmp ("type=", arg, strlen ("type=")) == 0)
+ re_type = arg + strlen ("type=");
+ else if (strncasecmp ("type_instance=", arg, strlen ("type_instance=")) == 0)
+ re_type_instance = arg + strlen ("type_instance=");
+
+ /* Grouping */
+ else if (strncasecmp ("group=", arg, strlen ("group=")) == 0)
+ return (parse_group (arg + strlen ("group=")));
+
+ /* Aggregations */
+ else if (strncasecmp ("aggregate=", arg, strlen ("aggregate=")) == 0)
+ return (parse_aggregate (arg + strlen ("aggregate=")));
+
+ /* Some alternative spellings to make it easier to guess a working argument
+ * name: */
+ else if (strncasecmp ("hostname=", arg, strlen ("hostname=")) == 0)
+ re_host = arg + strlen ("hostname=");
+ else if (strncasecmp ("plugininstance=", arg, strlen ("plugininstance=")) == 0)
+ re_plugin_instance = arg + strlen ("plugininstance=");
+ else if (strncasecmp ("typeinstance=", arg, strlen ("typeinstance=")) == 0)
+ re_type_instance = arg + strlen ("typeinstance=");
+ else if (strncasecmp ("pinst=", arg, strlen ("pinst=")) == 0)
+ re_plugin_instance = arg + strlen ("pinst=");
+ else if (strncasecmp ("tinst=", arg, strlen ("tinst=")) == 0)
+ re_type_instance = arg + strlen ("tinst=");
+ else if (strncasecmp ("aggr=", arg, strlen ("aggr=")) == 0)
+ return (parse_aggregate (arg + strlen ("aggr=")));
+
+ /* Don't know what that is ... */
+ else
+ {
+ fprintf (stderr, "Unknown argument: \"%s\"\n", arg);
+ exit_usage (EXIT_FAILURE);
+ }
+
+ return (0);
+} /* }}} int parse_arg */
+
int show (lcc_connection_t *c, int argc, char **argv) /* {{{ */
{
- lcc_identifier_t tmp;
int status;
int i;
size_t j;
- if (argc < 3)
- exit_usage (EXIT_FAILURE);
-
- memset (&tmp, 0, sizeof (tmp));
- status = lcc_string_to_identifier (c, &tmp, argv[1]);
- if (status != 0)
- return (status);
- selector = &tmp;
+ for (i = 1; i < argc; i++)
+ {
+ status = parse_arg (argv[i]);
+ /* parse_arg calls exit_usage() on error. */
+ assert (status == 0);
+ }
- for (i = 2; i < argc; i++)
- aggregation_type_add (argv[i]);
+ if ((grouping == 0) && (aggregation_types_num > 0))
+ {
+ fprintf (stderr, "One or more aggregations were specified, but no fields "
+ "were selected for grouping values. Please use the ""\"group=...\" "
+ "option.\n");
+ exit_usage (EXIT_FAILURE);
+ }
+ else if ((grouping != 0) && (aggregation_types_num == 0))
+ {
+ fprintf (stderr, "One or more fields were specified for grouping but no "
+ "aggregation was given. Please use the \"aggregate=...\" option.\n");
+ exit_usage (EXIT_FAILURE);
+ }
status = read_data (c);
if (status != 0)
data-set definition specified by the type as given in the identifier (see
L<types.db(5)> for details).
-=item B<show> I<E<lt>selectorE<gt>> I<E<lt>aggregationE<gt>> [I<E<lt>aggregationE<gt>> ...]
+=item B<show> [I<E<lt>SelectionE<gt>>] [I<E<lt>AggregationE<gt>> I<E<lt>GroupingE<gt>>]
-Show values or an aggregation of values. The I<selector> selects which values
-to show. It is basically an I<identifier> with special meaning for C<+> and
-C<*>. If a hostname, plugin, type or one of the two instances is C<+> or C<*>,
-any string will match the selector. The difference between the two is that all
-identifiers with the same substitution for C<+> are grouped and aggregated by
-the specified aggregation function(s). For example, the selector
+Show values or an aggregation of values. The I<Selection> selects which values
+to show. The selection consists of the five options B<host>, B<plugin>,
+B<plugin_instance>, B<type> and B<type_instance> which take a regular
+expression each. The regular expressions are passed on to the C<LISTVAL>
+command so they will behave exactly as documented in L<collectd-unixsock(5)>.
- +/cpu-*/cpu-+
+Example: Show CPU statistics only.
-will return the CPU states of each host, aggregated over all CPUs of each
-system. Please see L</"IDENTIFIERS"> for a description of identifiers.
+ collectdctl show plugin="^cpu$" type="^cpu$"
-The I<aggregation> setting defines how multiple values are combined into one
-value. Valid values are:
+If you're not interested in single values, but aggregations of values, you can
+use the I<Aggregation> and I<Grouping> options to get an overview over your
+system(s) and such. The two options to this effect are:
+
+=over 4
+
+=item B<aggregate=>I<aggr>[B<,>I<aggr>[...]]
+
+List all the aggregation functions that shall be used to combine multiple
+values. Available aggregation functions are:
=over 4
=back
+=item B<group=>I<field>[B<,>I<field>[...]]
+
+Chose the fields of the I<identifier> you want to group values by. Valid
+I<fields> are B<host>, B<plugin>, B<plugin_instance>, B<type> and
+B<type_instance>. In 99E<nbsp>% of all cases, you want to make sure all values
+have the same I<type> -- either by using a construct like C<type='^foo$'>
+or by adding B<type> to the B<group> option (e.g. C<group=type>).
+
+=back
+
+Example: Print the minimum, average and maximum time spent in each CPU state
+for all your web servers:
+
+ collectdctl show host="^www[0-9]\\." plugin="^cpu$" type="^cpu$" aggregate=min,avg,max group=type_instance
+
=back
=head1 IDENTIFIERS
=head1 AUTHOR
-collectd has been written by Florian Forster E<lt>octo at verplant.orgE<gt>
+collectd has been written by Florian Forster E<lt>octo at collectd.orgE<gt>
and many contributors (see `AUTHORS').
collectdctl has been written by
-Håkon J Dugstad Johnsen E<lt>hakon-dugstad.johnsenE<nbsp>atE<nbsp>telenor.comE<gt>
-and Sebastian Harl E<lt>sh at tokkee.orgE<gt>.
+Håkon J Dugstad Johnsen E<lt>hakon-dugstad.johnsenE<nbsp>atE<nbsp>telenor.comE<gt>,
+Sebastian Harl E<lt>sh at tokkee.orgE<gt> and
+Florian Forster E<lt>octo at collectd.orgE<gt>.
=cut