-2007-04-02, Version 4.0.0
+2007-06-03, Version 4.0.0
* collectd: The plugin-infrastructure has been changed to allow for
more types of plugins, namely `write' and `log' plugins.
* collectd: The read-function has been changed to read many plugins in
connections) field was added by Florent Monbillard.
* collectd-nagios: The new `collectd-nagios' binary queries values
from collectd, parses them and exits according to Nagios-standards.
+ * manpages: The manpages have been improved a lot.
2007-05-29, Version 3.11.5
* configure: Added `AC_SYS_LARGEFILE' for LFS.
write your own plugins in Perl and return arbitary values using this
API. See collectd-perl(5).
+ This plugin is still considered to be experimental and subject to change
+ between minor releases.
+
- ping
Network latency: Time to reach the default gateway or another given
host.
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(collectd, 4.0.0-rc10)
+AC_INIT(collectd, 4.0.0)
AC_CONFIG_SRCDIR(src/collectd.c)
AC_CONFIG_HEADERS(src/config.h)
AM_INIT_AUTOMAKE(dist-bzip2)
--- /dev/null
+# collectd - Collectd.pm
+# Copyright (C) 2007 Sebastian Harl
+#
+# 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
+#
+# Author:
+# Sebastian Harl <sh at tokkee.org>
+
+package Collectd;
+
+use strict;
+use warnings;
+
+require Exporter;
+
+our @ISA = qw( Exporter );
+
+our %EXPORT_TAGS = (
+ 'funcs' => [ qw( plugin_register plugin_unregister
+ plugin_dispatch_values plugin_log ) ],
+ 'types' => [ qw( TYPE_INIT TYPE_READ TYPE_WRITE TYPE_SHUTDOWN TYPE_LOG
+ TYPE_DATASET ) ],
+ 'ds_types' => [ qw( DS_TYPE_COUNTER DS_TYPE_GAUGE ) ],
+ 'log' => [ qw( LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG ) ],
+);
+
+{
+ my %seen;
+
+ push @{$EXPORT_TAGS{'all'}}, grep {! $seen{$_}++ } @{$EXPORT_TAGS{$_}}
+ foreach keys %EXPORT_TAGS;
+}
+
+Exporter::export_ok_tags('all');
+
+bootstrap Collectd "4.0.0";
+
+1;
+
+# vim: set sw=4 ts=4 tw=78 noexpandtab :
+
=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
Perl-script every time you want to read a value with the C<exec plugin> (see
L<collectd-exec(5)>) and provides a lot more functionality, too.
+Please note that this is still considered to be experimental and subject to
+change between minor releases.
+
=head1 DATA TYPES
There are two more complex types you need to know about:
Submits a value (identified by I<Identifier>, see below) to the daemon which
will dispatch it to all it's write-plugins. The I<Valuelist> is a
-colon-seperated list of values, either an integer if the data-source is a
-counter, of a double if the data-source if of type "gauge". You can submit an
-undefined gauge-value by using B<U>. When submitting B<U> to a counter the
-behavior is undefined.
+colon-seperated list of the time and the values, each either an integer if the
+data-source is a counter, of a double if the data-source if of type "gauge".
+You can submit an undefined gauge-value by using B<U>. When submitting B<U> to
+a counter the behavior is undefined. The time is given as epoch (i.E<nbsp>e.
+standard UNIX time).
Example:
-> | PUTVAL testhost/interface/if_octets-test0 1179574444:123:456
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);