=head1 DESCRIPTION
The C<exec plugin> forks of an executable and reads back values that it writes
-to C<STDOUT>. The executable is forked in a fassion similar to L<init>: It is
+to C<STDOUT>. The executable is forked in a fashion similar to L<init>: It is
forked once and not again until it exits. If it exited, it will be forked again
after at most I<Interval> seconds. It is perfectly legal for the executable to
run for a long time and continuously write values to C<STDOUT>.
=item
-Any other line must be of the form C<I<type>,I<type-instance>,I<value>>, where
-I<type> is either B<counter> or B<gauge>, I<type-instance> may not contain
-C<,> (comma), C</> (slash) and C<\0> (null byte) and I<value> is either an
-integer (if I<type> is B<counter>) or a floating-point number (if I<type> is
-B<gauge>).
+Other lines must consist of an I<Identifier> and a I<Value-List>, separated by
+a space. A description of these two parts follows:
-=back
+An I<Identifier> is of the form
+C<I<host>B</>I<plugin>B<->I<instance>B</>I<type>B<->I<instance>> with both
+I<instance>-parts being optional. If they're omitted the hyphen must be
+omitted, too.
+
+A I<Value-List> is a colon-separated list of values, prepended by the time
+stamp in epoch, i.E<nbsp>e. the same format RRDTool uses, see L<rrdupdate(1)>.
+As with the argument passed to RRDTool you can use B<N> as the current time and
+B<U> for undefined values. However, undefined values can only passed for
+B<GAUGE> values. When setting B<U> for a B<COUNTER> data source the behavior is
+undefined.
+
+Since examples usually let one understand a lot better, here are some:
-The values are always considered to be "fresh", i.E<nbsp>e. the time is set to
-"now".
+ leeloo/cpu-0/cpu-idle N:2299366
+ alice/interface/if_octets-eth0 1180647081:421465:479194
+
+=back
When collectd exits it sends a B<SIGTERM> to all still running
child-processes upon which they have to quit.
L<collectd(1)>,
L<collectd.conf(5)>,
L<collectd-perl(5)>,
+L<collectd-unixsock(5)>,
L<fork(2)>, L<exec(3)>
=head1 AUTHOR
return (-1);
return (0);
} /* int format_name */
+
+int parse_identifier (char *str, char **ret_host,
+ char **ret_plugin, char **ret_plugin_instance,
+ char **ret_type, char **ret_type_instance)
+{
+ char *hostname = NULL;
+ char *plugin = NULL;
+ char *plugin_instance = NULL;
+ char *type = NULL;
+ char *type_instance = NULL;
+
+ hostname = str;
+ if (hostname == NULL)
+ return (-1);
+
+ plugin = strchr (hostname, '/');
+ if (plugin == NULL)
+ return (-1);
+ *plugin = '\0'; plugin++;
+
+ type = strchr (plugin, '/');
+ if (type == NULL)
+ return (-1);
+ *type = '\0'; type++;
+
+ plugin_instance = strchr (plugin, '-');
+ if (plugin_instance != NULL)
+ {
+ *plugin_instance = '\0';
+ plugin_instance++;
+ }
+
+ type_instance = strchr (type, '-');
+ if (type_instance != NULL)
+ {
+ *type_instance = '\0';
+ type_instance++;
+ }
+
+ *ret_host = hostname;
+ *ret_plugin = plugin;
+ *ret_plugin_instance = plugin_instance;
+ *ret_type = type;
+ *ret_type_instance = type_instance;
+ return (0);
+} /* int parse_identifier */
+
+int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds)
+{
+ int i;
+ char *dummy;
+ char *ptr;
+ char *saveptr;
+
+ i = -1;
+ dummy = buffer;
+ saveptr = NULL;
+ while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL)
+ {
+ dummy = NULL;
+
+ if (i >= vl->values_len)
+ break;
+
+ if (i == -1)
+ {
+ if (strcmp ("N", ptr) == 0)
+ vl->time = time (NULL);
+ else
+ vl->time = (time_t) atoi (ptr);
+ }
+ else
+ {
+ if (strcmp ("U", ptr) == 0)
+ vl->values[i].gauge = NAN;
+ else if (ds->ds[i].type == DS_TYPE_COUNTER)
+ vl->values[i].counter = atoll (ptr);
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ vl->values[i].gauge = atof (ptr);
+ }
+
+ i++;
+ } /* while (strtok_r) */
+
+ if ((ptr != NULL) || (i != vl->values_len))
+ return (-1);
+ return (0);
+} /* int parse_values */
#define COMMON_H
#include "collectd.h"
+#include "plugin.h"
#define sfree(ptr) \
if((ptr) != NULL) { \
format_name (ret, ret_len, (vl)->host, (vl)->plugin, (vl)->plugin_instance, \
(ds)->type, (vl)->type_instance)
+int parse_identifier (char *str, char **ret_host,
+ char **ret_plugin, char **ret_plugin_instance,
+ char **ret_type, char **ret_type_instance);
+int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
+
#endif /* COMMON_H */
return (0);
} /* int exec_config */
-static void submit_counter (const char *type_instance, counter_t value)
-{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
-
- DEBUG ("type_instance = %s; value = %llu;", type_instance, value);
-
- values[0].counter = value;
-
- vl.values = values;
- vl.values_len = 1;
- vl.time = time (NULL);
- strcpy (vl.host, hostname_g);
- strcpy (vl.plugin, "exec");
- strcpy (vl.plugin_instance, "");
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-
- plugin_dispatch_values ("counter", &vl);
-} /* void submit_counter */
-
-static void submit_gauge (const char *type_instance, gauge_t value)
-{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
-
- DEBUG ("type_instance = %s; value = %lf;", type_instance, value);
-
- values[0].gauge = value;
-
- vl.values = values;
- vl.values_len = 1;
- vl.time = time (NULL);
- strcpy (vl.host, hostname_g);
- strcpy (vl.plugin, "exec");
- strcpy (vl.plugin_instance, "");
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
-
- plugin_dispatch_values ("gauge", &vl);
-} /* void submit_counter */
-
static void exec_child (program_list_t *pl)
{
int status;
return (fd_pipe[0]);
} /* int fork_child */
+static int parse_line (char *buffer)
+{
+ char *fields[4];
+ int fields_num;
+
+ char *hostname;
+ char *plugin;
+ char *plugin_instance;
+ char *type;
+ char *type_instance;
+
+ const data_set_t *ds;
+ value_list_t vl = VALUE_LIST_INIT;
+
+ int status;
+
+ fields_num = strsplit (buffer, fields, 4);
+ if (fields_num != 2)
+ {
+ WARNING ("exec plugin: Number of fields is not 2.");
+ return (-1);
+ }
+
+ status = parse_identifier (fields[0], &hostname,
+ &plugin, &plugin_instance,
+ &type, &type_instance);
+ if (status != 0)
+ {
+ WARNING ("exec plugin: Cannot parse `%s'", fields[0]);
+ return (-1);
+ }
+
+ if ((strlen (hostname) >= sizeof (vl.host))
+ || (strlen (plugin) >= sizeof (vl.plugin))
+ || ((plugin_instance != NULL)
+ && (strlen (plugin_instance) >= sizeof (vl.plugin_instance)))
+ || ((type_instance != NULL)
+ && (strlen (type_instance) >= sizeof (vl.type_instance))))
+ {
+ WARNING ("exec plugin: An identifier is too long.");
+ return (-1);
+ }
+
+ strcpy (vl.host, hostname);
+ strcpy (vl.plugin, plugin);
+ if (plugin_instance != NULL)
+ strcpy (vl.plugin_instance, plugin_instance);
+ if (type_instance != NULL)
+ strcpy (vl.type_instance, type_instance);
+
+ ds = plugin_get_ds (type);
+ if (ds == NULL)
+ {
+ WARNING ("exec plugin: No such type: `%s'", type);
+ return (-1);
+ }
+
+ vl.values_len = ds->ds_num;
+ vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+ if (vl.values == NULL)
+ return (-1);
+
+ /* Sets vl.values and vl.time */
+ status = parse_values (fields[1], &vl, ds);
+ if (status != 0)
+ {
+ WARNING ("exec plugin: Cannot parse `%s'", fields[1]);
+ sfree (vl.values);
+ return (-1);
+ }
+
+ plugin_dispatch_values (type, &vl);
+
+ sfree (vl.values);
+
+ return (0);
+} /* int parse_line */
+
static void *exec_read_one (void *arg)
{
program_list_t *pl = (program_list_t *) arg;
while (fgets (buffer, sizeof (buffer), fh) != NULL)
{
int len;
- char *type;
- char *type_instance;
- char *value;
len = strlen (buffer);
DEBUG ("exec plugin: exec_read_one: buffer = %s", buffer);
- if (len < 5)
- continue;
-
- if (buffer[0] == '#')
- continue;
-
- type = buffer;
-
- type_instance = strchr (type, ',');
- if (type_instance == NULL)
- continue;
- *type_instance = '\0';
- type_instance++;
-
- if ((strcasecmp ("counter", type) != 0)
- && (strcasecmp ("gauge", type) != 0))
- {
- WARNING ("exec plugin: Received invalid type: %s", type);
- continue;
- }
-
- value = strchr (type_instance, ',');
- if (value == NULL)
- {
- WARNING ("exec plugin: type-instance is missing.");
- continue;
- }
- *value = '\0';
- value++;
-
- DEBUG ("exec plugin: exec_read_one: type = %s; type_instance = %s; "
- "value = %s;", type, type_instance, value);
-
- if (strcasecmp ("counter", type) == 0)
- submit_counter (type_instance, atoll (value));
- else
- submit_gauge (type_instance, atof (value));
+ parse_line (buffer);
} /* while (fgets) */
fclose (fh);
*/
#include "collectd.h"
-#include "common.h"
#include "configfile.h"
/* ... while we want the definition found in plugin.h. */
#include "plugin.h"
+#include "common.h"
#define PLUGIN_INIT 0
#define PLUGIN_READ 1
/*
* Functions
*/
-static int parse_identifier (char *str, char **ret_host,
- char **ret_plugin, char **ret_plugin_instance,
- char **ret_type, char **ret_type_instance)
-{
- char *hostname = NULL;
- char *plugin = NULL;
- char *plugin_instance = NULL;
- char *type = NULL;
- char *type_instance = NULL;
-
- hostname = str;
- if (hostname == NULL)
- return (-1);
-
- plugin = strchr (hostname, '/');
- if (plugin == NULL)
- return (-1);
- *plugin = '\0'; plugin++;
-
- type = strchr (plugin, '/');
- if (type == NULL)
- return (-1);
- *type = '\0'; type++;
-
- plugin_instance = strchr (plugin, '-');
- if (plugin_instance != NULL)
- {
- *plugin_instance = '\0';
- plugin_instance++;
- }
-
- type_instance = strchr (type, '-');
- if (type_instance != NULL)
- {
- *type_instance = '\0';
- type_instance++;
- }
-
- *ret_host = hostname;
- *ret_plugin = plugin;
- *ret_plugin_instance = plugin_instance;
- *ret_type = type;
- *ret_type_instance = type_instance;
- return (0);
-} /* int parse_identifier */
-
static value_cache_t *cache_search (const char *name)
{
value_cache_t *vc;
return (-1);
}
- if ((strlen (hostname) > sizeof (vl.host))
- || (strlen (plugin) > sizeof (vl.plugin))
+ if ((strlen (hostname) >= sizeof (vl.host))
+ || (strlen (plugin) >= sizeof (vl.plugin))
|| ((plugin_instance != NULL)
- && (strlen (plugin_instance) > sizeof (vl.plugin_instance)))
+ && (strlen (plugin_instance) >= sizeof (vl.plugin_instance)))
|| ((type_instance != NULL)
- && (strlen (type_instance) > sizeof (vl.type_instance))))
+ && (strlen (type_instance) >= sizeof (vl.type_instance))))
{
fprintf (fh, "-1 Identifier too long.");
return (-1);