apcups plugin by:
Anthony Gialluca <tonyabg at charter.net>
-cpufreq module by:
+cpufreq and multimeter module by:
Peter Holik <peter at holik.at>
hddtemp module by:
%attr(0444,root,root) %{_libdir}/%{name}/hddtemp.so*
%attr(0444,root,root) %{_libdir}/%{name}/load.so*
%attr(0444,root,root) %{_libdir}/%{name}/memory.so*
+%attr(0444,root,root) %{_libdir}/%{name}/multimeter.so*
%attr(0444,root,root) %{_libdir}/%{name}/nfs.so*
%attr(0444,root,root) %{_libdir}/%{name}/ntpd.so*
%attr(0444,root,root) %{_libdir}/%{name}/ping.so*
# For load module
AC_CHECK_HEADERS(sys/loadavg.h)
+# For the processes plugin
+AC_CHECK_HEADERS(linux/config.h)
+
# For the swap module
AC_CHECK_HEADERS(sys/swap.h)
AC_COLLECTD([hddtemp], [disable], [module], [hdd temperature statistics])
AC_COLLECTD([load], [disable], [module], [system load statistics])
AC_COLLECTD([memory], [disable], [module], [memory statistics])
+AC_COLLECTD([multimeter],[disable], [module], [multimeter statistics])
AC_COLLECTD([mysql], [disable], [module], [mysql statistics])
AC_COLLECTD([nfs], [disable], [module], [nfs statistics])
AC_COLLECTD([ntpd], [disable], [module], [nfs statistics])
hddtemp . . . . . . $enable_hddtemp
load . . . . . . . $enable_load
memory . . . . . . $enable_memory
+ multimeter . . . . $enable_multimeter
mysql . . . . . . . $enable_mysql
nfs . . . . . . . . $enable_nfs
ntpd . . . . . . . $enable_ntpd
'GPRINT:tx_avg:AVERAGE:%5.1lf%s Avg,',
'GPRINT:tx_max:MAX:%5.1lf%s Max,',
'GPRINT:tx_avg:LAST:%5.1lf%s Last',
- 'GPRINT:tx_avg_sum:LAST:(ca. %.0lf Total)\l',
+ 'GPRINT:tx_avg_sum:LAST:(ca. %4.0lf%s Total)\l',
"LINE1:rx_avg#$FullBlue:RX",
#'GPRINT:rx_min:MIN:%5.1lf %s Min,',
'GPRINT:rx_avg:AVERAGE:%5.1lf%s Avg,',
'GPRINT:rx_max:MAX:%5.1lf%s Max,',
'GPRINT:rx_avg:LAST:%5.1lf%s Last',
- 'GPRINT:rx_avg_sum:LAST:(ca. %.0lf Total)\l'
+ 'GPRINT:rx_avg_sum:LAST:(ca. %4.0lf%s Total)\l'
],
load => ['DEF:s_avg={file}:shortterm:AVERAGE',
'DEF:s_min={file}:shortterm:MIN',
'GPRINT:sleeping_max:MAX:%5.1lf Max,',
'GPRINT:sleeping_avg:LAST:%5.1lf Last\l'
],
+ ps_rss => [
+ 'DEF:avg={file}:byte:AVERAGE',
+ 'DEF:min={file}:byte:MIN',
+ 'DEF:max={file}:byte:MAX',
+ "AREA:avg#$HalfBlue",
+ "LINE1:avg#$FullBlue:RSS",
+ 'GPRINT:min:MIN:%5.1lf%s Min,',
+ 'GPRINT:avg:AVERAGE:%5.1lf%s Avg,',
+ 'GPRINT:max:MAX:%5.1lf%s Max,',
+ 'GPRINT:avg:LAST:%5.1lf%s Last\l'
+ ],
+ ps_cputime => [
+ 'DEF:user_avg_raw={file}:user:AVERAGE',
+ 'DEF:user_min_raw={file}:user:MIN',
+ 'DEF:user_max_raw={file}:user:MAX',
+ 'DEF:syst_avg_raw={file}:syst:AVERAGE',
+ 'DEF:syst_min_raw={file}:syst:MIN',
+ 'DEF:syst_max_raw={file}:syst:MAX',
+ 'CDEF:user_avg=user_avg_raw,1000000,/',
+ 'CDEF:user_min=user_min_raw,1000000,/',
+ 'CDEF:user_max=user_max_raw,1000000,/',
+ 'CDEF:syst_avg=syst_avg_raw,1000000,/',
+ 'CDEF:syst_min=syst_min_raw,1000000,/',
+ 'CDEF:syst_max=syst_max_raw,1000000,/',
+ 'CDEF:user_syst=syst_avg,UN,0,syst_avg,IF,user_avg,+',
+ "AREA:user_syst#$HalfBlue",
+ "AREA:syst_avg#$HalfRed",
+ "LINE1:user_syst#$FullBlue:User ",
+ 'GPRINT:user_min:MIN:%5.1lf%s Min,',
+ 'GPRINT:user_avg:AVERAGE:%5.1lf%s Avg,',
+ 'GPRINT:user_max:MAX:%5.1lf%s Max,',
+ 'GPRINT:user_avg:LAST:%5.1lf%s Last\l',
+ "LINE1:syst_avg#$FullRed:System",
+ 'GPRINT:syst_min:MIN:%5.1lf%s Min,',
+ 'GPRINT:syst_avg:AVERAGE:%5.1lf%s Avg,',
+ 'GPRINT:syst_max:MAX:%5.1lf%s Max,',
+ 'GPRINT:syst_avg:LAST:%5.1lf%s Last\l'
+ ],
+ ps_count => [
+ 'DEF:procs_avg={file}:processes:AVERAGE',
+ 'DEF:procs_min={file}:processes:MIN',
+ 'DEF:procs_max={file}:processes:MAX',
+ 'DEF:thrds_avg={file}:threads:AVERAGE',
+ 'DEF:thrds_min={file}:threads:MIN',
+ 'DEF:thrds_max={file}:threads:MAX',
+ "AREA:thrds_avg#$HalfBlue",
+ "AREA:procs_avg#$HalfRed",
+ "LINE1:thrds_avg#$FullBlue:Threads ",
+ 'GPRINT:thrds_min:MIN:%5.1lf Min,',
+ 'GPRINT:thrds_avg:AVERAGE:%5.1lf Avg,',
+ 'GPRINT:thrds_max:MAX:%5.1lf Max,',
+ 'GPRINT:thrds_avg:LAST:%5.1lf Last\l',
+ "LINE1:procs_avg#$FullRed:Processes",
+ 'GPRINT:procs_min:MIN:%5.1lf Min,',
+ 'GPRINT:procs_avg:AVERAGE:%5.1lf Avg,',
+ 'GPRINT:procs_max:MAX:%5.1lf Max,',
+ 'GPRINT:procs_avg:LAST:%5.1lf Last\l'
+ ],
+ ps_pagefaults => [
+ 'DEF:minor_avg={file}:minflt:AVERAGE',
+ 'DEF:minor_min={file}:minflt:MIN',
+ 'DEF:minor_max={file}:minflt:MAX',
+ 'DEF:major_avg={file}:majflt:AVERAGE',
+ 'DEF:major_min={file}:majflt:MIN',
+ 'DEF:major_max={file}:majflt:MAX',
+ 'CDEF:minor_major=major_avg,UN,0,major_avg,IF,minor_avg,+',
+ "AREA:minor_major#$HalfBlue",
+ "AREA:major_avg#$HalfRed",
+ "LINE1:minor_major#$FullBlue:Minor",
+ 'GPRINT:minor_min:MIN:%5.1lf%s Min,',
+ 'GPRINT:minor_avg:AVERAGE:%5.1lf%s Avg,',
+ 'GPRINT:minor_max:MAX:%5.1lf%s Max,',
+ 'GPRINT:minor_avg:LAST:%5.1lf%s Last\l',
+ "LINE1:major_avg#$FullRed:Major",
+ 'GPRINT:major_min:MIN:%5.1lf%s Min,',
+ 'GPRINT:major_avg:AVERAGE:%5.1lf%s Avg,',
+ 'GPRINT:major_max:MAX:%5.1lf%s Max,',
+ 'GPRINT:major_avg:LAST:%5.1lf%s Last\l'
+ ],
swap => [
'DEF:used_avg={file}:used:AVERAGE',
'DEF:used_min={file}:used:MIN',
'GPRINT:cpufreq_max:MAX:%5.1lf%s Max,',
'GPRINT:cpufreq_avg:LAST:%5.1lf%s Last\l'
],
+ multimeter => [
+ 'DEF:multimeter_avg={file}:value:AVERAGE',
+ 'DEF:multimeter_min={file}:value:MIN',
+ 'DEF:multimeter_max={file}:value:MAX',
+ "AREA:multimeter_max#$HalfBlue",
+ "AREA:multimeter_min#$Canvas",
+ "LINE1:multimeter_avg#$FullBlue:Multimeter",
+ 'GPRINT:multimeter_min:MIN:%4.1lf Min,',
+ 'GPRINT:multimeter_avg:AVERAGE:%4.1lf Average,',
+ 'GPRINT:multimeter_max:MAX:%4.1lf Max,',
+ 'GPRINT:multimeter_avg:LAST:%4.1lf Last\l'
+ ],
users => [
'DEF:users_avg={file}:users:AVERAGE',
'DEF:users_min={file}:users:MIN',
partition => ['-t', '{host} partition {inst} usage', '-v', 'Byte/s'],
ping => ['-t', '{host} ping to {inst}', '-v', 'ms'],
processes => ['-t', '{host} processes', '-v', 'Processes'],
+ ps_rss => ['-t', '{host} process {inst} RSS', '-v', 'Bytes', '-b', '1024'],
+ ps_cputime => ['-t', '{host} process {inst} CPU usage', '-v', 'Seconds'],
+ ps_count => ['-t', '{host} process {inst} count', '-v', 'Threads/Processes'],
+ ps_pagefaults => ['-t', '{host} process {inst} pagefaults', '-v', 'Pagefaults/s'],
sensors => ['-t', '{host} sensor {inst}', '-v', '°Celsius'],
swap => ['-t', '{host} swap usage', '-v', 'Bytes', '-b', '1024', '-l', '0'],
temperature => ['-t', '{host} temperature {inst}', '-v', '°Celsius'],
time_dispersion => ['-t', 'NTPd time dispersion ({inst})', '-v', 'Seconds'],
traffic => ['-t', '{host} {inst} traffic', '-v', 'Bit/s'],
users => ['-t', '{host} users', '-v', 'Users'],
+ multimeter => ['-t', '{host} multimeter', '-v', 'Value'],
voltage => ['-t', '{host} voltage', '-v', 'Volts'],
vs_threads => ['-t', '{host} threads', '-v', 'Threads'],
vs_memory => ['-t', '{host} memory usage', '-v', 'Bytes'],
ping => \&output_graph_ping,
sensors => 1,
traffic => 1,
- users => 1
+ users => 1,
+ multimeter => 1
};
our @Info;
Depends: collectd (= ${Source-Version}), libsensors3
Description: collectd module for libsensors.
collectd module to collect system temperatures.
+
+Package: collectd-multimeter
+Architecture: any
+Depends: collectd (= ${Source-Version}), ${shlibs:Depends}
+Description: statistics collection daemon (multimeter plugin)
+ collectd is a small daemon written in C for performance. It reads various
+ system statistics and updates RRD files, creating them if necessary. Since
+ the daemon doesn't need to startup every time it wants to update the files
+ it's very fast and easy on the system. Also, the statistics are very fine
+ grained since the files are updated every 10 seconds.
+ .
+ This package contains the multimeter plugin which collects values from a
+ multimeter connected to a serial port.
CFLAGS = -Wall -g
-PLUGINS = apache mysql sensors
+PLUGINS = apache mysql sensors multimeter
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS += -O0
endif
endif
+if BUILD_MODULE_MULTIMETER
+pkglib_LTLIBRARIES += multimeter.la
+multimeter_la_SOURCES = multimeter.c
+multimeter_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" multimeter.la
+collectd_DEPENDENCIES += multimeter.la
+endif
+
if BUILD_MODULE_MYSQL
pkglib_LTLIBRARIES += mysql.la
mysql_la_SOURCES = mysql.c
#if HAVE_LIBCURL
static CURL *curl = NULL;
-static char apache_buffer[4096];
+#define ABUFFER_SIZE 16384
+static char apache_buffer[ABUFFER_SIZE];
static int apache_buffer_len = 0;
static char apache_curl_error[CURL_ERROR_SIZE];
#endif /* HAVE_LIBCURL */
{
size_t len = size * nmemb;
- if ((apache_buffer_len + len) >= 4096)
+ if ((apache_buffer_len + len) >= ABUFFER_SIZE)
{
- len = 4095 - apache_buffer_len;
+ len = (ABUFFER_SIZE - 1) - apache_buffer_len;
}
if (len <= 0)
double value;
static int sockfd = -1;
- static unsigned int complain = 0;
+ static complain_t compl;
#if APCMAIN
# define PRINT_VALUE(name, val) printf(" Found property: name = %s; value = %f;\n", name, val)
{
if ((sockfd = net_open (host, NULL, port)) < 0)
{
- /* Complain once every six hours. */
- int complain_step = 21600 / atoi (COLLECTD_STEP);
-
- if ((complain % complain_step) == 0)
- syslog (LOG_ERR, "apcups plugin: Connecting to the apcupsd failed.");
- complain++;
-
+ plugin_complain (LOG_ERR, &compl, "apcups plugin: "
+ "Connecting to the apcupsd failed.");
return (-1);
}
- else if (complain > 1)
+ else
{
- syslog (LOG_NOTICE, "apcups plugin: Connection re-established to the apcupsd.");
- complain = 0;
+ plugin_relief (LOG_NOTICE, &compl, "apcups plugin: "
+ "Connection re-established to the apcupsd.");
}
}
@BUILD_MODULE_HDDTEMP_TRUE@LoadPlugin hddtemp
@BUILD_MODULE_LOAD_TRUE@LoadPlugin load
@BUILD_MODULE_MEMORY_TRUE@LoadPlugin memory
+@BUILD_MODULE_MULTIMETER_TRUE@LoadPlugin multimeter
@BUILD_MODULE_MYSQL_TRUE@LoadPlugin mysql
@BUILD_MODULE_NFS_TRUE@LoadPlugin nfs
@BUILD_MODULE_NTPD_TRUE@LoadPlugin ntpd
# Host host.foo.bar
#</Plugin>
+#<Plugin processes>
+# Process name
+#</Plugin>
+
#<Plugin traffic>
# Interface eth0
# IgnoreSelected false
char *fields[9];
int numfields;
+ static complain_t complain_obj;
+
if ((fh = fopen ("/proc/stat", "r")) == NULL)
{
- syslog (LOG_WARNING, "cpu: fopen: %s", strerror (errno));
+ plugin_complain (LOG_ERR, &complain_obj, "cpu plugin: "
+ "fopen (/proc/stat) failed: %s",
+ strerror (errno));
return;
}
+ plugin_relief (LOG_NOTICE, &complain_obj, "cpu plugin: "
+ "fopen (/proc/stat) succeeded.");
+
while (fgets (buf, BUFSIZE, fh) != NULL)
{
if (strncmp (buf, "cpu", 3))
long cpuinfo[CPUSTATES];
size_t cpuinfo_size;
+ static complain_t complain_obj;
+
cpuinfo_size = sizeof (cpuinfo);
if (sysctlbyname("kern.cp_time", &cpuinfo, &cpuinfo_size, NULL, 0) < 0)
{
- syslog (LOG_WARNING, "cpu: sysctlbyname: %s", strerror (errno));
+ plugin_complain (LOG_ERR, &complain_obj, "cpu plugin: "
+ "sysctlbyname failed: %s.",
+ strerror (errno));
return;
}
+ plugin_relief (LOG_NOTICE, &complain_obj, "cpu plugin: "
+ "sysctlbyname succeeded.");
+
cpuinfo[CP_SYS] += cpuinfo[CP_INTR];
/* FIXME: Instance is always `0' */
int disk_minor;
char disk_name[64];
+ static complain_t complain_obj;
+
/* Get the list of all disk objects. */
if (IOServiceGetMatchingServices (io_master_port,
IOServiceMatching (kIOBlockStorageDriverClass),
&disk_list) != kIOReturnSuccess)
{
- syslog (LOG_ERR, "disk-plugin: IOServiceGetMatchingServices failed.");
+ plugin_complain (LOG_ERR, &complain_obj, "disk plugin: "
+ "IOServiceGetMatchingServices failed.");
return;
}
+ else if (complain_obj.interval != 0)
+ {
+ plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: "
+ "IOServiceGetMatchingServices succeeded.");
+ }
while ((disk = IOIteratorNext (disk_list)) != 0)
{
diskstats_t *ds, *pre_ds;
+ static complain_t complain_obj;
+
if ((fh = fopen ("/proc/diskstats", "r")) == NULL)
{
if ((fh = fopen ("/proc/partitions", "r")) == NULL)
+ {
+ plugin_complain (LOG_ERR, &complain_obj, "disk plugin: Failed to open /proc/{diskstats,partitions}.");
return;
+ }
/* Kernel is 2.4.* */
fieldshift = 1;
}
+ plugin_relief (LOG_NOTICE, &complain_obj, "disk plugin: Succeeded to open /proc/{diskstats,partitions}.");
+
while (fgets (buffer, 1024, fh) != NULL)
{
numfields = strsplit (buffer, fields, 32);
(struct sockaddr *) ph->addr, ph->addrlen);
if (ret < 0)
+ {
+#if defined(EHOSTUNREACH)
+ if (errno == EHOSTUNREACH)
+ return (0);
+#endif
+#if defined(ENETUNREACH)
+ if (errno == ENETUNREACH)
+ return (0);
+#endif
ping_set_error (obj, "sendto", strerror (errno));
+ }
return (ret);
}
--- /dev/null
+/**
+ * collectd - src/multimeter.c
+ * Copyright (C) 2005,2006 Peter Holik
+ *
+ * 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:
+ * Peter Holik <peter at holik.at>
+ *
+ * Used multimeter: Metex M-4650CR
+ *
+ **/
+
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <math.h>
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#define MODULE_NAME "multimeter"
+
+static char *multimeter_file = "multimeter.rrd";
+
+static char *ds_def[] =
+{
+ "DS:value:GAUGE:"COLLECTD_HEARTBEAT":U:U",
+ NULL
+};
+static int ds_num = 1;
+
+static int fd = -1;
+
+static int multimeter_timeval_sub (struct timeval *tv1, struct timeval *tv2,
+ struct timeval *res)
+{
+ if ((tv1->tv_sec < tv2->tv_sec) ||
+ ((tv1->tv_sec == tv2->tv_sec) && (tv1->tv_usec < tv2->tv_usec)))
+ return (-1);
+
+ res->tv_sec = tv1->tv_sec - tv2->tv_sec;
+ res->tv_usec = tv1->tv_usec - tv2->tv_usec;
+
+ assert ((res->tv_sec > 0) || ((res->tv_sec == 0) && (res->tv_usec > 0)));
+
+ while (res->tv_usec < 0)
+ {
+ res->tv_usec += 1000000;
+ res->tv_sec--;
+ }
+ return (0);
+}
+#define LINE_LENGTH 14
+static int multimeter_read_value(double *value)
+{
+ int retry = 3; /* sometimes we receive garbadge */
+
+ do
+ {
+ struct timeval time_end;
+
+ tcflush(fd, TCIFLUSH);
+
+ if (gettimeofday (&time_end, NULL) < 0)
+ {
+ syslog (LOG_ERR, MODULE_NAME": gettimeofday failed: %s",
+ strerror (errno));
+ return (-1);
+ }
+ time_end.tv_sec++;
+
+ while (1)
+ {
+ char buf[LINE_LENGTH];
+ char *range;
+ int status;
+ fd_set rfds;
+ struct timeval timeout;
+ struct timeval time_now;
+
+ write(fd, "D", 1);
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ if (gettimeofday (&time_now, NULL) < 0)
+ {
+ syslog (LOG_ERR, MODULE_NAME": gettimeofday failed: %s",
+ strerror (errno));
+ return (-1);
+ }
+ if (multimeter_timeval_sub (&time_end, &time_now, &timeout) == -1)
+ break;
+
+ status = select(fd+1, &rfds, NULL, NULL, &timeout);
+
+ if (status > 0) /* usually we succeed */
+ {
+ status = read(fd, buf, LINE_LENGTH);
+
+ if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+ continue;
+
+ /* Format: "DC 00.000mV \r" */
+ if (status > 0 && status == LINE_LENGTH)
+ {
+ *value = strtod(buf + 2, &range);
+
+ if ( range > (buf + 6) )
+ {
+ range = buf + 9;
+
+ switch ( *range )
+ {
+ case 'p': *value *= 1.0E-12; break;
+ case 'n': *value *= 1.0E-9; break;
+ case 'u': *value *= 1.0E-6; break;
+ case 'm': *value *= 1.0E-3; break;
+ case 'k': *value *= 1.0E3; break;
+ case 'M': *value *= 1.0E6; break;
+ case 'G': *value *= 1.0E9; break;
+ }
+ }
+ else
+ return (-1); /* Overflow */
+
+ return (0); /* value received */
+ }
+ else break;
+ }
+ else if (!status) /* Timeout */
+ {
+ break;
+ }
+ else if ((status == -1) && ((errno == EAGAIN) || (errno == EINTR)))
+ {
+ continue;
+ }
+ else /* status == -1 */
+ {
+ syslog (LOG_ERR, MODULE_NAME": select failed: %s",
+ strerror (errno));
+ break;
+ }
+ }
+ } while (--retry);
+
+ return (-2); /* no value received */
+}
+
+static void multimeter_init (void)
+{
+ int i;
+ char device[] = "/dev/ttyS ";
+
+ for (i = 0; i < 10; i++)
+ {
+ device[strlen(device)-1] = i + '0';
+
+ if ((fd = open(device, O_RDWR | O_NOCTTY)) > 0)
+ {
+ struct termios tios;
+ int rts = TIOCM_RTS;
+ double value;
+
+ tios.c_cflag = B1200 | CS7 | CSTOPB | CREAD | CLOCAL;
+ tios.c_iflag = IGNBRK | IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ tios.c_cc[VTIME] = 3;
+ tios.c_cc[VMIN] = LINE_LENGTH;
+
+ tcflush(fd, TCIFLUSH);
+ tcsetattr(fd, TCSANOW, &tios);
+ ioctl(fd, TIOCMBIC, &rts);
+
+ if (multimeter_read_value(&value) < -1)
+ {
+ close(fd);
+ fd = -1;
+ }
+ else
+ {
+ syslog (LOG_INFO, MODULE_NAME" found (%s)", device);
+ return;
+ }
+ }
+ }
+ syslog (LOG_ERR, MODULE_NAME" not found");
+}
+#undef LINE_LENGTH
+
+static void multimeter_write (char *host, char *inst, char *val)
+{
+ rrd_update_file (host, multimeter_file, val, ds_def, ds_num);
+}
+#define BUFSIZE 128
+static void multimeter_submit (double *value)
+{
+ char buf[BUFSIZE];
+
+ if (snprintf (buf, BUFSIZE, "%u:%f", (unsigned int) curtime, *value) >= BUFSIZE)
+ return;
+
+ plugin_submit (MODULE_NAME, NULL, buf);
+}
+#undef BUFSIZE
+
+static void multimeter_read (void)
+{
+ double value;
+
+ if (fd > -1 && !(multimeter_read_value(&value)))
+ multimeter_submit (&value);
+}
+
+void module_register (void)
+{
+ plugin_register (MODULE_NAME, multimeter_init, multimeter_read, multimeter_write);
+}
+
+#undef MODULE_NAME
else
plugin_write (NULL, type, inst, val);
}
+
+void plugin_complain (int level, complain_t *c, const char *format, ...)
+{
+ char message[512];
+ va_list ap;
+ int step;
+
+ if (c->delay > 0)
+ {
+ c->delay--;
+ return;
+ }
+
+ step = atoi (COLLECTD_STEP);
+ assert (step > 0);
+
+ if (c->interval < step)
+ c->interval = step;
+ else
+ c->interval *= 2;
+
+ if (c->interval > 86400)
+ c->interval = 86400;
+
+ c->delay = c->interval / step;
+
+ va_start (ap, format);
+ vsnprintf (message, 512, format, ap);
+ message[511] = '\0';
+ va_end (ap);
+
+ syslog (level, message);
+}
+
+void plugin_relief (int level, complain_t *c, const char *format, ...)
+{
+ char message[512];
+ va_list ap;
+
+ if (c->interval == 0)
+ return;
+
+ c->interval = 0;
+
+ va_start (ap, format);
+ vsnprintf (message, 512, format, ap);
+ message[511] = '\0';
+ va_end (ap);
+
+ syslog (level, message);
+}
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
/**
* collectd - src/plugin.h
* Copyright (C) 2005,2006 Florian octo Forster
* Florian octo Forster <octo at verplant.org>
**/
-#ifndef PLUGIN_H
-#define PLUGIN_H
+/*
+ *
+ */
+typedef struct complain_s
+{
+ unsigned int interval; /* how long we wait for reporting this error again */
+ unsigned int delay; /* how many more iterations we still need to wait */
+} complain_t;
/*
* NAME
void plugin_submit (char *type, char *inst, char *val);
+
+void plugin_complain (int level, complain_t *c, const char *format, ...);
+void plugin_relief (int level, complain_t *c, const char *format, ...);
+
#endif /* PLUGIN_H */
#include "common.h"
#include "plugin.h"
#include "utils_debug.h"
+#include "configfile.h"
/* Include header files for the mach system, if they exist.. */
-#if HAVE_MACH_MACH_INIT_H
-# include <mach/mach_init.h>
-#endif
-#if HAVE_MACH_HOST_PRIV_H
-# include <mach/host_priv.h>
-#endif
-#if HAVE_MACH_MACH_ERROR_H
-# include <mach/mach_error.h>
-#endif
-#if HAVE_MACH_MACH_HOST_H
-# include <mach/mach_host.h>
-#endif
-#if HAVE_MACH_MACH_PORT_H
-# include <mach/mach_port.h>
-#endif
-#if HAVE_MACH_MACH_TYPES_H
-# include <mach/mach_types.h>
-#endif
-#if HAVE_MACH_MESSAGE_H
-# include <mach/message.h>
-#endif
-#if HAVE_MACH_PROCESSOR_SET_H
-# include <mach/processor_set.h>
-#endif
-#if HAVE_MACH_TASK_H
-# include <mach/task.h>
-#endif
-#if HAVE_MACH_THREAD_ACT_H
-# include <mach/thread_act.h>
-#endif
-#if HAVE_MACH_VM_REGION_H
-# include <mach/vm_region.h>
-#endif
-#if HAVE_MACH_VM_MAP_H
-# include <mach/vm_map.h>
-#endif
-#if HAVE_MACH_VM_PROT_H
-# include <mach/vm_prot.h>
-#endif
+#if HAVE_THREAD_INFO
+# if HAVE_MACH_MACH_INIT_H
+# include <mach/mach_init.h>
+# endif
+# if HAVE_MACH_HOST_PRIV_H
+# include <mach/host_priv.h>
+# endif
+# if HAVE_MACH_MACH_ERROR_H
+# include <mach/mach_error.h>
+# endif
+# if HAVE_MACH_MACH_HOST_H
+# include <mach/mach_host.h>
+# endif
+# if HAVE_MACH_MACH_PORT_H
+# include <mach/mach_port.h>
+# endif
+# if HAVE_MACH_MACH_TYPES_H
+# include <mach/mach_types.h>
+# endif
+# if HAVE_MACH_MESSAGE_H
+# include <mach/message.h>
+# endif
+# if HAVE_MACH_PROCESSOR_SET_H
+# include <mach/processor_set.h>
+# endif
+# if HAVE_MACH_TASK_H
+# include <mach/task.h>
+# endif
+# if HAVE_MACH_THREAD_ACT_H
+# include <mach/thread_act.h>
+# endif
+# if HAVE_MACH_VM_REGION_H
+# include <mach/vm_region.h>
+# endif
+# if HAVE_MACH_VM_MAP_H
+# include <mach/vm_map.h>
+# endif
+# if HAVE_MACH_VM_PROT_H
+# include <mach/vm_prot.h>
+# endif
+/* #endif HAVE_THREAD_INFO */
+
+#elif KERNEL_LINUX
+# if HAVE_LINUX_CONFIG_H
+# include <linux/config.h>
+# endif
+# ifndef CONFIG_HZ
+# define CONFIG_HZ 100
+# endif
+#endif /* KERNEL_LINUX */
#define MODULE_NAME "processes"
#define BUFSIZE 256
-static char *ps_file = "processes.rrd";
-
-static char *ds_def[] =
+static char *processes_file = "processes.rrd";
+static char *processes_ds_def[] =
{
"DS:running:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
"DS:sleeping:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
"DS:blocked:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
NULL
};
-static int ds_num = 6;
+static int processes_ds_num = 6;
+
+static char *ps_rss_file = "processes/ps_rss-%s.rrd";
+static char *ps_rss_ds_def[] =
+{
+ /* max = 2^63 - 1 */
+ "DS:byte:GAUGE:"COLLECTD_HEARTBEAT":0:9223372036854775807",
+ NULL
+};
+static int ps_rss_ds_num = 1;
+
+static char *ps_cputime_file = "processes/ps_cputime-%s.rrd";
+static char *ps_cputime_ds_def[] =
+{
+ /* 1 second in user-mode per second ought to be enough.. */
+ "DS:user:COUNTER:"COLLECTD_HEARTBEAT":0:1000000",
+ "DS:syst:COUNTER:"COLLECTD_HEARTBEAT":0:1000000",
+ NULL
+};
+static int ps_cputime_ds_num = 2;
+
+static char *ps_count_file = "processes/ps_count-%s.rrd";
+static char *ps_count_ds_def[] =
+{
+ "DS:processes:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
+ "DS:threads:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
+ NULL
+};
+static int ps_count_ds_num = 2;
+
+static char *ps_pagefaults_file = "processes/ps_pagefaults-%s.rrd";
+static char *ps_pagefaults_ds_def[] =
+{
+ /* max = 2^63 - 1 */
+ "DS:minflt:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
+ "DS:majflt:COUNTER:"COLLECTD_HEARTBEAT":0:9223372036854775807",
+ NULL
+};
+static int ps_pagefaults_ds_num = 2;
+
+static char *config_keys[] =
+{
+ "Process",
+ NULL
+};
+static int config_keys_num = 1;
+
+typedef struct procstat_entry_s
+{
+ unsigned long id;
+ unsigned long age;
+
+ unsigned long num_proc;
+ unsigned long num_lwp;
+ unsigned long vmem_rss;
+
+ unsigned long vmem_minflt;
+ unsigned long vmem_majflt;
+ unsigned long vmem_minflt_counter;
+ unsigned long vmem_majflt_counter;
+
+ unsigned long cpu_user;
+ unsigned long cpu_system;
+ unsigned long cpu_user_counter;
+ unsigned long cpu_system_counter;
+
+ struct procstat_entry_s *next;
+} procstat_entry_t;
+
+#define PROCSTAT_NAME_LEN 256
+typedef struct procstat
+{
+ char name[PROCSTAT_NAME_LEN];
+
+ unsigned long num_proc;
+ unsigned long num_lwp;
+ unsigned long vmem_rss;
+
+ unsigned long vmem_minflt_counter;
+ unsigned long vmem_majflt_counter;
+
+ unsigned long cpu_user_counter;
+ unsigned long cpu_system_counter;
+
+ struct procstat *next;
+ struct procstat_entry_s *instances;
+} procstat_t;
+
+static procstat_t *list_head_g = NULL;
#if HAVE_THREAD_INFO
static mach_port_t port_host_self;
/* #endif HAVE_THREAD_INFO */
#elif KERNEL_LINUX
-/* No global variables */
+static long pagesize_g;
#endif /* KERNEL_LINUX */
+static void ps_list_register (const char *name)
+{
+ procstat_t *new;
+ procstat_t *ptr;
+
+ if ((new = (procstat_t *) malloc (sizeof (procstat_t))) == NULL)
+ return;
+ memset (new, 0, sizeof (procstat_t));
+ strncpy (new->name, name, PROCSTAT_NAME_LEN);
+
+ for (ptr = list_head_g; ptr != NULL; ptr = ptr->next)
+ {
+ if (strcmp (ptr->name, name) == 0)
+ return;
+ if (ptr->next == NULL)
+ break;
+ }
+
+ if (ptr == NULL)
+ list_head_g = new;
+ else
+ ptr->next = new;
+}
+
+static procstat_t *ps_list_search (const char *name)
+{
+ procstat_t *ptr;
+
+ for (ptr = list_head_g; ptr != NULL; ptr = ptr->next)
+ if (strcmp (ptr->name, name) == 0)
+ break;
+
+ return (ptr);
+}
+
+static void ps_list_add (const char *name, procstat_entry_t *entry)
+{
+ procstat_t *ps;
+ procstat_entry_t *pse;
+
+ if (entry->id == 0)
+ return;
+
+ if ((ps = ps_list_search (name)) == NULL)
+ return;
+
+ for (pse = ps->instances; pse != NULL; pse = pse->next)
+ if ((pse->id == entry->id) || (pse->next == NULL))
+ break;
+
+ if ((pse == NULL) || (pse->id != entry->id))
+ {
+ procstat_entry_t *new;
+
+ new = (procstat_entry_t *) malloc (sizeof (procstat_entry_t));
+ if (new == NULL)
+ return;
+ memset (new, 0, sizeof (procstat_entry_t));
+ new->id = entry->id;
+
+ if (pse == NULL)
+ ps->instances = new;
+ else
+ pse->next = new;
+
+ pse = new;
+ }
+
+ pse->age = 0;
+ pse->num_proc = entry->num_proc;
+ pse->num_lwp = entry->num_lwp;
+ pse->vmem_rss = entry->vmem_rss;
+
+ ps->num_proc += pse->num_proc;
+ ps->num_lwp += pse->num_lwp;
+ ps->vmem_rss += pse->vmem_rss;
+
+ if ((entry->vmem_minflt_counter == 0)
+ && (entry->vmem_majflt_counter == 0))
+ {
+ pse->vmem_minflt_counter += entry->vmem_minflt;
+ pse->vmem_minflt = entry->vmem_minflt;
+
+ pse->vmem_majflt_counter += entry->vmem_majflt;
+ pse->vmem_majflt = entry->vmem_majflt;
+ }
+ else
+ {
+ if (entry->vmem_minflt_counter < pse->vmem_minflt_counter)
+ {
+ pse->vmem_minflt = entry->vmem_minflt_counter
+ + (ULONG_MAX - pse->vmem_minflt_counter);
+ }
+ else
+ {
+ pse->vmem_minflt = entry->vmem_minflt_counter - pse->vmem_minflt_counter;
+ }
+ pse->vmem_minflt_counter = entry->vmem_minflt_counter;
+
+ if (entry->vmem_majflt_counter < pse->vmem_majflt_counter)
+ {
+ pse->vmem_majflt = entry->vmem_majflt_counter
+ + (ULONG_MAX - pse->vmem_majflt_counter);
+ }
+ else
+ {
+ pse->vmem_majflt = entry->vmem_majflt_counter - pse->vmem_majflt_counter;
+ }
+ pse->vmem_majflt_counter = entry->vmem_majflt_counter;
+ }
+
+ ps->vmem_minflt_counter += pse->vmem_minflt;
+ ps->vmem_majflt_counter += pse->vmem_majflt;
+
+ if ((entry->cpu_user_counter == 0)
+ && (entry->cpu_system_counter == 0))
+ {
+ pse->cpu_user_counter += entry->cpu_user;
+ pse->cpu_user = entry->cpu_user;
+
+ pse->cpu_system_counter += entry->cpu_system;
+ pse->cpu_system = entry->cpu_system;
+ }
+ else
+ {
+ if (entry->cpu_user_counter < pse->cpu_user_counter)
+ {
+ pse->cpu_user = entry->cpu_user_counter
+ + (ULONG_MAX - pse->cpu_user_counter);
+ }
+ else
+ {
+ pse->cpu_user = entry->cpu_user_counter - pse->cpu_user_counter;
+ }
+ pse->cpu_user_counter = entry->cpu_user_counter;
+
+ if (entry->cpu_system_counter < pse->cpu_system_counter)
+ {
+ pse->cpu_system = entry->cpu_system_counter
+ + (ULONG_MAX - pse->cpu_system_counter);
+ }
+ else
+ {
+ pse->cpu_system = entry->cpu_system_counter - pse->cpu_system_counter;
+ }
+ pse->cpu_system_counter = entry->cpu_system_counter;
+ }
+
+ ps->cpu_user_counter += pse->cpu_user;
+ ps->cpu_system_counter += pse->cpu_system;
+}
+
+static void ps_list_reset (void)
+{
+ procstat_t *ps;
+ procstat_entry_t *pse;
+ procstat_entry_t *pse_prev;
+
+ for (ps = list_head_g; ps != NULL; ps = ps->next)
+ {
+ ps->num_proc = 0;
+ ps->num_lwp = 0;
+ ps->vmem_rss = 0;
+
+ pse_prev = NULL;
+ pse = ps->instances;
+ while (pse != NULL)
+ {
+ if (pse->age > 10)
+ {
+ DBG ("Removing this procstat entry cause it's too old: "
+ "id = %lu; name = %s;",
+ pse->id, ps->name);
+
+ if (pse_prev == NULL)
+ {
+ ps->instances = pse->next;
+ free (pse);
+ pse = ps->instances;
+ }
+ else
+ {
+ pse_prev->next = pse->next;
+ free (pse);
+ pse = pse_prev->next;
+ }
+ }
+ else
+ {
+ pse->age++;
+ pse_prev = pse;
+ pse = pse->next;
+ }
+ } /* while (pse != NULL) */
+ } /* for (ps = list_head_g; ps != NULL; ps = ps->next) */
+}
+
+static int ps_config (char *key, char *value)
+{
+ if (strcasecmp (key, "Process") == 0)
+ {
+ ps_list_register (value);
+ }
+ else
+ {
+ return (-1);
+ }
+
+ return (0);
+}
+
static void ps_init (void)
{
#if HAVE_THREAD_INFO
/* #endif HAVE_THREAD_INFO */
#elif KERNEL_LINUX
- /* No init */
+ pagesize_g = sysconf(_SC_PAGESIZE);
+ DBG ("pagesize_g = %li; CONFIG_HZ = %i;",
+ pagesize_g, CONFIG_HZ);
#endif /* KERNEL_LINUX */
return;
static void ps_write (char *host, char *inst, char *val)
{
- rrd_update_file (host, ps_file, val, ds_def, ds_num);
+ rrd_update_file (host, processes_file, val,
+ processes_ds_def, processes_ds_num);
+}
+
+static void ps_rss_write (char *host, char *inst, char *val)
+{
+ char filename[256];
+ int status;
+
+ status = snprintf (filename, 256, ps_rss_file, inst);
+ if ((status < 1) || (status >= 256))
+ return;
+
+ rrd_update_file (host, filename, val, ps_rss_ds_def, ps_rss_ds_num);
+}
+
+static void ps_cputime_write (char *host, char *inst, char *val)
+{
+ char filename[256];
+ int status;
+
+ status = snprintf (filename, 256, ps_cputime_file, inst);
+ if ((status < 1) || (status >= 256))
+ return;
+
+ DBG ("host = %s; filename = %s; val = %s;",
+ host, filename, val);
+ rrd_update_file (host, filename, val,
+ ps_cputime_ds_def, ps_cputime_ds_num);
+}
+
+static void ps_count_write (char *host, char *inst, char *val)
+{
+ char filename[256];
+ int status;
+
+ status = snprintf (filename, 256, ps_count_file, inst);
+ if ((status < 1) || (status >= 256))
+ return;
+
+ DBG ("host = %s; filename = %s; val = %s;",
+ host, filename, val);
+ rrd_update_file (host, filename, val,
+ ps_count_ds_def, ps_count_ds_num);
+}
+
+static void ps_pagefaults_write (char *host, char *inst, char *val)
+{
+ char filename[256];
+ int status;
+
+ status = snprintf (filename, 256, ps_pagefaults_file, inst);
+ if ((status < 1) || (status >= 256))
+ return;
+
+ DBG ("host = %s; filename = %s; val = %s;",
+ host, filename, val);
+ rrd_update_file (host, filename, val,
+ ps_pagefaults_ds_def, ps_pagefaults_ds_num);
}
#if PROCESSES_HAVE_READ
plugin_submit (MODULE_NAME, "-", buf);
}
+static void ps_submit_proc_list (procstat_t *ps)
+{
+ char buffer[64];
+
+ if (ps == NULL)
+ return;
+
+ snprintf (buffer, 64, "%u:%lu",
+ (unsigned int) curtime,
+ ps->vmem_rss);
+ buffer[63] = '\0';
+ plugin_submit ("ps_rss", ps->name, buffer);
+
+ snprintf (buffer, 64, "%u:%u:%u",
+ (unsigned int) curtime,
+ /* Make the counter overflow */
+ (unsigned int) (ps->cpu_user_counter & 0xFFFFFFFF),
+ (unsigned int) (ps->cpu_system_counter & 0xFFFFFFFF));
+ buffer[63] = '\0';
+ plugin_submit ("ps_cputime", ps->name, buffer);
+
+ snprintf (buffer, 64, "%u:%lu:%lu",
+ (unsigned int) curtime,
+ ps->num_proc, ps->num_lwp);
+ buffer[63] = '\0';
+ plugin_submit ("ps_count", ps->name, buffer);
+
+ snprintf (buffer, 64, "%u:%lu:%lu",
+ (unsigned int) curtime,
+ ps->vmem_minflt_counter, ps->vmem_majflt_counter);
+ buffer[63] = '\0';
+ plugin_submit ("ps_pagefaults", ps->name, buffer);
+
+ DBG ("name = %s; num_proc = %lu; num_lwp = %lu; vmem_rss = %lu; "
+ "vmem_minflt_counter = %i; vmem_majflt_counter = %i; "
+ "cpu_user_counter = %i; cpu_system_counter = %i;",
+ ps->name, ps->num_proc, ps->num_lwp, ps->vmem_rss,
+ ps->vmem_minflt_counter, ps->vmem_majflt_counter, ps->cpu_user_counter,
+ ps->cpu_system_counter);
+
+}
+
+#if KERNEL_LINUX
+static int *ps_read_tasks (int pid)
+{
+ int *list = NULL;
+ int list_size = 1; /* size of allocated space, in elements */
+ int list_len = 0; /* number of currently used elements */
+
+ char dirname[64];
+ DIR *dh;
+ struct dirent *ent;
+
+ snprintf (dirname, 64, "/proc/%i/task", pid);
+ dirname[63] = '\0';
+
+ if ((dh = opendir (dirname)) == NULL)
+ {
+ syslog (LOG_NOTICE, "processes plugin: Failed to open directory `%s'",
+ dirname);
+ return (NULL);
+ }
+
+ while ((ent = readdir (dh)) != NULL)
+ {
+ if (!isdigit (ent->d_name[0]))
+ continue;
+
+ if ((list_len + 1) >= list_size)
+ {
+ int *new_ptr;
+ int new_size = 2 * list_size;
+ /* Comes in sizes: 2, 4, 8, 16, ... */
+
+ new_ptr = (int *) realloc (list, (size_t) (sizeof (int) * new_size));
+ if (new_ptr == NULL)
+ {
+ if (list != NULL)
+ free (list);
+ syslog (LOG_ERR, "processes plugin: "
+ "Failed to allocate more memory.");
+ return (NULL);
+ }
+
+ list = new_ptr;
+ list_size = new_size;
+
+ memset (list + list_len, 0, sizeof (int) * (list_size - list_len));
+ }
+
+ list[list_len] = atoi (ent->d_name);
+ if (list[list_len] != 0)
+ list_len++;
+ }
+
+ closedir (dh);
+
+ assert (list_len < list_size);
+ assert (list[list_len] == 0);
+
+ return (list);
+}
+
+int ps_read_process (int pid, procstat_t *ps, char *state)
+{
+ char filename[64];
+ char buffer[1024];
+ FILE *fh;
+
+ char *fields[64];
+ char fields_len;
+
+ int *tasks;
+ int i;
+
+ int ppid;
+ int name_len;
+
+ long long unsigned cpu_user_counter;
+ long long unsigned cpu_system_counter;
+ long long unsigned vmem_rss;
+
+ memset (ps, 0, sizeof (procstat_t));
+
+ snprintf (filename, 64, "/proc/%i/stat", pid);
+ filename[63] = '\0';
+
+ if ((fh = fopen (filename, "r")) == NULL)
+ return (-1);
+
+ if (fgets (buffer, 1024, fh) == NULL)
+ {
+ fclose (fh);
+ return (-1);
+ }
+
+ fclose (fh);
+
+ fields_len = strsplit (buffer, fields, 64);
+ if (fields_len < 24)
+ {
+ DBG ("`%s' has only %i fields..",
+ filename, fields_len);
+ return (-1);
+ }
+ else if (fields_len != 41)
+ {
+ DBG ("WARNING: (fields_len = %i) != 41", fields_len);
+ }
+
+ /* copy the name, strip brackets in the process */
+ name_len = strlen (fields[1]) - 2;
+ if ((fields[1][0] != '(') || (fields[1][name_len + 1] != ')'))
+ {
+ DBG ("No brackets found in process name: `%s'", fields[1]);
+ return (-1);
+ }
+ fields[1] = fields[1] + 1;
+ fields[1][name_len] = '\0';
+ strncpy (ps->name, fields[1], PROCSTAT_NAME_LEN);
+
+ ppid = atoi (fields[3]);
+
+ if ((tasks = ps_read_tasks (pid)) == NULL)
+ {
+ /* This happends for zombied, e.g. */
+ DBG ("ps_read_tasks (%i) failed.", pid);
+ *state = 'Z';
+ ps->num_lwp = 0;
+ ps->num_proc = 0;
+ }
+ else
+ {
+ *state = '\0';
+ ps->num_lwp = 0;
+ ps->num_proc = 1;
+ for (i = 0; tasks[i] != 0; i++)
+ ps->num_lwp++;
+
+ free (tasks);
+ tasks = NULL;
+ }
+
+ /* Leave the rest at zero if this is only an LWP */
+ if (ps->num_proc == 0)
+ {
+ DBG ("This is only an LWP: pid = %i; name = %s;",
+ pid, ps->name);
+ return (0);
+ }
+
+ cpu_user_counter = atoll (fields[13]);
+ cpu_system_counter = atoll (fields[14]);
+ vmem_rss = atoll (fields[23]);
+ ps->vmem_minflt_counter = atol (fields[9]);
+ ps->vmem_majflt_counter = atol (fields[11]);
+
+ /* Convert jiffies to useconds */
+ cpu_user_counter = cpu_user_counter * 1000000 / CONFIG_HZ;
+ cpu_system_counter = cpu_system_counter * 1000000 / CONFIG_HZ;
+ vmem_rss = vmem_rss * pagesize_g;
+
+ ps->cpu_user_counter = (unsigned long) cpu_user_counter;
+ ps->cpu_system_counter = (unsigned long) cpu_system_counter;
+ ps->vmem_rss = (unsigned long) vmem_rss;
+
+ *state = fields[2][0];
+
+ /* success */
+ return (0);
+} /* int ps_read_process (...) */
+#endif /* KERNEL_LINUX */
+
static void ps_read (void)
{
#if HAVE_THREAD_INFO
int paging = 0;
int blocked = 0;
- char buf[BUFSIZE];
- char filename[20]; /* need 17 bytes */
- char *fields[BUFSIZE];
-
struct dirent *ent;
- DIR *proc;
- FILE *fh;
+ DIR *proc;
+ int pid;
+
+ int status;
+ procstat_t ps;
+ procstat_entry_t pse;
+ char state;
+
+ procstat_t *ps_ptr;
running = sleeping = zombies = stopped = paging = blocked = 0;
+ ps_list_reset ();
if ((proc = opendir ("/proc")) == NULL)
{
if (!isdigit (ent->d_name[0]))
continue;
- if (snprintf (filename, 20, "/proc/%s/stat", ent->d_name) >= 20)
+ if ((pid = atoi (ent->d_name)) < 1)
continue;
- if ((fh = fopen (filename, "r")) == NULL)
+ status = ps_read_process (pid, &ps, &state);
+ if (status != 0)
{
- syslog (LOG_NOTICE, "Cannot open `%s': %s", filename,
- strerror (errno));
+ DBG ("ps_read_process failed: %i", status);
continue;
}
- if (fgets (buf, BUFSIZE, fh) == NULL)
- {
- syslog (LOG_NOTICE, "Unable to read from `%s': %s",
- filename, strerror (errno));
- fclose (fh);
- continue;
- }
+ pse.id = pid;
+ pse.age = 0;
- fclose (fh);
+ pse.num_proc = ps.num_proc;
+ pse.num_lwp = ps.num_lwp;
+ pse.vmem_rss = ps.vmem_rss;
- if (strsplit (buf, fields, BUFSIZE) < 3)
- {
- DBG ("Line has less than three fields.");
- continue;
- }
+ pse.vmem_minflt = 0;
+ pse.vmem_minflt_counter = ps.vmem_minflt_counter;
+ pse.vmem_majflt = 0;
+ pse.vmem_majflt_counter = ps.vmem_majflt_counter;
- switch (fields[2][0])
+ pse.cpu_user = 0;
+ pse.cpu_user_counter = ps.cpu_user_counter;
+ pse.cpu_system = 0;
+ pse.cpu_system_counter = ps.cpu_system_counter;
+
+ switch (state)
{
case 'R': running++; break;
case 'S': sleeping++; break;
case 'T': stopped++; break;
case 'W': paging++; break;
}
+
+ ps_list_add (ps.name, &pse);
}
closedir (proc);
ps_submit (running, sleeping, zombies, stopped, paging, blocked);
+
+ for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
+ ps_submit_proc_list (ps_ptr);
#endif /* KERNEL_LINUX */
}
#else
void module_register (void)
{
plugin_register (MODULE_NAME, ps_init, ps_read, ps_write);
+ plugin_register ("ps_rss", NULL, NULL, ps_rss_write);
+ plugin_register ("ps_cputime", NULL, NULL, ps_cputime_write);
+ plugin_register ("ps_count", NULL, NULL, ps_count_write);
+ plugin_register ("ps_pagefaults", NULL, NULL, ps_pagefaults_write);
+ cf_register (MODULE_NAME, ps_config, config_keys, config_keys_num);
}
#undef BUFSIZE
DIR *proc;
struct dirent *dent; /* 42 */
+ static complain_t complain_obj;
+
errno = 0;
- if (NULL == (proc = opendir (PROCDIR))) {
- syslog (LOG_ERR, "Cannot open '%s': %s", PROCDIR, strerror (errno));
+ if (NULL == (proc = opendir (PROCDIR)))
+ {
+ plugin_complain (LOG_ERR, &complain_obj, "vserver plugin: "
+ "fopen (%s) failed: %s", PROCDIR, strerror (errno));
return;
}
+ plugin_relief (LOG_NOTICE, &complain_obj, "vserver plugin: "
+ "fopen (%s) succeeded.", PROCDIR);
while (NULL != (dent = readdir (proc))) {
int len;