# python stuff
*.pyc
+
+# tag stuff
+src/tags
+
+# backup stuff
+*~
collectd without the need to start a heavy interpreter every interval.
See collectd-python(5) for details.
+ - redis
+ The redis plugin gathers information from a redis server, including:
+ uptime, used memory, total connections etc.
+
- routeros
Query interface and wireless registration statistics from RouterOS.
* libclntsh (optional)
Used by the `oracle' plugin.
+ * libcredis (optional)
+ Used by the redis plugin. Please note that you require a 0.2.2 version
+ or higher. <http://code.google.com/p/credis/>
+
* libcurl (optional)
If you want to use the `apache', `ascent', `curl', `nginx', or `write_http'
plugin.
}
}
-sub plugin_flush_one {
- my $timeout = shift;
- my $name = shift;
-
- WARNING ("Collectd::plugin_flush_one is deprecated - "
- . "use Collectd::plugin_flush instead.");
-
- if (! (defined ($timeout) && defined ($name))) {
- ERROR ("Usage: Collectd::plugin_flush_one(timeout, name)");
- return;
- }
-
- plugin_flush (plugins => $name, timeout => $timeout);
-}
-
-sub plugin_flush_all {
- my $timeout = shift;
-
- WARNING ("Collectd::plugin_flush_all is deprecated - "
- . "use Collectd::plugin_flush instead.");
-
- if (! defined ($timeout)) {
- ERROR ("Usage: Collectd::plugin_flush_all(timeout)");
- return;
- }
-
- plugin_flush (timeout => $timeout);
-}
-
sub fc_call {
my $type = shift;
my $name = shift;
fi
AM_CONDITIONAL(BUILD_WITH_LIBKVM_OPENFILES, test "x$with_kvm_openfiles" = "xyes")
+# --with-libcredis {{{
+AC_ARG_WITH(libcredis, [AS_HELP_STRING([--with-libcredis@<:@=PREFIX@:>@], [Path to libcredis.])],
+[
+ if test "x$withval" = "xyes"
+ then
+ with_libcredis="yes"
+ else if test "x$withval" = "xno"
+ then
+ with_libcredis="no"
+ else
+ with_libcredis="yes"
+ LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS -I$withval/include"
+ LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS -L$withval/lib"
+ fi; fi
+],
+[with_libcredis="yes"])
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+
+CPPFLAGS="$CPPFLAGS $LIBCREDIS_CPPFLAGS"
+LDFLAGS="$LDFLAGS $LIBCREDIS_LDFLAGS"
+
+if test "x$with_libcredis" = "xyes"
+then
+ if test "x$LIBCREDIS_CPPFLAGS" != "x"
+ then
+ AC_MSG_NOTICE([libcredis CPPFLAGS: $LIBCREDIS_CPPFLAGS])
+ fi
+ AC_CHECK_HEADERS(credis.h,
+ [with_libcredis="yes"],
+ [with_libcredis="no ('credis.h' not found)"])
+fi
+if test "x$with_libcredis" = "xyes"
+then
+ if test "x$LIBCREDIS_LDFLAGS" != "x"
+ then
+ AC_MSG_NOTICE([libcredis LDFLAGS: $LIBCREDIS_LDFLAGS])
+ fi
+ AC_CHECK_LIB(credis, credis_info,
+ [with_libcredis="yes"],
+ [with_libcredis="no (symbol 'credis_info' not found)"])
+
+fi
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+
+if test "x$with_libcredis" = "xyes"
+then
+ BUILD_WITH_LIBCREDIS_CPPFLAGS="$LIBCREDIS_CPPFLAGS"
+ BUILD_WITH_LIBCREDIS_LDFLAGS="$LIBCREDIS_LDFLAGS"
+ AC_SUBST(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBCREDIS_LDFLAGS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBCREDIS, test "x$with_libcredis" = "xyes")
+# }}}
+
# --with-libcurl {{{
with_curl_config="curl-config"
with_curl_cflags=""
fi
if test "x$have_sysctlbyname" = "xyes"
then
+ plugin_contextswitch="yes"
plugin_cpu="yes"
plugin_memory="yes"
plugin_tcpconns="yes"
AC_PLUGIN([processes], [$plugin_processes], [Process statistics])
AC_PLUGIN([protocols], [$plugin_protocols], [Protocol (IP, TCP, ...) statistics])
AC_PLUGIN([python], [$with_python], [Embed a Python interpreter])
+AC_PLUGIN([redis], [$with_libcredis], [Redis plugin])
AC_PLUGIN([routeros], [$with_librouteros], [RouterOS plugin])
AC_PLUGIN([rrdcached], [$librrd_rrdc_update], [RRDTool output plugin])
AC_PLUGIN([rrdtool], [$with_librrd], [RRDTool output plugin])
AC_PLUGIN([vserver], [$plugin_vserver], [Linux VServer statistics])
AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics])
AC_PLUGIN([write_http], [$with_libcurl], [HTTP output plugin])
+AC_PLUGIN([write_redis], [$with_libcredis], [Redis output plugin])
AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics])
AC_PLUGIN([zfs_arc], [$plugin_zfs_arc], [ZFS ARC statistics])
Libraries:
libcurl . . . . . . . $with_libcurl
libdbi . . . . . . . $with_libdbi
+ libcredis . . . . . . $with_libcredis
libesmtp . . . . . . $with_libesmtp
libganglia . . . . . $with_libganglia
libgcrypt . . . . . . $with_libgcrypt
processes . . . . . . $enable_processes
protocols . . . . . . $enable_protocols
python . . . . . . . $enable_python
+ redis . . . . . . . . $enable_redis
routeros . . . . . . $enable_routeros
rrdcached . . . . . . $enable_rrdcached
rrdtool . . . . . . . $enable_rrdtool
vserver . . . . . . . $enable_vserver
wireless . . . . . . $enable_wireless
write_http . . . . . $enable_write_http
+ write_redis . . . . . $enable_write_redis
xmms . . . . . . . . $enable_xmms
zfs_arc . . . . . . . $enable_zfs_arc
AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
sbin_PROGRAMS = collectd collectdmon
-bin_PROGRAMS = collectd-nagios collectd-flush
+bin_PROGRAMS = collectd-nagios collectdctl
collectd_SOURCES = collectd.c collectd.h \
common.c common.h \
collectd_nagios_DEPENDENCIES = libcollectdclient/libcollectdclient.la
-collectd_flush_SOURCES = collectd-flush.c
-collectd_flush_LDADD =
+collectdctl_SOURCES = collectdctl.c
+collectdctl_LDADD =
if BUILD_WITH_LIBSOCKET
-collectd_flush_LDADD += -lsocket
+collectdctl_LDADD += -lsocket
endif
if BUILD_AIX
-collectd_flush_LDADD += -lm
+collectdctl_LDADD += -lm
endif
-collectd_flush_LDADD += libcollectdclient/libcollectdclient.la
-collectd_flush_DEPENDENCIES = libcollectdclient/libcollectdclient.la
+collectdctl_LDADD += libcollectdclient/libcollectdclient.la
+collectdctl_DEPENDENCIES = libcollectdclient/libcollectdclient.la
pkglib_LTLIBRARIES =
collectd_DEPENDENCIES += protocols.la
endif
+if BUILD_PLUGIN_REDIS
+pkglib_LTLIBRARIES += redis.la
+redis_la_SOURCES = redis.c
+redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
+redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+redis_la_LIBADD = -lcredis
+collectd_LDADD += "-dlopen" redis.la
+collectd_DEPENDENCIES += redis.la
+endif
+
if BUILD_PLUGIN_ROUTEROS
pkglib_LTLIBRARIES += routeros.la
routeros_la_SOURCES = routeros.c
collectd_DEPENDENCIES += write_http.la
endif
+if BUILD_PLUGIN_WRITE_REDIS
+pkglib_LTLIBRARIES += write_redis.la
+write_redis_la_SOURCES = write_redis.c
+write_redis_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBCREDIS_LDFLAGS)
+write_redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCREDIS_CPPFLAGS)
+write_redis_la_LIBADD = -lcredis
+collectd_LDADD += "-dlopen" write_redis.la
+collectd_DEPENDENCIES += write_redis.la
+endif
+
if BUILD_PLUGIN_XMMS
pkglib_LTLIBRARIES += xmms.la
xmms_la_SOURCES = xmms.c
collectd.conf.5 \
collectd-email.5 \
collectd-exec.5 \
+ collectdctl.1 \
collectd-java.5 \
collectdmon.1 \
collectd-nagios.1 \
EXTRA_DIST += collectd.conf.pod \
collectd-email.pod \
collectd-exec.pod \
+ collectdctl.pod \
collectd-java.pod \
collectdmon.pod \
collectd-nagios.pod \
/**
* collectd - src/apache.c
- * Copyright (C) 2006-2009 Florian octo Forster
+ * Copyright (C) 2006-2010 Florian octo Forster
* Copyright (C) 2007 Florent EppO Monbillard
* Copyright (C) 2009 Amit Gupta
*
st->server_type = APACHE;
else if (strstr (buf, "lighttpd") != NULL)
st->server_type = LIGHTTPD;
+ else if (strstr (buf, "IBM_HTTP_Server") != NULL)
+ st->server_type = APACHE;
else
{
const char *hdr = buf;
{
int status = 0;
int i;
- oconfig_item_t *lci = NULL; /* legacy config */
for (i = 0; i < ci->children_num; i++)
{
oconfig_item_t *child = ci->children + i;
- if (strcasecmp ("Instance", child->key) == 0 && child->children_num > 0)
+ if (strcasecmp ("Instance", child->key) == 0)
config_add (child);
else
- {
- /* legacy mode - convert to <Instance ...> config */
- if (lci == NULL)
- {
- lci = malloc (sizeof(*lci));
- if (lci == NULL)
- {
- ERROR ("apache plugin: malloc failed.");
- return (-1);
- }
- memset (lci, '\0', sizeof (*lci));
- }
-
- lci->children_num++;
- lci->children =
- realloc (lci->children,
- lci->children_num * sizeof (*child));
- if (lci->children == NULL)
- {
- ERROR ("apache plugin: realloc failed.");
- return (-1);
- }
- memcpy (&lci->children[lci->children_num-1], child, sizeof (*child));
- }
+ WARNING ("apache plugin: The configuration option "
+ "\"%s\" is not allowed here. Did you "
+ "forget to add an <Instance /> block "
+ "around the configuration?",
+ child->key);
} /* for (ci->children) */
- if (lci)
- {
- /* create a <Instance ""> entry */
- lci->key = "Instance";
- lci->values_num = 1;
- lci->values = (oconfig_value_t *) malloc (lci->values_num * sizeof (oconfig_value_t));
- lci->values[0].type = OCONFIG_TYPE_STRING;
- lci->values[0].value.string = "";
-
- status = config_add (lci);
- sfree (lci->values);
- sfree (lci->children);
- sfree (lci);
- }
-
- return status;
+ return (status);
} /* int config */
/* initialize curl for each host */
st->server_type = APACHE;
else if (strcasecmp(st->server, "lighttpd") == 0)
st->server_type = LIGHTTPD;
+ else if (strcasecmp(st->server, "ibm_http_server") == 0)
+ st->server_type = APACHE;
else
WARNING ("apache plugin: Unknown `Server' setting: %s",
st->server);
+++ /dev/null
-/**
- * collectd-flush - src/collectd-flush.c
- * Copyright (C) 2010 HÃ¥kon J Dugstad Johnsen
- *
- * 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
- *
- * Authors:
- * HÃ¥kon J Dugstad Johnsen <hakon-dugstad.johnsen at telenor.com>
- **/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-
-#include "libcollectdclient/client.h"
-
-extern char *optarg;
-
-static int flush (
- const char *address,
- const char *plugin,
- const char *ident_str,
- int timeout)
-{
- lcc_connection_t *connection;
- lcc_identifier_t ident;
-
- /* Pointer which is passed to lcc_flush.
- * Either a null pointer or it points to ident */
- lcc_identifier_t *identp;
- int status;
-
- connection = NULL;
- status = lcc_connect(address, &connection);
- if (status != 0) {
- fprintf (stderr, "ERROR: Connecting to daemon at %s failed: %s.\n",
- address, strerror (errno));
- return 1;
- }
-
- identp = NULL;
- if (ident_str != NULL && *ident_str != '\0') {
- status = lcc_string_to_identifier (connection, &ident, ident_str);
- if (status != 0) {
- fprintf (stderr, "ERROR: Creating and identifier failed: %s.\n",
- lcc_strerror(connection));
- LCC_DESTROY (connection);
-
- return 1;
- }
- identp = &ident;
- }
-
- status = lcc_flush (connection, plugin, identp, timeout);
- if (status != 0) {
- fprintf (stderr, "ERROR: Flushing failed: %s.\n",
- lcc_strerror (connection));
- LCC_DESTROY (connection);
-
- return 1;
- }
-
- LCC_DESTROY (connection);
-
- return 0;
-}
-
-void usage (const char *name) {
- fprintf (stderr, "Usage: %s [options]\n"
- "\n"
- "Valid options are:\n"
- " -h, --help Display this help message.\n"
- " -s, --socket=<socket> Path to collectd's UNIX socket. Default: /var/run/collectd-unixsock\n"
- " -p, --plugin=<plugin> Plugin to flush _to_ (not from). Example: rrdtool\n"
- " -i, --identifier=<identifier>\n"
- " Only flush data specified by <identifier>, which has the format: \n"
- "\n"
- " [<hostname>/]<plugin>[-<plugin_instance>]/<type>[-<type_instance>]\n"
- "\n"
- " Hostname defaults to the local hostname if omitted.\n"
- " No error is returned if the specified identifier does not exist.\n"
- " Examples: uptime/uptime\n"
- " somehost/cpu-0/cpu-wait\n"
- " -t, --timeout=<timeout> Only flush values older than this timeout.\n", name);
-}
-
-/*
- * Count how many occurences there are of a char in a string.
- */
-int charoccurences (const char *str, char chr) {
- int count = 0;
- while (*str != '\0') {
- if (*str == chr) {
- count++;
- }
- str++;
- }
-
- return count;
-}
-
-int main (int argc, char **argv) {
- char address[1024] = "unix:/var/run/collectd-unixsock";
- char *plugin = NULL;
- char ident_str[1024] = "";
- int timeout = -1;
- char hostname[1024];
- char c;
-
- static struct option long_options[] =
- {
- {"help", no_argument, 0, 'h'},
- {"socket", required_argument, 0, 's'},
- {"plugin", required_argument, 0, 'p'},
- {"identifier", required_argument, 0, 'i'},
- {"timeout", required_argument, 0, 't'}
- };
- int option_index = 0;
-
-
- while ((c = getopt_long (argc, argv, "s:p:i:ht:", long_options, &option_index)) != -1) {
- switch (c) {
- case 's':
- snprintf (address, sizeof (address), "unix:%s", optarg);
- break;
- case 'p':
- plugin = optarg;
- break;
- case 'i':
- if(charoccurences(optarg, '/') == 1) {
- /* The user has omitted the hostname part of the identifier
- * (there is only one '/' in the identifier)
- * Let's add the local hostname */
- if(gethostname(hostname, sizeof(hostname)) != 0) {
- fprintf (stderr, "Could not get local hostname: %s", strerror(errno));
- return 1;
- }
- /* Make sure hostname is zero-terminated */
- hostname[sizeof(hostname)-1] = '\0';
- snprintf (ident_str, sizeof (ident_str), "%s/%s", hostname, optarg);
- /* Make sure ident_str is zero terminated */
- ident_str[sizeof(ident_str)-1] = '\0';
- } else {
- strncpy(ident_str, optarg, sizeof (ident_str));
- /* Make sure identifier is zero terminated */
- ident_str[sizeof(ident_str)-1] = '\0';
- }
- break;
- case 't':
- timeout = atoi (optarg);
- break;
- case 'h':
- usage (argv[0]);
- return 0;
- default:
- usage (argv[0]);
- return 1;
- }
- }
-
- return flush(address, plugin, ident_str, timeout);
-}
+++ /dev/null
-=head1 NAME
-
-collectd-flush - Small command line utility to flush collectd
-
-=head1 SYNOPSIS
-
-collectd-flush I<[options]>
-
-=head1 DESCRIPTION
-
-This small command line utitilty uses C<libcollectdclient> to flush collectd
-through a socket from the L<unixsock plugin>. Useful if you want to be sure
-you have the latest values in your RRD files before graphing them or copying
-them somewhere else.
-
-=head1 ARGUMENTS AND OPTIONS
-
-The following arguments and options are understood by collectd-flush. The order
-of the arguments generally doesn't matter, as long as no argument is passed
-more than once.
-
-=over 4
-
-=item B<-h>, B<--help>
-
-Display information about the options.
-
-=item B<-s>, B<--socket=>I<socket>
-
-Path to the UNIX socket opened by collectd's C<unixsock plugin>.
-Default: /var/run/collectd-unixsock
-
-=item B<-p>, B<--plugin=>I<plugin>
-
-Plugin to flush I<to>. Example: B<rrdtool>.
-
-=item B<-i>, B<--identifier=>I<identifier>
-
-If this option is present, only the data specified by I<identifier> will be flushed.
-I<identifier> has the following format:
-
-[I<hostname>/]I<plugin>[-I<plugin_instance>]/I<type>[-I<type_instance>]
-
-Examples:
- somehost/cpu-0/cpu-idle
- uptime/uptime
- otherhost/memory/memory-used
-
-Hostname defaults to the local hostname if omitted. No error is returned if the
-specified identifier does not exist (this is a limitation in the
-C<libcollectdclient> library).You can only specify one identifier each time you
-run this program (even though L<collectd-unixsock(5)> supports multiple
-identifiers).
-
-=item B<-t>, B<--timeout=>I<timeout>
-
-Only flush values older than I<timeout>.
-
-=back
-
-=head1 SEE ALSO
-
-L<collectd(1)>
-L<collectd.conf(5)>
-L<collectd-unixsock(5)>
-
-=head1 AUTHOR
-
-HÃ¥kon J Dugstad Johnsen E<lt>hakon-dugstad.johnsenE<nbsp>atE<nbsp>telenor.comE<gt>
-
-=cut
# include "config.h"
#endif
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+
#if !defined(__GNUC__) || !__GNUC__
# define __attribute__(x) /**/
#endif
#include <string.h>
#include <strings.h>
#include <assert.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <math.h>
#include "libcollectdclient/client.h"
-/*
- * This is copied directly from collectd.h. Make changes there!
- */
-#if NAN_STATIC_DEFAULT
-# include <math.h>
-/* #endif NAN_STATIC_DEFAULT*/
-#elif NAN_STATIC_ISOC
-# ifndef __USE_ISOC99
-# define DISABLE_ISOC99 1
-# define __USE_ISOC99 1
-# endif /* !defined(__USE_ISOC99) */
-# include <math.h>
-# if DISABLE_ISOC99
-# undef DISABLE_ISOC99
-# undef __USE_ISOC99
-# endif /* DISABLE_ISOC99 */
-/* #endif NAN_STATIC_ISOC */
-#elif NAN_ZERO_ZERO
-# include <math.h>
-# ifdef NAN
-# undef NAN
-# endif
-# define NAN (0.0 / 0.0)
-# ifndef isnan
-# define isnan(f) ((f) != (f))
-# endif /* !defined(isnan) */
-#endif /* NAN_ZERO_ZERO */
-
#define RET_OKAY 0
#define RET_WARNING 1
#define RET_CRITICAL 2
=head1 SYNOPSIS
- LoadPlugin perl
+ <LoadPlugin perl>
+ Globals true
+ </LoadPlugin>
# ...
<Plugin perl>
IncludeDir "/path/to/perl/plugins"
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.
+When loading the C<perl plugin>, the B<Globals> option should be enabled.
+Else, the perl plugin will fail to load any Perl modules implemented in C,
+which includes, amongst many others, the B<threads> module used by the plugin
+itself. See the documentation of the B<Globals> option in L<collectd.conf(5)>
+for details.
+
=head1 CONFIGURATION
=over 4
type, data-set and value-list is passed to all write-callbacks that are
registered with the daemon.
-B<Note>: Prior to version 4.4 of collectd, the data-set type used to be passed
-as the first argument to B<plugin_register>. This syntax is still supported
-for backwards compatibility but has been deprecated and will be removed in
-some future version of collectd.
-
=item B<plugin_write> ([B<plugins> => I<...>][, B<datasets> => I<...>],
B<valuelists> => I<...>)
the B<plugins> and B<identifiers> arguments may either be a string or a
reference to an array of strings.
-=item B<plugin_flush_one> (I<timeout>, I<plugin>)
-
-This is identical to using "plugin_flush (timeout =E<gt> I<timeout>, plugins
-=E<gt> I<plugin>".
-
-B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_one> has been
-deprecated and will be removed in some future version of collectd. Use
-B<plugin_flush> instead.
-
-=item B<plugin_flush_all> (I<timeout>)
-
-This is identical to using "plugin_flush (timeout =E<gt> I<timeout>)".
-
-B<Note>: Starting with version 4.5 of collectd, B<plugin_flush_all> has been
-deprecated and will be removed in some future version of collectd. Use
-B<plugin_flush> instead.
-
=item B<plugin_dispatch_notification> (I<notification>)
Submits a I<notification> to the daemon which will then pass it to all
#@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
#@BUILD_PLUGIN_PROTOCOLS_TRUE@LoadPlugin protocols
#@BUILD_PLUGIN_PYTHON_TRUE@LoadPlugin python
+#@BUILD_PLUGIN_REDIS_TRUE@LoadPlugin redis
#@BUILD_PLUGIN_ROUTEROS_TRUE@LoadPlugin routeros
#@BUILD_PLUGIN_RRDCACHED_TRUE@LoadPlugin rrdcached
@LOAD_PLUGIN_RRDTOOL@LoadPlugin rrdtool
#@BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver
#@BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless
#@BUILD_PLUGIN_WRITE_HTTP_TRUE@LoadPlugin write_http
+#@BUILD_PLUGIN_WRITE_REDIS_TRUE@LoadPlugin write_redis
#@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
#@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc
#</Plugin>
#<Plugin apache>
-# URL "http://localhost/status?auto"
-# User "www-user"
-# Password "secret"
-# CACert "/etc/ssl/ca.crt"
+# <Instance "local">
+# URL "http://localhost/status?auto"
+# User "www-user"
+# Password "secret"
+# CACert "/etc/ssl/ca.crt"
+# </Instance>
#</Plugin>
#<Plugin apcups>
# </Module>
#</Plugin>
+#<Plugin redis>
+# <Node example>
+# Host "redis.example.com"
+# Port "6379"
+# Timeout 2000
+# </Node>
+#</Plugin>
+
#<Plugin routeros>
# <Router>
# Host "router.example.com"
# </URL>
#</Plugin>
+#<Plugin write_redis>
+# <Node "example">
+# Host "localhost"
+# Port "6379"
+# Timeout 1000
+# </Node>
+#</Plugin>
+
##############################################################################
# Filter configuration #
#----------------------------------------------------------------------------#
Loads the plugin I<Plugin>. There must be at least one such line or B<collectd>
will be mostly useless.
+Starting with collectd 4.9, this may also be a block in which further options
+affecting the behavior of B<LoadPlugin> may be specified. The following
+options are allowed inside a B<LoadPlugin> block:
+
+ <LoadPlugin perl>
+ Globals true
+ </LoadPlugin>
+
+=over 4
+
+=item B<Globals> B<true|false>
+
+If enabled, collectd will export all global symbols of the plugin (and of all
+libraries loaded as dependencies of the plugin) and, thus, makes those symbols
+available for resolving unresolved symbols in subsequently loaded plugins if
+that is supported by your system. By default, this is disabled.
+
+This is useful (or possibly even required), e.E<nbsp>g., when loading a plugin
+that embeds some scripting language into the daemon (e.E<nbsp>g. the C<perl>
+or C<python> plugins). Scripting languages usually provide means to load
+extensions written in C. Those extensions require symbols provided by the
+interpreter, which is loaded as a dependency of the respective collectd
+plugin. See the documentation of those plugins (e.E<nbsp>g.,
+L<collectd-perl(5)> or L<collectd-python(5)>) for details.
+
+=back
+
=item B<Include> I<Path>
If I<Path> points to a file, includes that file. If I<Path> points to a
also supported. It introduces a new field, called C<BusyServers>, to count the
number of currently connected clients. This field is also supported.
-The following options are accepted by the C<apache>-plugin:
+The configuration of the I<Apache> plugin consists of one or more
+C<E<lt>InstanceE<nbsp>/E<gt>> blocks. Each block requires one string argument
+as the instance name. For example:
+
+ <Plugin "apache">
+ <Instance "www1">
+ URL "http://www1.example.com/mod_status?auto"
+ </Instance>
+ <Instance "www2">
+ URL "http://www2.example.com/mod_status?auto"
+ </Instance>
+ </Plugin>
+
+The instance name will be used as the I<plugin instance>. To emulate the old
+(versionE<nbsp>4) behavior, you can use an empty string (""). In order for the
+plugin to work correctly, each instance name must be unique. This is not
+enforced by the plugin and it is your responsibility to ensure it.
+
+The following options are accepted within each I<Instance> block:
=over 4
Sets the URL of the C<mod_status> output. This needs to be the output generated
by C<ExtendedStatus on> and it needs to be the machine readable output
-generated by appending the C<?auto> argument.
+generated by appending the C<?auto> argument. This option is I<mandatory>.
=item B<User> I<Username>
=item B<MaxPacketSize> I<1024-65535>
Set the maximum size for datagrams received over the network. Packets larger
-than this will be truncated.
+than this will be truncated. Defaults to 1452E<nbsp>bytes.
=item B<Forward> I<true|false>
The returned lines will be handled separately one after another.
-=item B<Query> I<sql query statement>
-
-This is a deprecated synonym for B<Statement>. It will be removed in version 5
-of collectd.
-
=item B<Param> I<hostname>|I<database>|I<username>|I<interval>
Specify the parameters which should be passed to the SQL query. The parameters
times. If multiple B<ValuesFrom> options are specified, the columns are read
in the given order.
-=item B<Column> I<type> [I<type instance>]
-
-This is a deprecated alternative to a B<Result> block. It will be removed in
-version 5 of collectd. It is equivalent to the following B<Result> block:
-
- <Result>
- Type I<type>
- InstancePrefix I<type instance>
- ValuesFrom I<name of the x. column>
- </Result>
-
-The order of the B<Column> options defines which columns of the query result
-should be used. The first option specifies the data found in the first column,
-the second option that of the second column, and so on.
-
=item B<MinVersion> I<version>
=item B<MaxVersion> I<version>
and patch-level versions, each represented as two-decimal-digit numbers. For
example, version 8.2.3 will become 80203.
-=item B<MinPGVersion> I<version>
-
-=item B<MaxPGVersion> I<version>
-
-These are deprecated synonyms for B<MinVersion> and B<MaxVersion>
-respectively. They will be removed in version 5 of collectd.
-
=back
The following predefined queries are available (the definitions can be found
=back
+=head2 Plugin C<redis>
+
+The I<Redis plugin> connects to one or more Redis servers and gathers
+information about each server's state. For each server there is a I<Node> block
+which configures the connection parameters for this node.
+
+ <Plugin redis>
+ <Node "example">
+ Host "localhost"
+ Port "6379"
+ Timeout 2000
+ </Node>
+ </Plugin>
+
+The information shown in the synopsis above is the I<default configuration>
+which is used by the plugin if no configuration is present.
+
+=over 4
+
+=item B<Node> I<Nodename>
+
+The B<Node> block identifies a new Redis node, that is a new Redis instance
+running in an specified host and port. The name for node is a canonical
+identifier which is used as I<plugin instance>. It is limited to
+64E<nbsp>characters in length.
+
+=item B<Host> I<Hostname>
+
+The B<Host> option is the hostname or IP-address where the Redis instance is
+running on.
+
+=item B<Port> I<Port>
+
+The B<Port> option is the TCP port on which the Redis instance accepts
+connections. Either a service name of a port number may be given. Please note
+that numerical port numbers must be given as a string, too.
+
+=item B<Timeout> I<Timeout in miliseconds>
+
+The B<Timeout> option set the socket timeout for node response. Since the Redis
+read function is blocking, you should keep this value as low as possible. Keep
+in mind that the sum of all B<Timeout> values for all B<Nodes> should be lower
+than B<Interval> defined globally.
+
+=back
+
=head2 Plugin C<rrdcached>
The C<rrdcached> plugin uses the RRDtool accelerator daemon, L<rrdcached(1)>,
=item B<CounterSet>
-The matched number is a counter. Simply sets the internal counter to this
-value.
+=item B<DeriveSet>
+
+=item B<AbsoluteSet>
+
+The matched number is a counter. Simply I<sets> the internal counter to this
+value. Variants exist for C<COUNTER>, C<DERIVE>, and C<ABSOLUTE> data sources.
=item B<CounterAdd>
-Add the matched value to the internal counter.
+=item B<DeriveAdd>
+
+Add the matched value to the internal counter. In case of B<DeriveAdd>, the
+matched number may be negative, which will effectively subtract from the
+internal counter.
=item B<CounterInc>
-Increase the internal counter by one. This B<DSType> is the only one that does
-not use the matched subexpression, but simply counts the number of matched
+=item B<DeriveInc>
+
+Increase the internal counter by one. These B<DSType> are the only ones that do
+not use the matched subexpression, but simply count the number of matched
lines. Thus, you may use a regular expression without submatch in this case.
=back
As you'd expect the B<Gauge*> types interpret the submatch as a floating point
-number, using L<strtod(3)>. The B<CounterSet> and B<CounterAdd> interpret the
-submatch as an integer using L<strtoll(3)>. B<CounterInc> does not use the
-submatch at all and it may be omitted in this case.
+number, using L<strtod(3)>. The B<Counter*> and B<AbsoluteSet> types interpret
+the submatch as an unsigned integer using L<strtoull(3)>. The B<Derive*> types
+interpret the submatch as a signed integer using L<strtoll(3)>. B<CounterInc>
+and B<DeriveInc> do not use the submatch at all and it may be omitted in this
+case.
=item B<Type> I<Type>
#if HAVE_STDINT_H
# include <stdint.h>
#endif
-#if HAVE_STDBOOL_H
-# include <stdbool.h>
-#else
-# ifndef HAVE__BOOL
-# ifdef __cplusplus
-typedef bool _Bool;
-# else
-# define _Bool signed char
-# endif
-# endif
-# define bool _Bool
-# define false 0
-# define true 1
-# define __bool_true_false_are_defined 1
-#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
--- /dev/null
+/**
+ * collectd - src/collectdctl.c
+ * Copyright (C) 2010 HÃ¥kon J Dugstad Johnsen
+ * Copyright (C) 2010 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
+ *
+ * Authors:
+ * HÃ¥kon J Dugstad Johnsen <hakon-dugstad.johnsen at telenor.com>
+ * Sebastian "tokkee" Harl <sh@tokkee.org>
+ **/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef _ISOC99_SOURCE
+# define _ISOC99_SOURCE
+#endif
+
+#ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+#endif
+
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <math.h>
+
+#include "libcollectdclient/client.h"
+
+
+#define DEFAULT_SOCK LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock"
+
+extern char *optarg;
+extern int optind;
+
+static void exit_usage (const char *name, int status) {
+ fprintf ((status == 0) ? stdout : stderr,
+ "Usage: %s [options] <command> [cmd options]\n\n"
+
+ "Available options:\n"
+ " -s Path to collectd's UNIX socket.\n"
+ " Default: "DEFAULT_SOCK"\n"
+
+ "\n -h Display this help and exit.\n"
+
+ "\nAvailable commands:\n\n"
+
+ " * getval <identifier>\n"
+ " * flush [timeout=<seconds>] [plugin=<name>] [identifier=<id>]\n"
+ " * listval\n"
+ " * putval <identifier> [interval=<seconds>] <value-list(s)>\n"
+
+ "\nIdentifiers:\n\n"
+
+ "An identifier has the following format:\n\n"
+
+ " [<hostname>/]<plugin>[-<plugin_instance>]/<type>[-<type_instance>]\n\n"
+
+ "Hostname defaults to the local hostname if omitted (e.g., uptime/uptime).\n"
+ "No error is returned if the specified identifier does not exist.\n"
+
+ "\n"PACKAGE" "VERSION", http://collectd.org/\n"
+ "by Florian octo Forster <octo@verplant.org>\n"
+ "for contributions see `AUTHORS'\n"
+ , name);
+ exit (status);
+}
+
+/* Count the number of occurrences of the character 'chr'
+ * in the specified string. */
+static int count_chars (const char *str, char chr) {
+ int count = 0;
+
+ while (*str != '\0') {
+ if (*str == chr) {
+ count++;
+ }
+ str++;
+ }
+
+ return count;
+} /* count_chars */
+
+static int array_grow (void **array, int *array_len, size_t elem_size)
+{
+ void *tmp;
+
+ assert ((array != NULL) && (array_len != NULL));
+
+ tmp = realloc (*array, (*array_len + 1) * elem_size);
+ if (tmp == NULL) {
+ fprintf (stderr, "ERROR: Failed to allocate memory.\n");
+ return (-1);
+ }
+
+ *array = tmp;
+ ++(*array_len);
+ return (0);
+} /* array_grow */
+
+static int parse_identifier (lcc_connection_t *c,
+ const char *value, lcc_identifier_t *ident)
+{
+ char hostname[1024];
+ char ident_str[1024] = "";
+ int n_slashes;
+
+ int status;
+
+ n_slashes = count_chars (value, '/');
+ if (n_slashes == 1) {
+ /* The user has omitted the hostname part of the identifier
+ * (there is only one '/' in the identifier)
+ * Let's add the local hostname */
+ if (gethostname (hostname, sizeof (hostname)) != 0) {
+ fprintf (stderr, "ERROR: Failed to get local hostname: %s",
+ strerror (errno));
+ return (-1);
+ }
+ hostname[sizeof (hostname) - 1] = '\0';
+
+ snprintf (ident_str, sizeof (ident_str), "%s/%s", hostname, value);
+ ident_str[sizeof(ident_str) - 1] = '\0';
+ }
+ else {
+ strncpy (ident_str, value, sizeof (ident_str));
+ ident_str[sizeof (ident_str) - 1] = '\0';
+ }
+
+ status = lcc_string_to_identifier (c, ident, ident_str);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: Failed to parse identifier ``%s'': %s.\n",
+ ident_str, lcc_strerror(c));
+ return (-1);
+ }
+ return (0);
+} /* parse_identifier */
+
+static int getval (lcc_connection_t *c, int argc, char **argv)
+{
+ lcc_identifier_t ident;
+
+ size_t ret_values_num = 0;
+ gauge_t *ret_values = NULL;
+ char **ret_values_names = NULL;
+
+ int status;
+ size_t i;
+
+ assert (strcasecmp (argv[0], "getval") == 0);
+
+ if (argc != 2) {
+ fprintf (stderr, "ERROR: getval: Missing identifier.\n");
+ return (-1);
+ }
+
+ memset (&ident, 0, sizeof (ident));
+ status = parse_identifier (c, argv[1], &ident);
+ if (status != 0)
+ return (status);
+
+#define BAIL_OUT(s) \
+ do { \
+ if (ret_values != NULL) \
+ free (ret_values); \
+ if (ret_values_names != NULL) { \
+ for (i = 0; i < ret_values_num; ++i) \
+ free (ret_values_names[i]); \
+ free (ret_values_names); \
+ } \
+ ret_values_num = 0; \
+ return (s); \
+ } while (0)
+
+ status = lcc_getval (c, &ident,
+ &ret_values_num, &ret_values, &ret_values_names);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+ BAIL_OUT (-1);
+ }
+
+ for (i = 0; i < ret_values_num; ++i)
+ printf ("%s=%e\n", ret_values_names[i], ret_values[i]);
+ BAIL_OUT (0);
+#undef BAIL_OUT
+} /* getval */
+
+static int flush (lcc_connection_t *c, int argc, char **argv)
+{
+ int timeout = -1;
+
+ lcc_identifier_t *identifiers = NULL;
+ int identifiers_num = 0;
+
+ char **plugins = NULL;
+ int plugins_num = 0;
+
+ int status;
+ int i;
+
+ assert (strcasecmp (argv[0], "flush") == 0);
+
+#define BAIL_OUT(s) \
+ do { \
+ if (identifiers != NULL) \
+ free (identifiers); \
+ identifiers_num = 0; \
+ if (plugins != NULL) \
+ free (plugins); \
+ plugins_num = 0; \
+ return (s); \
+ } while (0)
+
+ for (i = 1; i < argc; ++i) {
+ char *key, *value;
+
+ key = argv[i];
+ value = strchr (argv[i], (int)'=');
+
+ if (! value) {
+ fprintf (stderr, "ERROR: flush: Invalid option ``%s''.\n", argv[i]);
+ BAIL_OUT (-1);
+ }
+
+ *value = '\0';
+ ++value;
+
+ if (strcasecmp (key, "timeout") == 0) {
+ char *endptr = NULL;
+
+ timeout = (int) strtol (value, &endptr, 0);
+
+ if (endptr == value) {
+ fprintf (stderr, "ERROR: Failed to parse timeout as number: %s.\n",
+ value);
+ BAIL_OUT (-1);
+ }
+ else if ((endptr != NULL) && (*endptr != '\0')) {
+ fprintf (stderr, "WARNING: Ignoring trailing garbage after timeout: "
+ "%s.\n", endptr);
+ }
+ }
+ else if (strcasecmp (key, "plugin") == 0) {
+ status = array_grow ((void *)&plugins, &plugins_num,
+ sizeof (*plugins));
+ if (status != 0)
+ BAIL_OUT (status);
+
+ plugins[plugins_num - 1] = value;
+ }
+ else if (strcasecmp (key, "identifier") == 0) {
+ status = array_grow ((void *)&identifiers, &identifiers_num,
+ sizeof (*identifiers));
+ if (status != 0)
+ BAIL_OUT (status);
+
+ memset (identifiers + (identifiers_num - 1), 0, sizeof (*identifiers));
+ status = parse_identifier (c, value,
+ identifiers + (identifiers_num - 1));
+ if (status != 0)
+ BAIL_OUT (status);
+ }
+ else {
+ fprintf (stderr, "ERROR: flush: Unknown option `%s'.\n", key);
+ BAIL_OUT (-1);
+ }
+ }
+
+ if (plugins_num == 0) {
+ status = array_grow ((void *)&plugins, &plugins_num, sizeof (*plugins));
+ if (status != 0)
+ BAIL_OUT (status);
+
+ assert (plugins_num == 1);
+ plugins[0] = NULL;
+ }
+
+ for (i = 0; i < plugins_num; ++i) {
+ if (identifiers_num == 0) {
+ status = lcc_flush (c, plugins[i], NULL, timeout);
+ if (status != 0)
+ fprintf (stderr, "ERROR: Failed to flush plugin `%s': %s.\n",
+ (plugins[i] == NULL) ? "(all)" : plugins[i], lcc_strerror (c));
+ }
+ else {
+ int j;
+
+ for (j = 0; j < identifiers_num; ++j) {
+ status = lcc_flush (c, plugins[i], identifiers + j, timeout);
+ if (status != 0) {
+ char id[1024];
+
+ lcc_identifier_to_string (c, id, sizeof (id), identifiers + j);
+ fprintf (stderr, "ERROR: Failed to flush plugin `%s', "
+ "identifier `%s': %s.\n",
+ (plugins[i] == NULL) ? "(all)" : plugins[i],
+ id, lcc_strerror (c));
+ }
+ }
+ }
+ }
+
+ BAIL_OUT (0);
+#undef BAIL_OUT
+} /* flush */
+
+static int listval (lcc_connection_t *c, int argc, char **argv)
+{
+ lcc_identifier_t *ret_ident = NULL;
+ size_t ret_ident_num = 0;
+
+ int status;
+ size_t i;
+
+ assert (strcasecmp (argv[0], "listval") == 0);
+
+ if (argc != 1) {
+ fprintf (stderr, "ERROR: listval: Does not accept any arguments.\n");
+ return (-1);
+ }
+
+#define BAIL_OUT(s) \
+ do { \
+ if (ret_ident != NULL) \
+ free (ret_ident); \
+ ret_ident_num = 0; \
+ return (s); \
+ } while (0)
+
+ status = lcc_listval (c, &ret_ident, &ret_ident_num);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: %s\n", lcc_strerror (c));
+ BAIL_OUT (status);
+ }
+
+ for (i = 0; i < ret_ident_num; ++i) {
+ char id[1024];
+
+ status = lcc_identifier_to_string (c, id, sizeof (id), ret_ident + i);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: listval: Failed to convert returned "
+ "identifier to a string: %s\n", lcc_strerror (c));
+ continue;
+ }
+
+ printf ("%s\n", id);
+ }
+ BAIL_OUT (0);
+#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 == argv[i]) {
+ 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)'.');
+ endptr = NULL;
+ if (strcasecmp (value, "U") == 0) {
+ values[values_len].gauge = NAN;
+ values_types[values_len] = LCC_TYPE_GAUGE;
+ }
+ else 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;
+
+ lcc_connection_t *c;
+
+ int status;
+
+ while (42) {
+ int c;
+
+ c = getopt (argc, argv, "s:h");
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 's':
+ snprintf (address, sizeof (address), "unix:%s", optarg);
+ address[sizeof (address) - 1] = '\0';
+ break;
+ case 'h':
+ exit_usage (argv[0], 0);
+ break;
+ default:
+ exit_usage (argv[0], 1);
+ }
+ }
+
+ if (optind >= argc) {
+ fprintf (stderr, "%s: missing command\n", argv[0]);
+ exit_usage (argv[0], 1);
+ }
+
+ c = NULL;
+ status = lcc_connect (address, &c);
+ if (status != 0) {
+ fprintf (stderr, "ERROR: Failed to connect to daemon at %s: %s.\n",
+ address, strerror (errno));
+ return (1);
+ }
+
+ if (strcasecmp (argv[optind], "getval") == 0)
+ status = getval (c, argc - optind, argv + optind);
+ else if (strcasecmp (argv[optind], "flush") == 0)
+ 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);
+ }
+
+ LCC_DESTROY (c);
+
+ if (status != 0)
+ return (status);
+ return (0);
+} /* main */
+
+/* vim: set sw=2 ts=2 tw=78 expandtab : */
+
--- /dev/null
+=head1 NAME
+
+collectdctl - Control interface for collectd
+
+=head1 SYNOPSIS
+
+collectdctl I<[options]> I<E<lt>commandE<gt>> I<[command options]>
+
+=head1 DESCRIPTION
+
+collectdctl provides a control interface for collectd, which may be used to
+interact with the daemon using the C<unixsock plugin>.
+
+=head1 OPTIONS
+
+collectdctl supports the following options:
+
+=over 4
+
+=item B<-s> I<socket>
+
+Path to the UNIX socket opened by collectd's C<unixsock plugin>.
+Default: /var/run/collectd-unixsock
+
+=item B<-h>
+
+Display usage information and exit.
+
+=back
+
+=head1 AVAILABLE COMMANDS
+
+The following commands are supported:
+
+=over 4
+
+=item B<getval> I<E<lt>identifierE<gt>>
+
+Query the latest collected value identified by the specified
+I<E<lt>identifierE<gt>> (see below). The value-list associated with that
+data-set is returned as a list of key-value-pairs, each on its own line. Keys
+and values are separated by the equal sign (C<=>).
+
+=item B<flush> [B<timeout=>I<E<lt>secondsE<gt>>] [B<plugin=>I<E<lt>nameE<gt>>]
+[B<identifier=>I<E<lt>idE<gt>>]
+
+Flush the daemon. This is useful, e.E<nbsp>g., to make sure that the latest
+values have been written to the respective RRD file before graphing them or
+copying them to somewhere else.
+
+The following options are supported by the flush command:
+
+=over 4
+
+=item B<timeout=>I<E<lt>secondsE<gt>>
+
+Flush values older than the specified timeout (in seconds) only.
+
+=item B<plugin=>I<E<lt>nameE<gt>>
+
+Flush the specified plugin only. I.E<nbsp>e., data cached by the specified
+plugin is written to disk (or network or whatever), if the plugin supports
+that operation.
+
+Example: B<rrdtool>.
+
+=item B<identifier=>I<E<lt>idE<gt>>
+
+If this option is present, only the data specified by the specified identifier
+(see below) will be flushed. Note that this option is not supported by all
+plugins (e.E<nbsp>g., the C<network> plugin does not support this).
+
+=back
+
+The B<plugin> and B<identifier> options may be specified more than once. In
+that case, all combinations of specified plugins and identifiers will be
+flushed only.
+
+=item B<listval>
+
+Returns a list of all values (by their identifier) available to the
+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
+
+An identifier has the following format:
+
+[I<hostname>/]I<plugin>[-I<plugin_instance>]/I<type>[-I<type_instance>]
+
+Examples:
+ somehost/cpu-0/cpu-idle
+ uptime/uptime
+ otherhost/memory/memory-used
+
+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. A literal C<U> is interpreted as an undefined 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
+
+=item C<collectdctl flush plugin=rrdtool identifier=somehost/cpu-0/cpu-wait>
+
+Flushes all CPU wait RRD values of the first CPU of the local host.
+I.E<nbsp>e., writes all pending RRD updates of that data-source to disk.
+
+=item C<for ident in `collectdctl listval | grep users/users`; do
+ collectdctl getval $ident;
+ done>
+
+Query the latest number of logged in users on all hosts known to the local
+collectd instance.
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<collectd-unixsock(5)>,
+L<types.db(5)>
+
+=head1 AUTHOR
+
+collectd has been written by Florian Forster E<lt>octo at verplant.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>.
+
+=cut
if (status != 0)
{
char errbuf[1024];
- ERROR ("configfile: stat (%s) failed: %s",
+ WARNING ("configfile: stat (%s) failed: %s",
path_ptr,
sstrerror (errno, errbuf, sizeof (errbuf)));
- oconfig_free (root);
- return (NULL);
+ continue;
}
if (S_ISREG (statbuf.st_mode))
temp = cf_read_dir (path_ptr, depth);
else
{
- ERROR ("configfile: %s is neither a file nor a "
+ WARNING ("configfile: %s is neither a file nor a "
"directory.", path);
continue;
}
wordfree (&we);
+ if (root->children == NULL)
+ {
+ oconfig_free (root);
+ return (NULL);
+ }
+
return (root);
} /* oconfig_item_t *cf_read_generic */
/* #endif HAVE_WORDEXP_H */
/**
* collectd - src/contextswitch.c
* Copyright (C) 2009 Patrik Weiskircher
+ * Copyright (C) 2010 Kimo Rosenbaum
*
* 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
*
* Authors:
* Patrik Weiskircher <weiskircher at inqnet.at>
+ * Kimo Rosenbaum <http://github.com/kimor79>
**/
#include "collectd.h"
#include "common.h"
#include "plugin.h"
-#if !KERNEL_LINUX
+#ifdef HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+#endif
+
+#if HAVE_SYSCTLBYNAME
+/* no global variables */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif KERNEL_LINUX
+/* no global variables */
+/* #endif KERNEL_LINUX */
+
+#else
# error "No applicable input method."
#endif
static int cs_read (void)
{
+#if HAVE_SYSCTLBYNAME
+ int value = 0;
+ size_t value_len = sizeof (value);
+ int status;
+
+ status = sysctlbyname ("vm.stats.sys.v_swtch",
+ &value, &value_len,
+ /* new pointer = */ NULL, /* new length = */ 0);
+ if (status != 0)
+ {
+ ERROR("contextswitch plugin: sysctlbyname "
+ "(vm.stats.sys.v_swtch) failed");
+ return (-1);
+ }
+
+ cs_submit (value);
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif KERNEL_LINUX
FILE *fh;
char buffer[64];
int numfields;
if (status == -2)
ERROR ("contextswitch plugin: Unable to find context switch value.");
+#endif /* KERNEL_LINUX */
return status;
}
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "curl", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
/**
* collectd - src/curl_json.c
* Copyright (C) 2009 Doug MacEachern
- * Copyright (C) 2006-2009 Florian octo Forster
+ * Copyright (C) 2006-2010 Florian octo 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
return (0);
status = yajl_parse(db->yajl, (unsigned char *)buf, len);
- if (status == yajl_status_ok)
- {
- status = yajl_parse_complete(db->yajl);
- return (len);
- }
- else if (status == yajl_status_insufficient_data)
- return (len);
-
- if (status != yajl_status_ok)
+ if ((status != yajl_status_ok)
+ && (status != yajl_status_insufficient_data))
{
unsigned char *msg =
- yajl_get_error(db->yajl, 1, (unsigned char *)buf, len);
+ yajl_get_error(db->yajl, /* verbose = */ 1,
+ /* jsonText = */ (unsigned char *) buf, (unsigned int) len);
ERROR ("curl_json plugin: yajl_parse failed: %s", msg);
yajl_free_error(db->yajl, msg);
return (0); /* abort write callback */
}
/* yajl callbacks */
-static int cj_cb_integer (void *ctx, long val)
+#define CJ_CB_ABORT 0
+#define CJ_CB_CONTINUE 1
+
+/* "number" may not be null terminated, so copy it into a buffer before
+ * parsing. */
+static int cj_cb_number (void *ctx,
+ const char *number, unsigned int number_len)
{
+ char buffer[number_len + 1];
+
cj_t *db = (cj_t *)ctx;
cj_key_t *key = db->state[db->depth].key;
+ char *endptr;
+ value_t vt;
+ int type;
- if (key != NULL)
- {
- value_t vt;
- int type;
+ if (key == NULL)
+ return (CJ_CB_CONTINUE);
- type = cj_get_type (key);
- if (type == DS_TYPE_COUNTER)
- vt.counter = (counter_t) val;
- else if (type == DS_TYPE_GAUGE)
- vt.gauge = (gauge_t) val;
- else if (type == DS_TYPE_DERIVE)
- vt.derive = (derive_t) val;
- else if (type == DS_TYPE_ABSOLUTE)
- vt.absolute = (absolute_t) val;
- else
- return 0;
+ memcpy (buffer, number, number_len);
+ buffer[sizeof (buffer) - 1] = 0;
- cj_submit (db, key, &vt);
- }
- return 1;
-}
+ type = cj_get_type (key);
-static int cj_cb_double (void *ctx, double val)
-{
- cj_t *db = (cj_t *)ctx;
- cj_key_t *key = db->state[db->depth].key;
+ endptr = NULL;
+ errno = 0;
- if (key != NULL)
+ if (type == DS_TYPE_COUNTER)
+ vt.counter = (counter_t) strtoull (buffer, &endptr, /* base = */ 0);
+ else if (type == DS_TYPE_GAUGE)
+ vt.gauge = (gauge_t) strtod (buffer, &endptr);
+ else if (type == DS_TYPE_DERIVE)
+ vt.derive = (derive_t) strtoll (buffer, &endptr, /* base = */ 0);
+ else if (type == DS_TYPE_ABSOLUTE)
+ vt.absolute = (absolute_t) strtoull (buffer, &endptr, /* base = */ 0);
+ else
{
- value_t vt;
- int type;
-
- type = cj_get_type (key);
- if (type == DS_TYPE_COUNTER)
- vt.counter = (counter_t) val;
- else if (type == DS_TYPE_GAUGE)
- vt.gauge = (gauge_t) val;
- else if (type == DS_TYPE_DERIVE)
- vt.derive = (derive_t) val;
- else if (type == DS_TYPE_ABSOLUTE)
- vt.absolute = (absolute_t) val;
- else
- return 0;
+ ERROR ("curl_json plugin: Unknown data source type: \"%s\"", key->type);
+ return (CJ_CB_ABORT);
+ }
- cj_submit (db, key, &vt);
+ if ((endptr == &buffer[0]) || (errno != 0))
+ {
+ NOTICE ("curl_json plugin: Overflow while parsing number. "
+ "Ignoring this value.");
+ return (CJ_CB_CONTINUE);
}
- return 1;
-}
+
+ cj_submit (db, key, &vt);
+ return (CJ_CB_CONTINUE);
+} /* int cj_cb_number */
static int cj_cb_map_key (void *ctx, const unsigned char *val,
unsigned int len)
db->state[db->depth].key = NULL;
}
- return 1;
+ return (CJ_CB_CONTINUE);
}
static int cj_cb_string (void *ctx, const unsigned char *val,
char *ptr;
if (db->depth != 1) /* e.g. _all_dbs */
- return 1;
+ return (CJ_CB_CONTINUE);
cj_cb_map_key (ctx, val, len); /* same logic */
cj_curl_perform (db, curl);
curl_easy_cleanup (curl);
}
- return 1;
+ return (CJ_CB_CONTINUE);
}
static int cj_cb_start (void *ctx)
if (++db->depth >= YAJL_MAX_DEPTH)
{
ERROR ("curl_json plugin: %s depth exceeds max, aborting.", db->url);
- return 0;
+ return (CJ_CB_ABORT);
}
- return 1;
+ return (CJ_CB_CONTINUE);
}
static int cj_cb_end (void *ctx)
cj_t *db = (cj_t *)ctx;
db->state[db->depth].tree = NULL;
--db->depth;
- return 1;
+ return (CJ_CB_CONTINUE);
}
static int cj_cb_start_map (void *ctx)
static yajl_callbacks ycallbacks = {
NULL, /* null */
NULL, /* boolean */
- cj_cb_integer,
- cj_cb_double,
- NULL, /* number */
+ NULL, /* integer */
+ NULL, /* double */
+ cj_cb_number,
cj_cb_string,
cj_cb_start_map,
cj_cb_map_key,
}
status = curl_easy_perform (curl);
-
- yajl_free (db->yajl);
- db->yajl = yprev;
+ if (status != 0)
+ {
+ ERROR ("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)",
+ status, db->curl_errbuf, url);
+ yajl_free (db->yajl);
+ db->yajl = yprev;
+ return (-1);
+ }
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
- if (rc != 200)
+ /* The response code is zero if a non-HTTP transport was used. */
+ if ((rc != 0) && (rc != 200))
{
- ERROR ("curl_json plugin: curl_easy_perform failed with response code %ld (%s)",
- rc, url);
+ ERROR ("curl_json plugin: curl_easy_perform failed with "
+ "response code %ld (%s)", rc, url);
+ yajl_free (db->yajl);
+ db->yajl = yprev;
return (-1);
}
- if (status != 0)
+ status = yajl_parse_complete (db->yajl);
+ if (status != yajl_status_ok)
{
- ERROR ("curl_json plugin: curl_easy_perform failed with status %i: %s (%s)",
- status, db->curl_errbuf, url);
+ unsigned char *errmsg;
+
+ errmsg = yajl_get_error (db->yajl, /* verbose = */ 0,
+ /* jsonText = */ NULL, /* jsonTextLen = */ 0);
+ ERROR ("curl_json plugin: yajl_parse_complete failed: %s",
+ (char *) errmsg);
+ yajl_free_error (db->yajl, errmsg);
+ yajl_free (db->yajl);
+ db->yajl = yprev;
return (-1);
}
+ yajl_free (db->yajl);
+ db->yajl = yprev;
return (0);
} /* }}} int cj_curl_perform */
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Query", child->key) == 0)
udb_query_create (&queries, &queries_num, child,
- /* callback = */ NULL, /* legacy mode = */ 0);
+ /* callback = */ NULL);
else if (strcasecmp ("Database", child->key) == 0)
cdbi_config_add_database (child);
else
static ignorelist_t *il_mountpoint = NULL;
static ignorelist_t *il_fstype = NULL;
-static _Bool by_device = false;
-static _Bool report_inodes = false;
+static _Bool by_device = 0;
+static _Bool report_inodes = 0;
static int df_init (void)
{
else if (strcasecmp (key, "ReportByDevice") == 0)
{
if (IS_TRUE (value))
- by_device = true;
+ by_device = 1;
return (0);
}
else if (strcasecmp (key, "ReportInodes") == 0)
{
if (IS_TRUE (value))
- report_inodes = true;
+ report_inodes = 1;
else
- report_inodes = false;
+ report_inodes = 0;
return (0);
}
else if (vl->values_types[i] == LCC_TYPE_GAUGE)
{
if (isnan (vl->values[i].gauge))
- SSTRCPY (command, ":U");
+ SSTRCATF (command, ":U");
else
SSTRCATF (command, ":%g", vl->values[i].gauge);
}
lcc_identifier_t identifier;
};
typedef struct lcc_value_list_s lcc_value_list_t;
-#define LCC_VALUE_LIST_INIT { NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
+#define LCC_VALUE_LIST_INIT { NULL, NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
struct lcc_connection_s;
typedef struct lcc_connection_s lcc_connection_t;
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcachec", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, wp->instance, sizeof (vl.plugin_instance));
vl.values = values;
vl.values_len = 2;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
sstrncpy (vl.type, type, sizeof (vl.type));
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
sstrncpy (vl.type, type, sizeof (vl.type));
vl.values = values;
vl.values_len = 2;
- vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memcached", sizeof (vl.plugin));
sstrncpy (vl.type, type, sizeof (vl.type));
struct mysql_database_s /* {{{ */
{
- /* instance == NULL => legacy mode */
char *instance;
char *host;
char *user;
int err;
if ((err = mysql_ping (db->con)) != 0)
{
- WARNING ("mysql_ping failed for %s: %s",
- (db->instance != NULL)
- ? db->instance
- : "<legacy>",
+ /* Assured by "mysql_config_database" */
+ assert (db->instance != NULL);
+ WARNING ("mysql_ping failed for instance \"%s\": %s",
+ db->instance,
mysql_error (db->con));
db->state = 0;
}
static void set_host (mysql_database_t *db, char *buf, size_t buflen)
{
- /* XXX legacy mode - use hostname_g */
- if (db->instance == NULL)
+ if ((db->host == NULL)
+ || (strcmp ("", db->host) == 0)
+ || (strcmp ("localhost", db->host) == 0))
sstrncpy (buf, hostname_g, buflen);
else
- {
- if ((db->host == NULL)
- || (strcmp ("", db->host) == 0)
- || (strcmp ("localhost", db->host) == 0))
- sstrncpy (buf, hostname_g, buflen);
- else
- sstrncpy (buf, db->host, buflen);
- }
-}
-
-static void set_plugin_instance (mysql_database_t *db,
- char *buf, size_t buflen)
-{
- /* XXX legacy mode - no plugin_instance */
- if (db->instance == NULL)
- sstrncpy (buf, "", buflen);
- else
- sstrncpy (buf, db->instance, buflen);
-}
+ sstrncpy (buf, db->host, buflen);
+} /* void set_host */
static void submit (const char *type, const char *type_instance,
value_t *values, size_t values_len, mysql_database_t *db)
set_host (db, vl.host, sizeof (vl.host));
sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
- set_plugin_instance (db, vl.plugin_instance, sizeof (vl.plugin_instance));
+
+ /* Assured by "mysql_config_database" */
+ assert (db->instance != NULL);
+ sstrncpy (vl.plugin_instance, db->instance, sizeof (vl.plugin_instance));
sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
sql = row[SLAVE_SQL_RUNNING_IDX];
set_host (db, n.host, sizeof (n.host));
- set_plugin_instance (db,
- n.plugin_instance, sizeof (n.plugin_instance));
+
+ /* Assured by "mysql_config_database" */
+ assert (db->instance != NULL);
+ sstrncpy (n.plugin_instance, db->instance, sizeof (n.plugin_instance));
if (((io == NULL) || (strcasecmp (io, "yes") != 0))
&& (db->slave_io_running))
* Private variables
*/
static int network_config_ttl = 0;
-static size_t network_config_packet_size = 1024;
+static size_t network_config_packet_size = 1452;
static int network_config_forward = 0;
static int network_config_stats = 0;
/* This is a value we already sent. Don't allow it to be received again in
* order to avoid looping. */
if ((status == 0) && (time_sent >= ((uint64_t) vl->time)))
- return (false);
+ return (0);
- return (true);
+ return (1);
} /* }}} _Bool check_receive_okay */
static _Bool check_send_okay (const value_list_t *vl) /* {{{ */
{
- _Bool received = false;
+ _Bool received = 0;
int status;
if (network_config_forward != 0)
- return (true);
+ return (1);
if (vl->meta == NULL)
- return (true);
+ return (1);
status = meta_data_get_boolean (vl->meta, "network:received", &received);
if (status == -ENOENT)
- return (true);
+ return (1);
else if (status != 0)
{
ERROR ("network plugin: check_send_okay: meta_data_get_boolean failed "
"with status %i.", status);
- return (true);
+ return (1);
}
/* By default, only *send* value lists that were not *received* by the
return (-ENOMEM);
}
- status = meta_data_add_boolean (vl->meta, "network:received", true);
+ status = meta_data_add_boolean (vl->meta, "network:received", 1);
if (status != 0)
{
ERROR ("network plugin: meta_data_add_boolean failed.");
static int network_init (void)
{
- static _Bool have_init = false;
+ static _Bool have_init = 0;
/* Check if we were already initialized. If so, just return - there's
* nothing more to do (for now, that is). */
if (have_init)
return (0);
- have_init = true;
+ have_init = 1;
#if HAVE_LIBGCRYPT
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
static CURL *curl = NULL;
-#define ABUFFER_SIZE 16384
-static char nginx_buffer[ABUFFER_SIZE];
-static int nginx_buffer_len = 0;
-static char nginx_curl_error[CURL_ERROR_SIZE];
+static char nginx_buffer[16384];
+static size_t nginx_buffer_len = 0;
+static char nginx_curl_error[CURL_ERROR_SIZE];
static const char *config_keys[] =
{
{
size_t len = size * nmemb;
- if ((nginx_buffer_len + len) >= ABUFFER_SIZE)
+ /* Check if the data fits into the memory. If not, truncate it. */
+ if ((nginx_buffer_len + len) >= sizeof (nginx_buffer))
{
- len = (ABUFFER_SIZE - 1) - nginx_buffer_len;
+ assert (sizeof (nginx_buffer) > nginx_buffer_len);
+ len = (sizeof (nginx_buffer) - 1) - nginx_buffer_len;
}
if (len <= 0)
return (len);
- memcpy (nginx_buffer + nginx_buffer_len, (char *) buf, len);
+ memcpy (&nginx_buffer[nginx_buffer_len], buf, len);
nginx_buffer_len += len;
- nginx_buffer[nginx_buffer_len] = '\0';
+ nginx_buffer[nginx_buffer_len] = 0;
return (len);
}
oconfig_item_t *child = ci->children + i;
if (strcasecmp ("Query", child->key) == 0)
udb_query_create (&queries, &queries_num, child,
- /* callback = */ NULL, /* legacy mode = */ 0);
+ /* callback = */ NULL);
else if (strcasecmp ("Database", child->key) == 0)
o_config_add_database (child);
else
#include "configfile.h"
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
+
#include <EXTERN.h>
#include <perl.h>
static XS (Collectd_plugin_dispatch_values)
{
SV *values = NULL;
- int values_idx = 0;
int ret = 0;
dXSARGS;
- if (2 == items) {
- log_warn ("Collectd::plugin_dispatch_values with two arguments "
- "is deprecated - pass the type through values->{type}.");
- values_idx = 1;
- }
- else if (1 != items) {
+ if (1 != items) {
log_err ("Usage: Collectd::plugin_dispatch_values(values)");
XSRETURN_EMPTY;
}
log_debug ("Collectd::plugin_dispatch_values: values=\"%s\"",
- SvPV_nolen (ST (values_idx)));
+ SvPV_nolen (ST (/* stack index = */ 0)));
- values = ST (values_idx);
+ values = ST (/* stack index = */ 0);
+ /* Make sure the argument is a hash reference. */
if (! (SvROK (values) && (SVt_PVHV == SvTYPE (SvRV (values))))) {
log_err ("Collectd::plugin_dispatch_values: Invalid values.");
XSRETURN_EMPTY;
}
- if (((2 == items) && (NULL == ST (0))) || (NULL == values))
- XSRETURN_EMPTY;
-
- if ((2 == items) && (NULL == hv_store ((HV *)SvRV (values), "type", 4,
- newSVsv (ST (0)), 0))) {
- log_err ("Collectd::plugin_dispatch_values: Could not store type.");
+ if (NULL == values)
XSRETURN_EMPTY;
- }
ret = pplugin_dispatch_values (aTHX_ (HV *)SvRV (values));
if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0)
{
- INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type);
+ char ident[6 * DATA_MAX_NAME_LEN];
+
+ FORMAT_VL (ident, sizeof (ident), vl);
+ INFO ("plugin_dispatch_values: Dataset not found: %s "
+ "(from \"%s\"), check your types.db!",
+ vl->type, ident);
return (-1);
}
}
case NM_TYPE_BOOLEAN:
{
- meta->nm_value.nm_boolean = *((bool *) value);
+ meta->nm_value.nm_boolean = *((_Bool *) value);
break;
}
default:
int plugin_notification_meta_add_boolean (notification_t *n,
const char *name,
- bool value)
+ _Bool value)
{
return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
}
int64_t nm_signed_int;
uint64_t nm_unsigned_int;
double nm_double;
- bool nm_boolean;
+ _Bool nm_boolean;
} nm_value;
struct notification_meta_s *next;
} notification_meta_t;
double value);
int plugin_notification_meta_add_boolean (notification_t *n,
const char *name,
- bool value);
+ _Bool value);
int plugin_notification_meta_copy (notification_t *dst,
const notification_t *src);
if (0 == strcasecmp (c->key, "Query"))
udb_query_create (&queries, &queries_num, c,
- /* callback = */ config_query_callback,
- /* legacy mode = */ 1);
+ /* callback = */ config_query_callback);
else if (0 == strcasecmp (c->key, "Database"))
c_psql_config_database (c);
else
--- /dev/null
+/**
+ * collectd - src/redis.c, based on src/memcached.c
+ * Copyright (C) 2010 Andrés J. DÃaz <ajdiaz@connectical.com>
+ *
+ * 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; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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
+ *
+ * Authors:
+ * Andrés J. DÃaz <ajdiaz@connectical.com>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <pthread.h>
+#include <credis.h>
+
+#define REDIS_DEF_HOST "localhost"
+#define REDIS_DEF_PORT 6379
+#define REDIS_DEF_TIMEOUT 2000
+#define MAX_REDIS_NODE_NAME 64
+
+/* Redis plugin configuration example:
+ *
+ * <Plugin redis>
+ * <Node "mynode">
+ * Host "localhost"
+ * Port "6379"
+ * Timeout 2000
+ * </Node>
+ * </Plugin>
+ */
+
+struct redis_node_s;
+typedef struct redis_node_s redis_node_t;
+struct redis_node_s
+{
+ char name[MAX_REDIS_NODE_NAME];
+ char host[HOST_NAME_MAX];
+ int port;
+ int timeout;
+
+ redis_node_t *next;
+};
+
+static redis_node_t *nodes_head = NULL;
+
+static int redis_node_add (const redis_node_t *rn) /* {{{ */
+{
+ redis_node_t *rn_copy;
+ redis_node_t *rn_ptr;
+
+ /* Check for duplicates first */
+ for (rn_ptr = nodes_head; rn_ptr != NULL; rn_ptr = rn_ptr->next)
+ if (strcmp (rn->name, rn_ptr->name) == 0)
+ break;
+
+ if (rn_ptr != NULL)
+ {
+ ERROR ("redis plugin: A node with the name `%s' already exists.",
+ rn->name);
+ return (-1);
+ }
+
+ rn_copy = malloc (sizeof (*rn_copy));
+ if (rn_copy == NULL)
+ {
+ ERROR ("redis plugin: malloc failed adding redis_node to the tree.");
+ return (-1);
+ }
+
+ memcpy (rn_copy, rn, sizeof (*rn_copy));
+ rn_copy->next = NULL;
+
+ DEBUG ("redis plugin: Adding node \"%s\".", rn->name);
+
+ if (nodes_head == NULL)
+ nodes_head = rn_copy;
+ else
+ {
+ rn_ptr = nodes_head;
+ while (rn_ptr->next != NULL)
+ rn_ptr = rn_ptr->next;
+ rn_ptr->next = rn_copy;
+ }
+
+ return (0);
+} /* }}} */
+
+static int redis_config_node (oconfig_item_t *ci) /* {{{ */
+{
+ redis_node_t rn;
+ int i;
+ int status;
+
+ memset (&rn, 0, sizeof (rn));
+ sstrncpy (rn.host, REDIS_DEF_HOST, sizeof (rn.host));
+ rn.port = REDIS_DEF_PORT;
+ rn.timeout = REDIS_DEF_TIMEOUT;
+
+ status = cf_util_get_string_buffer (ci, rn.name, sizeof (rn.name));
+ if (status != 0)
+ return (status);
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+
+ if (strcasecmp ("Host", option->key) == 0)
+ status = cf_util_get_string_buffer (option, rn.host, sizeof (rn.host));
+ else if (strcasecmp ("Port", option->key) == 0)
+ {
+ status = cf_util_get_port_number (option);
+ if (status > 0)
+ {
+ rn.port = status;
+ status = 0;
+ }
+ }
+ else if (strcasecmp ("Timeout", option->key) == 0)
+ status = cf_util_get_int (option, &rn.timeout);
+ else
+ WARNING ("redis plugin: Option `%s' not allowed inside a `Node' "
+ "block. I'll ignore this option.", option->key);
+
+ if (status != 0)
+ break;
+ }
+
+ if (status != 0)
+ return (status);
+
+ return (redis_node_add (&rn));
+} /* }}} int redis_config_node */
+
+static int redis_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+
+ if (strcasecmp ("Node", option->key) == 0)
+ redis_config_node (option);
+ else
+ WARNING ("redis plugin: Option `%s' not allowed in redis"
+ " configuration. It will be ignored.", option->key);
+ }
+
+ if (nodes_head == NULL)
+ {
+ ERROR ("redis plugin: No valid node configuration could be found.");
+ return (ENOENT);
+ }
+
+ return (0);
+} /* }}} */
+
+ __attribute__ ((nonnull(2)))
+static void redis_submit_g (char *plugin_instance,
+ const char *type, const char *type_instance,
+ gauge_t value) /* {{{ */
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "redis", sizeof (vl.plugin));
+ if (plugin_instance != NULL)
+ sstrncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_instance != NULL)
+ sstrncpy (vl.type_instance, type_instance,
+ sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* }}} */
+
+ __attribute__ ((nonnull(2)))
+static void redis_submit_c (char *plugin_instance,
+ const char *type, const char *type_instance,
+ counter_t value) /* {{{ */
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].counter = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "redis", sizeof (vl.plugin));
+ if (plugin_instance != NULL)
+ sstrncpy (vl.plugin_instance, plugin_instance,
+ sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_instance != NULL)
+ sstrncpy (vl.type_instance, type_instance,
+ sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* }}} */
+
+static int redis_init (void) /* {{{ */
+{
+ redis_node_t rn = { "default", REDIS_DEF_HOST, REDIS_DEF_PORT,
+ REDIS_DEF_TIMEOUT, /* next = */ NULL };
+
+ if (nodes_head == NULL)
+ redis_node_add (&rn);
+
+ return (0);
+} /* }}} int redis_init */
+
+static int redis_read (void) /* {{{ */
+{
+ redis_node_t *rn;
+
+ for (rn = nodes_head; rn != NULL; rn = rn->next)
+ {
+ REDIS rh;
+ REDIS_INFO info;
+
+ int status;
+
+ DEBUG ("redis plugin: querying info from node `%s' (%s:%d).", rn->name, rn->host, rn->port);
+
+ rh = credis_connect (rn->host, rn->port, rn->timeout);
+ if (rh == NULL)
+ {
+ ERROR ("redis plugin: unable to connect to node `%s' (%s:%d).", rn->name, rn->host, rn->port);
+ continue;
+ }
+
+ memset (&info, 0, sizeof (info));
+ status = credis_info (rh, &info);
+ if (status != 0)
+ {
+ WARNING ("redis plugin: unable to get info from node `%s'.", rn->name);
+ credis_close (rh);
+ continue;
+ }
+
+ /* typedef struct _cr_info {
+ * char redis_version[CREDIS_VERSION_STRING_SIZE];
+ * int bgsave_in_progress;
+ * int connected_clients;
+ * int connected_slaves;
+ * unsigned int used_memory;
+ * long long changes_since_last_save;
+ * int last_save_time;
+ * long long total_connections_received;
+ * long long total_commands_processed;
+ * int uptime_in_seconds;
+ * int uptime_in_days;
+ * int role;
+ * } REDIS_INFO; */
+
+ DEBUG ("redis plugin: received info from node `%s': connected_clients = %d; "
+ "connected_slaves = %d; used_memory = %lu; changes_since_last_save = %lld; "
+ "bgsave_in_progress = %d; total_connections_received = %lld; "
+ "total_commands_processed = %lld; uptime_in_seconds = %ld", rn->name,
+ info.connected_clients, info.connected_slaves, info.used_memory,
+ info.changes_since_last_save, info.bgsave_in_progress,
+ info.total_connections_received, info.total_commands_processed,
+ info.uptime_in_seconds);
+
+ redis_submit_g (rn->name, "current_connections", "clients", info.connected_clients);
+ redis_submit_g (rn->name, "current_connections", "slaves", info.connected_slaves);
+ redis_submit_g (rn->name, "memory", "used", info.used_memory);
+ redis_submit_g (rn->name, "volatile_changes", NULL, info.changes_since_last_save);
+ redis_submit_c (rn->name, "total_connections", NULL, info.total_connections_received);
+ redis_submit_c (rn->name, "total_operations", NULL, info.total_commands_processed);
+
+ credis_close (rh);
+ }
+
+ return 0;
+}
+/* }}} */
+
+void module_register (void) /* {{{ */
+{
+ plugin_register_complex_config ("redis", redis_config);
+ plugin_register_init ("redis", redis_init);
+ plugin_register_read ("redis", redis_read);
+ /* TODO: plugin_register_write: one redis list per value id with
+ * X elements */
+}
+/* }}} */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
pthread_mutex_lock (&queue_lock);
/* Wait for values to arrive */
- while (true)
+ while (42)
{
struct timespec ts_wait;
&ts_wait);
if (status == ETIMEDOUT)
break;
- } /* while (true) */
+ } /* while (42) */
/* XXX: If you need to lock both, cache_lock and queue_lock, at
* the same time, ALWAYS lock `cache_lock' first! */
values[0].gauge = value;
- vl.time = time (NULL);
vl.values = values;
vl.values_len = 1;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
cpufreq value:GAUGE:0:U
cpu value:COUNTER:0:4294967295
current value:GAUGE:U:U
+current_connections value:GAUGE:0:U
+current_sessions value:GAUGE:0:U
delay seconds:GAUGE:-1000000:1000000
derive value:DERIVE:0:U
df used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
mysql_locks value:COUNTER:0:U
mysql_log_position value:COUNTER:0:4294967295
mysql_octets rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
-mysql_qcache hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U
-mysql_threads running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U
nfs_procedure value:COUNTER:0:4294967295
nginx_connections value:GAUGE:0:U
nginx_requests value:COUNTER:0:134217728
timeleft timeleft:GAUGE:0:3600
time_offset seconds:GAUGE:-1000000:1000000
total_bytes value:DERIVE:0:U
+total_connections value:DERIVE:0:U
total_operations value:DERIVE:0:U
total_requests value:DERIVE:0:U
total_sessions value:DERIVE:0:U
vmpage_faults minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807
vmpage_io in:COUNTER:0:4294967295, out:COUNTER:0:4294967295
vmpage_number value:GAUGE:0:4294967295
+volatile_changes value:GAUGE:0:U
voltage_threshold value:GAUGE:U:U, threshold:GAUGE:U:U
voltage value:GAUGE:U:U
vs_memory value:GAUGE:0:9223372036854775807
char **values;
size_t values_num;
- /* Legacy data */
- int legacy_mode;
- size_t legacy_position;
- /* When in legacy mode:
- * - type/ds hold the format of the data
- * - instance_prefix is used as type-instance if non-NULL
- * - legacy_position holds the index of the column to use as value.
- */
-
udb_result_t *next;
}; /* }}} */
char *statement;
void *user_data;
- int legacy_mode;
-
unsigned int min_version;
unsigned int max_version;
} /* }}} int udb_config_set_uint */
/*
- * Legacy result private functions
- */
-static void udb_legacy_result_finish_result (const udb_result_t const *r, /* {{{ */
- udb_result_preparation_area_t *prep_area)
-{
- if ((r == NULL) || (prep_area))
- return;
-
- assert (r->legacy_mode == 1);
-
- prep_area->ds = NULL;
-} /* }}} void udb_legacy_result_finish_result */
-
-static int udb_legacy_result_handle_result (udb_result_t *r, /* {{{ */
- udb_query_preparation_area_t *q_area,
- udb_result_preparation_area_t *r_area,
- const udb_query_t const *q, char **column_values)
-{
- value_list_t vl = VALUE_LIST_INIT;
- value_t value;
- char *value_str;
-
- assert (r->legacy_mode == 1);
- assert (r_area->ds != NULL);
- assert (r_area->ds->ds_num == 1);
-
- vl.values = &value;
- vl.values_len = 1;
-
- value_str = column_values[r->legacy_position];
- if (0 != parse_value (value_str, &vl.values[0], r_area->ds->ds[0].type))
- {
- ERROR ("db query utils: udb_legacy_result_handle_result: "
- "Parsing `%s' as %s failed.", value_str,
- DS_TYPE_TO_STRING (r_area->ds->ds[0].type));
- errno = EINVAL;
- return (-1);
- }
-
- if (q_area->interval > 0)
- vl.interval = q_area->interval;
-
- sstrncpy (vl.host, q_area->host, sizeof (vl.host));
- sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.type_instance));
- sstrncpy (vl.type, r->type, sizeof (vl.type));
-
- if (r->instance_prefix != NULL)
- sstrncpy (vl.type_instance, r->instance_prefix,
- sizeof (vl.type_instance));
-
- plugin_dispatch_values (&vl);
-
- return (0);
-} /* }}} int udb_legacy_result_handle_result */
-
-static int udb_legacy_result_prepare_result (const udb_result_t const *r, /* {{{ */
- udb_result_preparation_area_t *prep_area,
- char **column_names, size_t column_num)
-{
- if (r == NULL)
- return (-EINVAL);
-
- assert (r->legacy_mode == 1);
-
- /* Make sure previous preparations are cleaned up. */
- udb_legacy_result_finish_result (r, prep_area);
-
- if (r->legacy_position >= column_num)
- {
- ERROR ("db query utils: The legacy configuration specified (at least) "
- "%zu `Column's, but the query returned only %zu columns!",
- r->legacy_position + 1, column_num);
- return (-ENOENT);
- }
-
- /* Read `ds' and check number of values {{{ */
- prep_area->ds = plugin_get_ds (r->type);
- if (prep_area->ds == NULL)
- {
- ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not "
- "known by the daemon. See types.db(5) for details.",
- r->type);
- return (-1);
- }
-
- if (prep_area->ds->ds_num != 1)
- {
- ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
- "requires exactly %i values, but the legacy configuration "
- "requires exactly one!",
- r->type,
- prep_area->ds->ds_num);
- return (-1);
- }
- /* }}} */
-
- return (0);
-} /* }}} int udb_legacy_result_prepare_result */
-
-static int udb_legacy_result_create (const char *query_name, /* {{{ */
- udb_result_t **r_head, oconfig_item_t *ci, size_t position)
-{
- udb_result_t *r;
-
- if ((ci->values_num < 1) || (ci->values_num > 2)
- || (ci->values[0].type != OCONFIG_TYPE_STRING)
- || ((ci->values_num == 2)
- && (ci->values[1].type != OCONFIG_TYPE_STRING)))
- {
- WARNING ("db query utils: The `Column' block needs either one or two "
- "string arguments.");
- return (-1);
- }
-
- r = (udb_result_t *) malloc (sizeof (*r));
- if (r == NULL)
- {
- ERROR ("db query utils: malloc failed.");
- return (-1);
- }
- memset (r, 0, sizeof (*r));
-
- r->legacy_mode = 1;
- r->legacy_position = position;
-
- r->type = strdup (ci->values[0].value.string);
- if (r->type == NULL)
- {
- ERROR ("db query utils: strdup failed.");
- free (r);
- return (-1);
- }
-
- r->instance_prefix = NULL;
- if (ci->values_num == 2)
- {
- r->instance_prefix = strdup (ci->values[1].value.string);
- if (r->instance_prefix == NULL)
- {
- ERROR ("db query utils: strdup failed.");
- free (r->type);
- free (r);
- return (-1);
- }
- }
-
- /* If all went well, add this result to the list of results. */
- if (*r_head == NULL)
- {
- *r_head = r;
- }
- else
- {
- udb_result_t *last;
-
- last = *r_head;
- while (last->next != NULL)
- last = last->next;
-
- last->next = r;
- }
-
- return (0);
-} /* }}} int udb_legacy_result_create */
-
-/*
* Result private functions
*/
static int udb_result_submit (udb_result_t *r, /* {{{ */
size_t i;
assert (r != NULL);
- assert (r->legacy_mode == 0);
assert (r_area->ds != NULL);
assert (((size_t) r_area->ds->ds_num) == r->values_num);
if ((r == NULL) || (prep_area == NULL))
return;
- if (r->legacy_mode == 1)
- {
- udb_legacy_result_finish_result (r, prep_area);
- return;
- }
-
- assert (r->legacy_mode == 0);
-
prep_area->ds = NULL;
sfree (prep_area->instances_pos);
sfree (prep_area->values_pos);
assert (r && q_area && r_area);
- if (r->legacy_mode == 1)
- return (udb_legacy_result_handle_result (r, q_area, r_area,
- q, column_values));
-
- assert (r->legacy_mode == 0);
-
for (i = 0; i < r->instances_num; i++)
r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
if ((r == NULL) || (prep_area == NULL))
return (-EINVAL);
- if (r->legacy_mode == 1)
- return (udb_legacy_result_prepare_result (r, prep_area,
- column_names, column_num));
-
- assert (r->legacy_mode == 0);
-
#define BAIL_OUT(status) \
prep_area->ds = NULL; \
sfree (prep_area->instances_pos); \
*/
int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
size_t *ret_query_list_len, oconfig_item_t *ci,
- udb_query_create_callback_t cb, int legacy_mode)
+ udb_query_create_callback_t cb)
{
udb_query_t **query_list;
size_t query_list_len;
int status;
int i;
- size_t legacy_position;
-
if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
return (-EINVAL);
query_list = *ret_query_list;
return (-1);
}
memset (q, 0, sizeof (*q));
- q->legacy_mode = legacy_mode;
q->min_version = 0;
q->max_version = UINT_MAX;
- legacy_position = 0;
-
status = udb_config_set_string (&q->name, ci);
if (status != 0)
{
else if (strcasecmp ("MaxVersion", child->key) == 0)
status = udb_config_set_uint (&q->max_version, child);
- /* PostgreSQL compatibility code */
- else if ((strcasecmp ("Query", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `Query' option is "
- "deprecated. Please use `Statement' instead.",
- q->name);
- status = udb_config_set_string (&q->statement, child);
- }
- else if ((strcasecmp ("Column", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `Column' option is "
- "deprecated. Please use the new syntax instead.",
- q->name);
- status = udb_legacy_result_create (q->name, &q->results, child,
- legacy_position);
- legacy_position++;
- }
- else if ((strcasecmp ("MinPGVersion", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `MinPGVersion' option is "
- "deprecated. Please use `MinVersion' instead.",
- q->name);
- status = udb_config_set_uint (&q->min_version, child);
- }
- else if ((strcasecmp ("MaxPGVersion", child->key) == 0)
- && (q->legacy_mode == 1))
- {
- WARNING ("db query utils: Query `%s': The `MaxPGVersion' option is "
- "deprecated. Please use `MaxVersion' instead.",
- q->name);
- status = udb_config_set_uint (&q->max_version, child);
- }
-
/* Call custom callbacks */
else if (cb != NULL)
{
*/
int udb_query_create (udb_query_t ***ret_query_list,
size_t *ret_query_list_len, oconfig_item_t *ci,
- udb_query_create_callback_t cb, int legacy_mode);
+ udb_query_create_callback_t cb);
void udb_query_free (udb_query_t **query_list, size_t query_list_len);
int udb_query_pick_from_list_by_name (const char *name,
return;
if (dir == DIR_UP)
- reheap (h, root / 2, dir);
+ reheap (h, (root - 1) / 2, dir);
else if (dir == DIR_DOWN)
reheap (h, min, dir);
} /* void reheap */
int c_heap_insert (c_heap_t *h, void *ptr)
{
+ size_t index;
+
if ((h == NULL) || (ptr == NULL))
return (-EINVAL);
}
/* Insert the new node as a leaf. */
- h->list[h->list_len] = ptr;
+ index = h->list_len;
+ h->list[index] = ptr;
h->list_len++;
/* Reorganize the heap from bottom up. */
- reheap (h, /* parent of this node = */ (h->list_len - 1) / 2, DIR_UP);
+ reheap (h, /* parent of this node = */ (index - 1) / 2, DIR_UP);
pthread_mutex_unlock (&h->lock);
return (0);
if (matches_num < 2)
return (-1);
- value = strtod (matches[1], &endptr);
+ value = (gauge_t) strtod (matches[1], &endptr);
if (matches[1] == endptr)
return (-1);
if (matches_num < 2)
return (-1);
- value = strtoll (matches[1], &endptr, 0);
+ value = (counter_t) strtoull (matches[1], &endptr, 0);
if (matches[1] == endptr)
return (-1);
if (matches_num < 2)
return (-1);
- value = strtoll (matches[1], &endptr, 0);
+ value = (derive_t) strtoll (matches[1], &endptr, 0);
if (matches[1] == endptr)
return (-1);
if (matches_num < 2)
return (-1);
- value = strtoll (matches[1], &endptr, 0);
+ value = (absolute_t) strtoull (matches[1], &endptr, 0);
if (matches[1] == endptr)
return (-1);
/*
* Defines
*/
-#define UTILS_MATCH_DS_TYPE_GAUGE 0x10
-#define UTILS_MATCH_DS_TYPE_COUNTER 0x20
-#define UTILS_MATCH_DS_TYPE_DERIVE 0x30
-#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x40
+#define UTILS_MATCH_DS_TYPE_GAUGE 0x10
+#define UTILS_MATCH_DS_TYPE_COUNTER 0x20
+#define UTILS_MATCH_DS_TYPE_DERIVE 0x40
+#define UTILS_MATCH_DS_TYPE_ABSOLUTE 0x80
#define UTILS_MATCH_CF_GAUGE_AVERAGE 0x01
#define UTILS_MATCH_CF_GAUGE_MIN 0x02
--- /dev/null
+/**
+ * collectd - src/write_redis.c
+ * Copyright (C) 2010 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <ff at octo.it>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+#include "configfile.h"
+
+#include <pthread.h>
+#include <credis.h>
+
+struct wr_node_s
+{
+ char name[DATA_MAX_NAME_LEN];
+
+ char *host;
+ int port;
+ int timeout;
+
+ REDIS conn;
+ pthread_mutex_t lock;
+};
+typedef struct wr_node_s wr_node_t;
+
+/*
+ * Functions
+ */
+static int wr_write (const data_set_t *ds, /* {{{ */
+ const value_list_t *vl,
+ user_data_t *ud)
+{
+ wr_node_t *node = ud->data;
+ char ident[512];
+ char key[512];
+ char value[512];
+ size_t value_size;
+ char *value_ptr;
+ int status;
+ int i;
+
+ status = FORMAT_VL (ident, sizeof (ident), vl);
+ if (status != 0)
+ return (status);
+ ssnprintf (key, sizeof (key), "collectd/%s", ident);
+
+ memset (value, 0, sizeof (value));
+ value_size = sizeof (value);
+ value_ptr = &value[0];
+
+#define APPEND(...) do { \
+ status = snprintf (value_ptr, value_size, __VA_ARGS__); \
+ if (((size_t) status) > value_size) \
+ { \
+ value_ptr += value_size; \
+ value_size = 0; \
+ } \
+ else \
+ { \
+ value_ptr += status; \
+ value_size -= status; \
+ } \
+} while (0)
+
+ APPEND ("%lu", (unsigned long) vl->time);
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ if (ds->ds[i].type == DS_TYPE_COUNTER)
+ APPEND ("%llu", vl->values[i].counter);
+ else if (ds->ds[i].type == DS_TYPE_GAUGE)
+ APPEND ("%g", vl->values[i].gauge);
+ else if (ds->ds[i].type == DS_TYPE_DERIVE)
+ APPEND ("%"PRIi64, vl->values[i].derive);
+ else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
+ APPEND ("%"PRIu64, vl->values[i].absolute);
+ else
+ assert (23 == 42);
+ }
+
+#undef APPEND
+
+ pthread_mutex_lock (&node->lock);
+
+ if (node->conn == NULL)
+ {
+ node->conn = credis_connect (node->host, node->port, node->timeout);
+ if (node->conn == NULL)
+ {
+ ERROR ("write_redis plugin: Connecting to host \"%s\" (port %i) failed.",
+ (node->host != NULL) ? node->host : "localhost",
+ (node->port != 0) ? node->port : 6379);
+ pthread_mutex_unlock (&node->lock);
+ return (-1);
+ }
+ }
+
+ /* "credis_zadd" doesn't handle a NULL pointer gracefully, so I'd rather
+ * have a meaningful assertion message than a normal segmentation fault. */
+ assert (node->conn != NULL);
+ status = credis_zadd (node->conn, key, (double) vl->time, value);
+
+ credis_sadd (node->conn, "collectd/values", ident);
+
+ pthread_mutex_unlock (&node->lock);
+
+ return (0);
+} /* }}} int wr_write */
+
+static void wr_config_free (void *ptr) /* {{{ */
+{
+ wr_node_t *node = ptr;
+
+ if (node == NULL)
+ return;
+
+ if (node->conn != NULL)
+ {
+ credis_close (node->conn);
+ node->conn = NULL;
+ }
+
+ sfree (node->host);
+ sfree (node);
+} /* }}} void wr_config_free */
+
+static int wr_config_node (oconfig_item_t *ci) /* {{{ */
+{
+ wr_node_t *node;
+ int status;
+ int i;
+
+ node = malloc (sizeof (*node));
+ if (node == NULL)
+ return (ENOMEM);
+ memset (node, 0, sizeof (*node));
+ node->host = NULL;
+ node->port = 0;
+ node->timeout = 1000;
+ node->conn = NULL;
+ pthread_mutex_init (&node->lock, /* attr = */ NULL);
+
+ status = cf_util_get_string_buffer (ci, node->name, sizeof (node->name));
+ if (status != 0)
+ {
+ sfree (node);
+ return (status);
+ }
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Host", child->key) == 0)
+ status = cf_util_get_string (child, &node->host);
+ else if (strcasecmp ("Port", child->key) == 0)
+ {
+ status = cf_util_get_port_number (child);
+ if (status > 0)
+ {
+ node->port = status;
+ status = 0;
+ }
+ }
+ else if (strcasecmp ("Timeout", child->key) == 0)
+ status = cf_util_get_int (child, &node->timeout);
+ else
+ WARNING ("write_redis plugin: Ignoring unknown config option \"%s\".",
+ child->key);
+
+ if (status != 0)
+ break;
+ } /* for (i = 0; i < ci->children_num; i++) */
+
+ if (status == 0)
+ {
+ char cb_name[DATA_MAX_NAME_LEN];
+ user_data_t ud;
+
+ ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name);
+
+ ud.data = node;
+ ud.free_func = wr_config_free;
+
+ status = plugin_register_write (cb_name, wr_write, &ud);
+ }
+
+ if (status != 0)
+ wr_config_free (node);
+
+ return (status);
+} /* }}} int wr_config_node */
+
+static int wr_config (oconfig_item_t *ci) /* {{{ */
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Node", child->key) == 0)
+ wr_config_node (child);
+ else
+ WARNING ("write_redis plugin: Ignoring unknown "
+ "configuration option \"%s\" at top level.", child->key);
+ }
+
+ return (0);
+} /* }}} int wr_config */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("write_redis", wr_config);
+}
+
+/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */