of these callback functions and initializing code which registers the
functions with collectd. See the section "EXAMPLES" below for a really basic
example. The following types of B<callback functions> are known to collectd
- (all of these are optional):
+ (all of them are optional):
=over 4
This type of function is used to write the dispatched values. It is called
once for each call to B<plugin_dispatch_values>.
+ =item flush functions
+
+ This type of function is used to flush internal caches of plugins. It is
+ usually triggered by the user only. Any plugin which caches data before
+ writing it to disk should provide this kind of callback function.
+
=item log functions
This type of function is used to pass messages of plugins or the daemon itself
time => time (),
host => $hostname_g,
plugin => 'myplugin',
+ type => 'myplugin',
plugin_instance => '',
type_instance => ''
}
=item TYPE_WRITE
+ =item TYPE_FLUSH
+
=item TYPE_LOG
=item TYPE_NOTIF
=item TYPE_SHUTDOWN
- No arguments are passed
+ No arguments are passed.
=item TYPE_WRITE
The arguments passed are I<type>, I<data-set>, and I<value-list>. I<type> is a
string. For the layout of I<data-set> and I<value-list> see above.
+ =item TYPE_FLUSH
+
+ The only argument passed is I<timeout> which indicates that only data older
+ than I<timeout> seconds is to be flushed.
+
=item TYPE_LOG
The arguments are I<log-level> and I<message>. The log level is small for
Removes a callback or data-set from collectd's internal list of
functionsE<nbsp>/ datasets.
-=item B<plugin_dispatch_values> (I<type>, I<value-list>)
+=item B<plugin_dispatch_values> (I<value-list>)
-Submits a I<value-list> of type I<type> to the daemon. If the data-set I<type>
+Submits a I<value-list> to the daemon. If the data-set identified by
+I<value-list>->{I<type>}
is found (and the number of values matches the number of data-sources) then the
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_flush> ([B<timeout> => I<timeout>,] [B<plugins> => I<...>])
+
+ Flush one or more plugins. I<timeout> is passed on to the registered
+ flush-callbacks. If omitted, C<-1> is used. If the I<plugins> argument has
+ been specified, only named plugins will be flushed. The argument's value 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>".
+
+ =item B<plugin_flush_all> (I<timeout>)
+
+ This is identical to using "plugin_flush (timeout =E<gt> I<timeout>)".
+
=item B<plugin_dispatch_notification> (I<notification>)
Submits a I<notification> to the daemon which will then pass it to all
=item B<plugin_dispatch_values> ()
+ =item B<plugin_flush> ()
+
+ =item B<plugin_flush_one> ()
+
+ =item B<plugin_flush_all> ()
+
=item B<plugin_dispatch_notification> ()
=item B<plugin_log> ()
=item B<TYPE_WRITE>
+ =item B<TYPE_FLUSH>
+
=item B<TYPE_SHUTDOWN>
=item B<TYPE_LOG>
=back
+ =head1 KNOWN BUGS
+
+ =over 4
+
+ =item
+
+ Currently, it is not possible to flush a single Perl plugin only. You can
+ either flush all Perl plugins or none at all and you have to use C<perl> as
+ plugin name when doing so.
+
+ =back
+
=head1 SEE ALSO
L<collectd(1)>,
#include "plugin.h"
#include "configfile.h"
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
+
/*
* Global variables
*/
str = global_option_get ("Hostname");
if (str != NULL)
{
- strncpy (hostname_g, str, sizeof (hostname_g));
- hostname_g[sizeof (hostname_g) - 1] = '\0';
+ sstrncpy (hostname_g, str, sizeof (hostname_g));
return (0);
}
if (ai_ptr->ai_canonname == NULL)
continue;
- strncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
- hostname_g[sizeof (hostname_g) - 1] = '\0';
+ sstrncpy (hostname_g, ai_ptr->ai_canonname, sizeof (hostname_g));
break;
}
/**
* collectd - src/email.c
- * Copyright (C) 2006,2007 Sebastian Harl
+ * Copyright (C) 2006-2008 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
# include <grp.h>
#endif /* HAVE_GRP_H */
- #define MODULE_NAME "email"
-
- /* 256 bytes ought to be enough for anybody ;-) */
- #define BUFSIZE 256
-
#define SOCK_PATH LOCALSTATEDIR"/run/"PACKAGE_NAME"-email"
#define MAX_CONNS 5
#define MAX_CONNS_LIMIT 16384
- #define log_err(...) ERROR (MODULE_NAME": "__VA_ARGS__)
- #define log_warn(...) WARNING (MODULE_NAME": "__VA_ARGS__)
+ #define log_debug(...) DEBUG ("email: "__VA_ARGS__)
+ #define log_err(...) ERROR ("email: "__VA_ARGS__)
+ #define log_warn(...) WARNING ("email: "__VA_ARGS__)
/*
* Private data structures
pthread_t thread;
/* socket descriptor of the current/last connection */
- int socket;
+ FILE *socket;
} collector_t;
/* linked list of pending connections */
typedef struct conn {
/* socket to read data from */
- int socket;
-
- /* buffer to read data to */
- char *buffer;
- int idx; /* current write position in buffer */
- int length; /* length of the current line, i.e. index of '\0' */
+ FILE *socket;
+ /* linked list of connections */
struct conn *next;
} conn_t;
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
/* socket configuration */
- static char *sock_file = SOCK_PATH;
- static char *sock_group = COLLECTD_GRP_NAME;
+ static char *sock_file = NULL;
+ static char *sock_group = NULL;
static int sock_perms = S_IRWXU | S_IRWXG;
static int max_conns = MAX_CONNS;
static int available_collectors;
static pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
- static type_list_t count;
+ static type_list_t list_count;
+ static type_list_t list_count_copy;
static pthread_mutex_t size_mutex = PTHREAD_MUTEX_INITIALIZER;
- static type_list_t size;
+ static type_list_t list_size;
+ static type_list_t list_size_copy;
static pthread_mutex_t score_mutex = PTHREAD_MUTEX_INITIALIZER;
static double score;
static int score_count;
static pthread_mutex_t check_mutex = PTHREAD_MUTEX_INITIALIZER;
- static type_list_t check;
+ static type_list_t list_check;
+ static type_list_t list_check_copy;
/*
* Private functions
static int email_config (const char *key, const char *value)
{
if (0 == strcasecmp (key, "SocketFile")) {
+ if (NULL != sock_file)
+ free (sock_file);
sock_file = sstrdup (value);
}
else if (0 == strcasecmp (key, "SocketGroup")) {
+ if (NULL != sock_group)
+ free (sock_group);
sock_group = sstrdup (value);
}
else if (0 == strcasecmp (key, "SocketPerms")) {
return;
} /* static void type_list_incr (type_list_t *, char *) */
- /* Read a single character from the socket. If an error occurs or end-of-file
- * is reached return '\0'. */
- static char read_char (conn_t *src)
- {
- char ret = '\0';
-
- fd_set fdset;
-
- FD_ZERO (&fdset);
- FD_SET (src->socket, &fdset);
-
- if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
- char errbuf[1024];
- log_err ("select() failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return '\0';
- }
-
- assert (FD_ISSET (src->socket, &fdset));
-
- do {
- ssize_t len = 0;
-
- errno = 0;
- if (0 > (len = read (src->socket, (void *)&ret, 1))) {
- if (EINTR != errno) {
- char errbuf[1024];
- log_err ("read() failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return '\0';
- }
- }
-
- if (0 == len)
- return '\0';
- } while (EINTR == errno);
- return ret;
- } /* static char read_char (conn_t *) */
-
- /* Read a single line (terminated by '\n') from the the socket.
- *
- * The return value is zero terminated and does not contain any newline
- * characters.
- *
- * If an error occurs or end-of-file is reached return NULL.
- *
- * IMPORTANT NOTE: If there is no newline character found in BUFSIZE
- * characters of the input stream, the line will will be ignored! By
- * definition we should not get any longer input lines, thus this is
- * acceptable in this case ;-) */
- static char *read_line (conn_t *src)
- {
- int i = 0;
-
- assert ((BUFSIZE >= src->idx) && (src->idx >= 0));
- assert ((src->idx > src->length) || (src->length == 0));
-
- if (src->length > 0) { /* remove old line */
- src->idx -= (src->length + 1);
- memmove (src->buffer, src->buffer + src->length + 1, src->idx);
- src->length = 0;
- }
-
- for (i = 0; i < src->idx; ++i) {
- if ('\n' == src->buffer[i])
- break;
- }
-
- if (i == src->idx) {
- fd_set fdset;
-
- ssize_t len = 0;
-
- FD_ZERO (&fdset);
- FD_SET (src->socket, &fdset);
-
- if (-1 == select (src->socket + 1, &fdset, NULL, NULL, NULL)) {
- char errbuf[1024];
- log_err ("select() failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return NULL;
- }
-
- assert (FD_ISSET (src->socket, &fdset));
-
- do {
- errno = 0;
- if (0 > (len = read (src->socket,
- (void *)(src->buffer + src->idx),
- BUFSIZE - src->idx))) {
- if (EINTR != errno) {
- char errbuf[1024];
- log_err ("read() failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return NULL;
- }
- }
-
- if (0 == len)
- return NULL;
- } while (EINTR == errno);
-
- src->idx += len;
-
- for (i = src->idx - len; i < src->idx; ++i) {
- if ('\n' == src->buffer[i])
- break;
- }
-
- if (i == src->idx) {
- src->length = 0;
-
- if (BUFSIZE == src->idx) { /* no space left in buffer */
- while ('\n' != read_char (src))
- /* ignore complete line */;
-
- src->idx = 0;
- }
- return read_line (src);
- }
- }
-
- src->buffer[i] = '\0';
- src->length = i;
-
- return src->buffer;
- } /* static char *read_line (conn_t *) */
-
static void *collect (void *arg)
{
collector_t *this = (collector_t *)arg;
-
- char *buffer = (char *)smalloc (BUFSIZE);
+ pthread_t self = pthread_self ();
while (1) {
int loop = 1;
conns.tail = NULL;
}
- this->socket = connection->socket;
-
pthread_mutex_unlock (&conns_mutex);
- connection->buffer = buffer;
- connection->idx = 0;
- connection->length = 0;
+ /* make the socket available to the global
+ * thread and connection management */
+ this->socket = connection->socket;
- { /* put the socket in non-blocking mode */
- int flags = 0;
+ log_debug ("[thread #%5lu] handling connection on fd #%i",
+ self, fileno (this->socket));
- errno = 0;
- if (-1 == fcntl (connection->socket, F_GETFL, &flags)) {
- char errbuf[1024];
- log_err ("fcntl() failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- loop = 0;
- }
+ while (loop) {
+ /* 256 bytes ought to be enough for anybody ;-) */
+ char line[256 + 1]; /* line + '\0' */
+ int len = 0;
errno = 0;
- if (-1 == fcntl (connection->socket, F_SETFL, flags | O_NONBLOCK)) {
- char errbuf[1024];
- log_err ("fcntl() failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
+ if (NULL == fgets (line, sizeof (line), this->socket)) {
loop = 0;
+
+ if (0 != errno) {
+ char errbuf[1024];
+ log_err ("[thread #%5lu] reading from socket (fd #%i) "
+ "failed: %s", self, fileno (this->socket),
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ }
+ break;
}
- }
- while (loop) {
- char *line = read_line (connection);
+ len = strlen (line);
+ if (('\n' != line[len - 1]) && ('\r' != line[len - 1])) {
+ log_warn ("[thread #%5lu] line too long (> %i characters): "
+ "'%s' (truncated)", self, sizeof (line) - 1, line);
- if (NULL == line) {
- loop = 0;
- break;
+ while (NULL != fgets (line, sizeof (line), this->socket))
+ if (('\n' == line[len - 1]) || ('\r' == line[len - 1]))
+ break;
+ continue;
}
+ line[len - 1] = '\0';
+
+ log_debug ("[thread #%5lu] line = '%s'", self, line);
+
if (':' != line[1]) {
- log_err ("syntax error in line '%s'", line);
+ log_err ("[thread #%5lu] syntax error in line '%s'",
+ self, line);
continue;
}
int bytes = 0;
if (NULL == tmp) {
- log_err ("syntax error in line '%s'", line);
+ log_err ("[thread #%5lu] syntax error in line '%s'",
+ self, line);
continue;
}
bytes = atoi (tmp);
pthread_mutex_lock (&count_mutex);
- type_list_incr (&count, type, 1);
+ type_list_incr (&list_count, type, 1);
pthread_mutex_unlock (&count_mutex);
if (bytes > 0) {
pthread_mutex_lock (&size_mutex);
- type_list_incr (&size, type, bytes);
+ type_list_incr (&list_size, type, bytes);
pthread_mutex_unlock (&size_mutex);
}
}
do {
pthread_mutex_lock (&check_mutex);
- type_list_incr (&check, type, 1);
+ type_list_incr (&list_check, type, 1);
pthread_mutex_unlock (&check_mutex);
} while (NULL != (type = strtok_r (NULL, ",", &ptr)));
}
else {
- log_err ("unknown type '%c'", line[0]);
+ log_err ("[thread #%5lu] unknown type '%c'", self, line[0]);
}
} /* while (loop) */
- close (connection->socket);
+ log_debug ("[thread #%5lu] shutting down connection on fd #%i",
+ pthread_self (), fileno (this->socket));
+
+ fclose (connection->socket);
free (connection);
- this->socket = -1;
+ this->socket = NULL;
pthread_mutex_lock (&available_mutex);
++available_collectors;
pthread_cond_signal (&collector_available);
} /* while (1) */
- free (buffer);
pthread_exit ((void *)0);
} /* static void *collect (void *) */
{
struct sockaddr_un addr;
+ char *path = (NULL == sock_file) ? SOCK_PATH : sock_file;
+ char *group = (NULL == sock_group) ? COLLECTD_GRP_NAME : sock_group;
+
/* create UNIX socket */
errno = 0;
if (-1 == (connector_socket = socket (PF_UNIX, SOCK_STREAM, 0))) {
addr.sun_family = AF_UNIX;
- sstrncpy (addr.sun_path, sock_file, sizeof (addr.sun_path));
- strncpy (addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
- addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
++ sstrncpy (addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
unlink (addr.sun_path);
errno = 0;
+ strlen(addr.sun_path))) {
char errbuf[1024];
disabled = 1;
- connector_socket = -1; /* TODO: close? */
+ close (connector_socket);
+ connector_socket = -1;
log_err ("bind() failed: %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
pthread_exit ((void *)1);
if (-1 == listen (connector_socket, 5)) {
char errbuf[1024];
disabled = 1;
- connector_socket = -1; /* TODO: close? */
+ close (connector_socket);
+ connector_socket = -1;
log_err ("listen() failed: %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
pthread_exit ((void *)1);
}
- if ((uid_t) 0 == geteuid ())
{
struct group sg;
struct group *grp;
int status;
grp = NULL;
- status = getgrnam_r (sock_group, &sg, grbuf, sizeof (grbuf), &grp);
+ status = getgrnam_r (group, &sg, grbuf, sizeof (grbuf), &grp);
if (status != 0)
{
char errbuf[1024];
- log_warn ("getgrnam_r (%s) failed: %s", sock_group,
+ log_warn ("getgrnam_r (%s) failed: %s", group,
sstrerror (errno, errbuf, sizeof (errbuf)));
}
else if (grp == NULL)
{
- log_warn ("No such group: `%s'", sock_group);
+ log_warn ("No such group: `%s'", group);
}
else
{
- status = chown (sock_file, (uid_t) -1, grp->gr_gid);
+ status = chown (path, (uid_t) -1, grp->gr_gid);
if (status != 0)
{
char errbuf[1024];
log_warn ("chown (%s, -1, %i) failed: %s",
- sock_file, (int) grp->gr_gid,
+ path, (int) grp->gr_gid,
sstrerror (errno, errbuf, sizeof (errbuf)));
}
}
}
- else /* geteuid != 0 */
- {
- log_warn ("not running as root");
- }
errno = 0;
- if (0 != chmod (sock_file, sock_perms)) {
+ if (0 != chmod (path, sock_perms)) {
char errbuf[1024];
log_warn ("chmod() failed: %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
for (i = 0; i < max_conns; ++i) {
collectors[i] = (collector_t *)smalloc (sizeof (collector_t));
- collectors[i]->socket = -1;
+ collectors[i]->socket = NULL;
if (0 != (err = pthread_create (&collectors[i]->thread, &ptattr,
collect, collectors[i]))) {
if (EINTR != errno) {
char errbuf[1024];
disabled = 1;
- connector_socket = -1; /* TODO: close? */
+ close (connector_socket);
+ connector_socket = -1;
log_err ("accept() failed: %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
pthread_exit ((void *)1);
connection = (conn_t *)smalloc (sizeof (conn_t));
- connection->socket = remote;
+ connection->socket = fdopen (remote, "r");
connection->next = NULL;
+ if (NULL == connection->socket) {
+ close (remote);
+ continue;
+ }
+
pthread_mutex_lock (&conns_mutex);
if (NULL == conns.head) {
static int email_shutdown (void)
{
+ type_t *ptr = NULL;
+
int i = 0;
if (connector != ((pthread_t) 0)) {
/* don't allow any more connections to be processed */
pthread_mutex_lock (&conns_mutex);
+ available_collectors = 0;
+
if (collectors != NULL) {
for (i = 0; i < max_conns; ++i) {
if (collectors[i] == NULL)
collectors[i]->thread = (pthread_t) 0;
}
- if (collectors[i]->socket >= 0) {
- close (collectors[i]->socket);
- collectors[i]->socket = -1;
+ if (collectors[i]->socket != NULL) {
+ fclose (collectors[i]->socket);
+ collectors[i]->socket = NULL;
}
+
+ sfree (collectors[i]);
}
+ sfree (collectors);
} /* if (collectors != NULL) */
pthread_mutex_unlock (&conns_mutex);
- unlink (sock_file);
- errno = 0;
+ for (ptr = list_count.head; NULL != ptr; ptr = ptr->next) {
+ free (ptr->name);
+ free (ptr);
+ }
+
+ for (ptr = list_count_copy.head; NULL != ptr; ptr = ptr->next) {
+ free (ptr->name);
+ free (ptr);
+ }
+
+ for (ptr = list_size.head; NULL != ptr; ptr = ptr->next) {
+ free (ptr->name);
+ free (ptr);
+ }
+ for (ptr = list_size_copy.head; NULL != ptr; ptr = ptr->next) {
+ free (ptr->name);
+ free (ptr);
+ }
+
+ for (ptr = list_check.head; NULL != ptr; ptr = ptr->next) {
+ free (ptr->name);
+ free (ptr);
+ }
+
+ for (ptr = list_check_copy.head; NULL != ptr; ptr = ptr->next) {
+ free (ptr->name);
+ free (ptr);
+ }
+
+ unlink ((NULL == sock_file) ? SOCK_PATH : sock_file);
+
+ sfree (sock_file);
+ sfree (sock_group);
return (0);
} /* static void email_shutdown (void) */
vl.time = time (NULL);
strcpy (vl.host, hostname_g);
strcpy (vl.plugin, "email");
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void email_submit */
/* Copy list l1 to list l2. l2 may partly exist already, but it is assumed
double score_old;
int score_count_old;
- static type_list_t *cnt;
- static type_list_t *sz;
- static type_list_t *chk;
-
if (disabled)
return (-1);
- if (NULL == cnt) {
- cnt = (type_list_t *)smalloc (sizeof (type_list_t));
- cnt->head = NULL;
- }
-
- if (NULL == sz) {
- sz = (type_list_t *)smalloc (sizeof (type_list_t));
- sz->head = NULL;
- }
-
- if (NULL == chk) {
- chk = (type_list_t *)smalloc (sizeof (type_list_t));
- chk->head = NULL;
- }
-
/* email count */
pthread_mutex_lock (&count_mutex);
- copy_type_list (&count, cnt);
+ copy_type_list (&list_count, &list_count_copy);
pthread_mutex_unlock (&count_mutex);
- for (ptr = cnt->head; NULL != ptr; ptr = ptr->next) {
+ for (ptr = list_count_copy.head; NULL != ptr; ptr = ptr->next) {
email_submit ("email_count", ptr->name, ptr->value);
}
/* email size */
pthread_mutex_lock (&size_mutex);
- copy_type_list (&size, sz);
+ copy_type_list (&list_size, &list_size_copy);
pthread_mutex_unlock (&size_mutex);
- for (ptr = sz->head; NULL != ptr; ptr = ptr->next) {
+ for (ptr = list_size_copy.head; NULL != ptr; ptr = ptr->next) {
email_submit ("email_size", ptr->name, ptr->value);
}
/* spam checks */
pthread_mutex_lock (&check_mutex);
- copy_type_list (&check, chk);
+ copy_type_list (&list_check, &list_check_copy);
pthread_mutex_unlock (&check_mutex);
- for (ptr = chk->head; NULL != ptr; ptr = ptr->next)
+ for (ptr = list_check_copy.head; NULL != ptr; ptr = ptr->next)
email_submit ("spam_check", ptr->name, ptr->value);
return (0);
# include <ifaddrs.h>
#endif
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
+
/*
* Various people have reported problems with `getifaddrs' and varying versions
* of `glibc'. That's why it's disabled by default. Since more statistics are
vl.time = time (NULL);
strcpy (vl.host, hostname_g);
strcpy (vl.plugin, "interface");
- strncpy (vl.type_instance, dev, sizeof (vl.type_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, dev, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void if_submit */
static int interface_read (void)
#include <sys/loadavg.h>
#endif
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
+
#ifdef HAVE_GETLOADAVG
#if !defined(LOADAVG_1MIN) || !defined(LOADAVG_5MIN) || !defined(LOADAVG_15MIN)
#define LOADAVG_1MIN 0
vl.time = time (NULL);
strcpy (vl.host, hostname_g);
strcpy (vl.plugin, "load");
+ strcpy (vl.type, "load");
- plugin_dispatch_values ("load", &vl);
+ plugin_dispatch_values (&vl);
}
static int load_read (void)
load_submit (snum, mnum, lnum);
/* #endif KERNEL_LINUX */
- #elif defined(HAVE_LIBSTATGRAB)
+ #elif HAVE_LIBSTATGRAB
gauge_t snum, mnum, lnum;
sg_load_stats *ls;
# include <mach/vm_statistics.h>
#endif
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
+
/* vm_statistics_data_t */
#if HAVE_HOST_STATISTICS
static mach_port_t port_host;
static kstat_t *ksp;
/* #endif HAVE_LIBKSTAT */
+ #elif HAVE_LIBSTATGRAB
+ /* no global variables */
+ /* endif HAVE_LIBSTATGRAB */
+
#else
# error "No applicable input method."
#endif
vl.time = time (NULL);
strcpy (vl.host, hostname_g);
strcpy (vl.plugin, "memory");
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ strcpy (vl.type, "memory");
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values ("memory", &vl);
+ plugin_dispatch_values (&vl);
}
static int memory_read (void)
memory_submit ("cache", sysctl_vals[6]);
/* #endif HAVE_SYSCTLBYNAME */
- #elif defined(KERNEL_LINUX)
+ #elif KERNEL_LINUX
FILE *fh;
char buffer[1024];
memory_submit ("cached", mem_cached);
memory_submit ("free", mem_free);
}
- /* #endif defined(KERNEL_LINUX) */
+ /* #endif KERNEL_LINUX */
- #elif defined(HAVE_LIBKSTAT)
+ #elif HAVE_LIBKSTAT
long long mem_used;
long long mem_free;
long long mem_lock;
memory_submit ("used", mem_used);
memory_submit ("free", mem_free);
memory_submit ("locked", mem_lock);
- /* #endif defined(HAVE_LIBKSTAT) */
+ /* #endif HAVE_LIBKSTAT */
- #elif defined(HAVE_LIBSTATGRAB)
+ #elif HAVE_LIBSTATGRAB
sg_mem_stats *ios;
if ((ios = sg_get_mem_stats ()) != NULL)
#define PLUGIN_SHUTDOWN 3
#define PLUGIN_LOG 4
#define PLUGIN_NOTIF 5
+ #define PLUGIN_FLUSH 6
- #define PLUGIN_TYPES 6
+ #define PLUGIN_TYPES 7
#define PLUGIN_DATASET 255
static XS (Collectd_plugin_register_ds);
static XS (Collectd_plugin_unregister_ds);
static XS (Collectd_plugin_dispatch_values);
+ static XS (Collectd_plugin_flush_one);
+ static XS (Collectd_plugin_flush_all);
static XS (Collectd_plugin_dispatch_notification);
static XS (Collectd_plugin_log);
static XS (Collectd_call_by_name);
{ "Collectd::plugin_register_data_set", Collectd_plugin_register_ds },
{ "Collectd::plugin_unregister_data_set", Collectd_plugin_unregister_ds },
{ "Collectd::plugin_dispatch_values", Collectd_plugin_dispatch_values },
+ { "Collectd::plugin_flush_one", Collectd_plugin_flush_one },
+ { "Collectd::plugin_flush_all", Collectd_plugin_flush_all },
{ "Collectd::plugin_dispatch_notification",
Collectd_plugin_dispatch_notification },
{ "Collectd::plugin_log", Collectd_plugin_log },
{ "Collectd::TYPE_SHUTDOWN", PLUGIN_SHUTDOWN },
{ "Collectd::TYPE_LOG", PLUGIN_LOG },
{ "Collectd::TYPE_NOTIF", PLUGIN_NOTIF },
+ { "Collectd::TYPE_FLUSH", PLUGIN_FLUSH },
{ "Collectd::TYPE_DATASET", PLUGIN_DATASET },
{ "Collectd::DS_TYPE_COUNTER", DS_TYPE_COUNTER },
{ "Collectd::DS_TYPE_GAUGE", DS_TYPE_GAUGE },
return -1;
if (NULL != (tmp = hv_fetch (hash, "name", 4, 0))) {
- strncpy (ds->name, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
- ds->name[DATA_MAX_NAME_LEN - 1] = '\0';
+ sstrncpy (ds->name, SvPV_nolen (*tmp), sizeof (ds->name));
}
else {
log_err ("hv2data_source: No DS name given.");
newSVpv (vl->plugin_instance, 0), 0))
return -1;
+ if ('\0' != vl->type[0])
+ if (NULL == hv_store (hash, "type", 4, newSVpv (vl->type, 0), 0))
+ return -1;
+
if ('\0' != vl->type_instance[0])
if (NULL == hv_store (hash, "type_instance", 13,
newSVpv (vl->type_instance, 0), 0))
static char *get_module_name (char *buf, size_t buf_len, const char *module) {
int status = 0;
if (base_name[0] == '\0')
- status = snprintf (buf, buf_len, "%s", module);
+ status = ssnprintf (buf, buf_len, "%s", module);
else
- status = snprintf (buf, buf_len, "%s::%s", base_name, module);
+ status = ssnprintf (buf, buf_len, "%s::%s", base_name, module);
if ((status < 0) || ((unsigned int)status >= buf_len))
return (NULL);
- buf[buf_len - 1] = '\0';
return (buf);
} /* char *get_module_name */
ds[i].name, ds[i].type, ds[i].min, ds[i].max);
}
- strncpy (set->type, name, DATA_MAX_NAME_LEN);
- set->type[DATA_MAX_NAME_LEN - 1] = '\0';
+ sstrncpy (set->type, name, sizeof (set->type));
set->ds_num = len + 1;
set->ds = ds;
* type_instance => $tinstance,
* }
*/
-static int pplugin_dispatch_values (pTHX_ char *name, HV *values)
+static int pplugin_dispatch_values (pTHX_ HV *values)
{
value_list_t list = VALUE_LIST_INIT;
value_t *val = NULL;
int ret = 0;
- if ((NULL == name) || (NULL == values))
+ if (NULL == values)
+ return -1;
+
+ if (NULL == (tmp = hv_fetch (values, "type", 4, 0))) {
+ log_err ("pplugin_dispatch_values: No type given.");
return -1;
+ }
+
+ sstrncpy (list.type, SvPV_nolen (*tmp), sizeof (list.type));
if ((NULL == (tmp = hv_fetch (values, "values", 6, 0)))
|| (! (SvROK (*tmp) && (SVt_PVAV == SvTYPE (SvRV (*tmp)))))) {
val = (value_t *)smalloc (len * sizeof (value_t));
- list.values_len = av2value (aTHX_ name, (AV *)SvRV (*tmp), val, len);
+ list.values_len = av2value (aTHX_ list.type, (AV *)SvRV (*tmp),
+ val, len);
list.values = val;
if (-1 == list.values_len) {
}
if (NULL != (tmp = hv_fetch (values, "host", 4, 0))) {
- strncpy (list.host, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
- list.host[DATA_MAX_NAME_LEN - 1] = '\0';
+ sstrncpy (list.host, SvPV_nolen (*tmp), sizeof (list.host));
}
else {
strcpy (list.host, hostname_g);
}
- if (NULL != (tmp = hv_fetch (values, "plugin", 6, 0))) {
- strncpy (list.plugin, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
- list.plugin[DATA_MAX_NAME_LEN - 1] = '\0';
- }
+ if (NULL != (tmp = hv_fetch (values, "plugin", 6, 0)))
+ sstrncpy (list.plugin, SvPV_nolen (*tmp), sizeof (list.plugin));
- if (NULL != (tmp = hv_fetch (values, "plugin_instance", 15, 0))) {
- strncpy (list.plugin_instance, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
- list.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
- }
+ if (NULL != (tmp = hv_fetch (values, "plugin_instance", 15, 0)))
+ sstrncpy (list.plugin_instance, SvPV_nolen (*tmp),
+ sizeof (list.plugin_instance));
- if (NULL != (tmp = hv_fetch (values, "type_instance", 13, 0))) {
- strncpy (list.type_instance, SvPV_nolen (*tmp), DATA_MAX_NAME_LEN);
- list.type_instance[DATA_MAX_NAME_LEN - 1] = '\0';
- }
+ if (NULL != (tmp = hv_fetch (values, "type_instance", 13, 0)))
+ sstrncpy (list.type_instance, SvPV_nolen (*tmp),
+ sizeof (list.type_instance));
- ret = plugin_dispatch_values (name, &list);
+ ret = plugin_dispatch_values (&list);
sfree (val);
return ret;
n.time = time (NULL);
if (NULL != (tmp = hv_fetch (notif, "message", 7, 0)))
- strncpy (n.message, SvPV_nolen (*tmp), sizeof (n.message));
- n.message[sizeof (n.message) - 1] = '\0';
+ sstrncpy (n.message, SvPV_nolen (*tmp), sizeof (n.message));
if (NULL != (tmp = hv_fetch (notif, "host", 4, 0)))
- strncpy (n.host, SvPV_nolen (*tmp), sizeof (n.host));
+ sstrncpy (n.host, SvPV_nolen (*tmp), sizeof (n.host));
else
- strncpy (n.host, hostname_g, sizeof (n.host));
- n.host[sizeof (n.host) - 1] = '\0';
+ sstrncpy (n.host, hostname_g, sizeof (n.host));
if (NULL != (tmp = hv_fetch (notif, "plugin", 6, 0)))
- strncpy (n.plugin, SvPV_nolen (*tmp), sizeof (n.plugin));
- n.plugin[sizeof (n.plugin) - 1] = '\0';
+ sstrncpy (n.plugin, SvPV_nolen (*tmp), sizeof (n.plugin));
if (NULL != (tmp = hv_fetch (notif, "plugin_instance", 15, 0)))
- strncpy (n.plugin_instance, SvPV_nolen (*tmp),
+ sstrncpy (n.plugin_instance, SvPV_nolen (*tmp),
sizeof (n.plugin_instance));
- n.plugin_instance[sizeof (n.plugin_instance) - 1] = '\0';
if (NULL != (tmp = hv_fetch (notif, "type", 4, 0)))
- strncpy (n.type, SvPV_nolen (*tmp), sizeof (n.type));
- n.type[sizeof (n.type) - 1] = '\0';
+ sstrncpy (n.type, SvPV_nolen (*tmp), sizeof (n.type));
if (NULL != (tmp = hv_fetch (notif, "type_instance", 13, 0)))
- strncpy (n.type_instance, SvPV_nolen (*tmp), sizeof (n.type_instance));
- n.type_instance[sizeof (n.type_instance) - 1] = '\0';
+ sstrncpy (n.type_instance, SvPV_nolen (*tmp), sizeof (n.type_instance));
return plugin_dispatch_notification (&n);
} /* static int pplugin_dispatch_notification (HV *) */
* time => $time,
* host => $hostname,
* plugin => $plugin,
+ * type => $type,
* plugin_instance => $instance,
* type_instance => $type_instance
* };
XPUSHs (sv_2mortal (newRV_noinc ((SV *)notif)));
}
+ else if (PLUGIN_FLUSH == type) {
+ /*
+ * $_[0] = $timeout;
+ */
+ XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
+ }
PUTBACK;
*/
static XS (Collectd_plugin_dispatch_values)
{
- SV *values = NULL;
+ SV *values = NULL;
+ int values_idx = 0;
int ret = 0;
dXSARGS;
- if (2 != items) {
- log_err ("Usage: Collectd::plugin_dispatch_values(name, values)");
+ 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) {
+ log_err ("Usage: Collectd::plugin_dispatch_values(values)");
XSRETURN_EMPTY;
}
- log_debug ("Collectd::plugin_dispatch_values: "
- "name = \"%s\", values=\"%s\"",
- SvPV_nolen (ST (0)), SvPV_nolen (ST (1)));
+ log_debug ("Collectd::plugin_dispatch_values: values=\"%s\"",
+ SvPV_nolen (ST (values_idx)));
- values = ST (1);
+ values = ST (values_idx);
if (! (SvROK (values) && (SVt_PVHV == SvTYPE (SvRV (values))))) {
log_err ("Collectd::plugin_dispatch_values: Invalid values.");
XSRETURN_EMPTY;
}
- if ((NULL == ST (0)) || (NULL == values))
+ if (((2 == items) && (NULL == ST (0))) || (NULL == values))
XSRETURN_EMPTY;
- ret = pplugin_dispatch_values (aTHX_ SvPV_nolen (ST (0)),
- (HV *)SvRV (values));
+ 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.");
+ XSRETURN_EMPTY;
+ }
+
+ ret = pplugin_dispatch_values (aTHX_ (HV *)SvRV (values));
if (0 == ret)
XSRETURN_YES;
} /* static XS (Collectd_plugin_dispatch_values) */
/*
+ * Collectd::plugin_flush_one (timeout, name).
+ *
+ * timeout:
+ * timeout to use when flushing the data
+ *
+ * name:
+ * name of the plugin to flush
+ */
+ static XS (Collectd_plugin_flush_one)
+ {
+ dXSARGS;
+
+ if (2 != items) {
+ log_err ("Usage: Collectd::plugin_flush_one(timeout, name)");
+ XSRETURN_EMPTY;
+ }
+
+ log_debug ("Collectd::plugin_flush_one: timeout = %i, name = \"%s\"",
+ (int)SvIV (ST (0)), SvPV_nolen (ST (1)));
+
+ if (0 == plugin_flush_one ((int)SvIV (ST (0)), SvPV_nolen (ST (1))))
+ XSRETURN_YES;
+ else
+ XSRETURN_EMPTY;
+ } /* static XS (Collectd_plugin_flush_one) */
+
+ /*
+ * Collectd::plugin_flush_all (timeout).
+ *
+ * timeout:
+ * timeout to use when flushing the data
+ */
+ static XS (Collectd_plugin_flush_all)
+ {
+ dXSARGS;
+
+ if (1 != items) {
+ log_err ("Usage: Collectd::plugin_flush_all(timeout)");
+ XSRETURN_EMPTY;
+ }
+
+ log_debug ("Collectd::plugin_flush_all: timeout = %i", (int)SvIV (ST (0)));
+
+ plugin_flush_all ((int)SvIV (ST (0)));
+ XSRETURN_YES;
+ } /* static XS (Collectd_plugin_flush_all) */
+
+ /*
* Collectd::plugin_dispatch_notification (notif).
*
* notif:
return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
} /* static int perl_notify (const notification_t *) */
+ static int perl_flush (const int timeout)
+ {
+ dTHX;
+
+ if (NULL == perl_threads)
+ return 0;
+
+ if (NULL == aTHX) {
+ c_ithread_t *t = NULL;
+
+ pthread_mutex_lock (&perl_threads->mutex);
+ t = c_ithread_create (perl_threads->head->interp);
+ pthread_mutex_unlock (&perl_threads->mutex);
+
+ aTHX = t->interp;
+ }
+ return pplugin_call_all (aTHX_ PLUGIN_FLUSH, timeout);
+ } /* static int perl_flush (const int) */
+
static int perl_shutdown (void)
{
c_ithread_t *t = NULL;
plugin_unregister_init ("perl");
plugin_unregister_read ("perl");
plugin_unregister_write ("perl");
+ plugin_unregister_flush ("perl");
ret = pplugin_call_all (aTHX_ PLUGIN_SHUTDOWN);
static int g_pv_set (pTHX_ SV *var, MAGIC *mg)
{
char *pv = mg->mg_ptr;
- strncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
- pv[DATA_MAX_NAME_LEN - 1] = '\0';
+ sstrncpy (pv, SvPV_nolen (var), DATA_MAX_NAME_LEN);
return 0;
} /* static int g_pv_set (pTHX_ SV *, MAGIC *) */
exit (1);
}
+ #ifdef __FreeBSD__
+ /* On FreeBSD, PERL_SYS_INIT3 expands to some expression which
+ * triggers a "value computed is not used" warning by gcc. */
+ (void)
+ #endif
PERL_SYS_INIT3 (&argc, &argv, &environ);
perl_threads = (c_ithread_list_t *)smalloc (sizeof (c_ithread_list_t));
plugin_register_read ("perl", perl_read);
plugin_register_write ("perl", perl_write);
+ plugin_register_flush ("perl", perl_flush);
plugin_register_shutdown ("perl", perl_shutdown);
return 0;
} /* static int init_pi (const char **, const int) */
value = ci->values[0].value.string;
log_debug ("perl_config: Setting plugin basename to \"%s\"", value);
- strncpy (base_name, value, sizeof (base_name));
- base_name[sizeof (base_name) - 1] = '\0';
+ sstrncpy (base_name, value, sizeof (base_name));
return 0;
} /* static int perl_config_basename (oconfig_item_it *) */
# include <kvm.h>
#endif
+ #if HAVE_STATGRAB_H
+ # include <statgrab.h>
+ #endif
+
#undef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
vl.time = time (NULL);
strcpy (vl.host, hostname_g);
strcpy (vl.plugin, "swap");
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ strcpy (vl.type, "swap");
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values ("swap", &vl);
+ plugin_dispatch_values (&vl);
} /* void swap_submit */
static int swap_read (void)