-This package was written by:
- Florian octo Forster <octo at verplant.org>
+Permanent project members
+=========================
-apcups plugin by:
- Anthony Gialluca <tonyabg at charter.net>
+Florian "octo" Forster <octo at verplant.org>
+ - Initial author.
-cpufreq, multimeter and irq plugin, as well as some bugfixes in the exec plugin
-by:
- Peter Holik <peter at holik.at>
+Sebastian "tokkee" Harl <sh at tokkee.org>
+ - Bugfixes and enhancments in many places all around the project.
+ - perl plugin.
+ - users plugin.
+ - vserver plugin.
+ - Debian package.
-hddtemp plugin by:
- Vincent Stehlé <vincent.stehle at free.fr>
-iptables plugin by:
- Sjoerd van der Berg <harekiet at gmail.com>
+Contributors (sorted alphabetically)
+====================================
-libvirt plugin by:
- Richard W. M. Jones <rjones at redhat.com>
+Alessandro Iurlano <alessandro.iurlano at gmail.com>
+ - Initial filecount plugin.
-mbmon plugin by:
- Flavio Stanchina <flavio at stanchina.net>
+Alvaro Barcellos <alvaro.barcellos at gmail.com>
+ - Don't-fork patch.
-memcached plugin by:
- Antony Dovgal <tony at daylessday.org>
+Anthony Gialluca <tonyabg at charter.net>
+ - apcups plugin.
-nfs plugin by:
- Jason Pepas <cell at ices.utexas.edu>
+Antony Dovgal <tony at daylessday.org>
+ - memcached plugin.
-perl plugin by:
- Sebastian Harl <sh at tokkee.org>
+Christophe Kalt <collectd at klb.taranis.org>
+ - The version 3 `log' mode.
+ - Many Solaris related hints and fixes.
-powerdns plugin and initial `tail' subsystem by:
- Luke Herberling <collectd at c-ware.com>
+Dan Berrange <berrange at redhat.com>
+ - uuid plugin.
-processes plugin by:
- Lyonel Vincent <lyonel at ezix.org>
+David Bacher <drbacher at gmail.com>
+ - serial plugin.
-sensors plugin has been improved by:
- Luboš Staněk <kolektor at atlas.cz>
+Flavio Stanchina <flavio at stanchina.net>
+ - mbmon plugin.
-serial plugin by:
- David Bacher <drbacher at gmail.com>
+Jason Pepas <cell at ices.utexas.edu>
+ - nfs plugin.
-tape plugin by:
- Scott Garrett <sgarrett at technomancer.com>
+Luboš Staněk <kolektor at atlas.cz>
+ - sensors plugin improvements.
+ - Time and effort to find a nasty bug in the ntpd-plugin.
-teamspeak2 plugin by:
- Stefan Hacker <stefan.hacker at web.de>
+Luke Herberling <collectd at c-ware.com>
+ - powerdns plugin.
+ - Initial `tail' subsystem by:
-users plugin by:
- Sebastian Harl <sh at tokkee.org>
+Lyonel Vincent <lyonel at ezix.org>
+ - processes plugin.
-uuid plugin by:
- Dan Berrange <berrange at redhat.com>
- Richard W.M. Jones <rjones at redhat.com>
+Michael Stapelberg <michael+git@stapelberg.de>
+ - OpenBSD port of the tcpconns plugin.
-vserver plugin by:
- Sebastian Harl <sh at tokkee.org>
+Niki W. Waibel <niki.waibel at newlogic.com>
+ - Initial autotools fixes.
+ - libltdl code.
+ - getmnt-wizardry.
-PID-file patch by:
- Tommie Gannert <d00-tga at d.kth.se>
+Oleg King <king2 at kaluga.ru>
+ - Added support for the statgrab library to
+ + the cpu plugin,
+ + the disk plugin, and
+ + the users plugin.
-Don't-fork-patch by:
- Alvaro Barcellos <alvaro.barcellos at gmail.com>
+Peter Holik <peter at holik.at>
+ - cpufreq plugin.
+ - multimeter plugin.
+ - irq plugin.
+ - Some bugfixes in the exec plugin.
+ - Notifications in the ipmi plugin.
-Many autotools related fixes, libltdl code, getmnt-wizardry and much help has
-contributed:
- Niki W. Waibel <niki.waibel at newlogic.com>
+Richard W. M. Jones <rjones at redhat.com>
+ - libvirt plugin.
+ - uuid plugin.
-The `log' mode has been written by:
- Christophe Kalt <collectd at klb.taranis.org>
+Scott Garrett <sgarrett at technomancer.com>
+ - tape plugin.
-Much time and effort to find a nasty bug in the ntpd-plugin has been
-contributed by:
- Luboš Staněk <lubek at users.sourceforge.net>
+Sjoerd van der Berg <harekiet at gmail.com>
+ - iptables plugin.
-Support for the statgrab library has been added to the cpu, disk and users
-plugins by
- Oleg King <king2 at kaluga.ru>
+Stefan Hacker <stefan.hacker at web.de>
+ - teamspeak2 plugin.
+
+Tommie Gannert <d00-tga at d.kth.se>
+ - PID-file patch.
+
+Vincent Stehlé <vincent.stehle at free.fr>
+ - hddtemp plugin.
collectd is available at:
<http://collectd.org/>
+2008-10-16, Version 4.5.1
+ * build system: Change `--enable-<plugin>' to abort with an error if
+ dependencies are not met. Thanks to Bruno Prémont for the patch.
+ Also, the poisoning of various string functions has been restricted
+ to debug builds.
+ * collectd: Fix a memory leak in the global value cache. With every
+ *missing* value a couple of bytes would be leaked. Another memory
+ leak in the configuration handling code has been fixed. Thanks to
+ Niraj Tolia for reporting these issues.
+ * collectd: Fix an off-by-one error in the ignorelist functionality.
+ When using regular expressions, the last character would be missing,
+ possibly matching differently from what one would expect.
+ * collectdmon: Don't block SIGCHLD. This fixes a potential portability
+ problem.
+ * collectd-nagios: Fix handling of the `-d' option. Thanks to Fabian
+ Linzberger for reporting the bug.
+ * iptables plugin: Fix an off-by-one error. If a string was just one
+ character too long, it was truncated instead of reporting an error.
+ * network plugin: Fix a memory leak in the configuration handling
+ code. Thanks to Niraj Tolia for reporting this issue.
+ * perl plugin: Log an error message if bootstrapping `Collectd' fails.
+ * postgresql plugin: Don't reopen connection during reinitialization.
+ This fixes a bug under Solaris and potentially other platforms.
+ Missing calls to `PQclear' have been added, too. This fixes memory
+ leaks. Thanks to ``Admin'' for reporting these bugs.
+ * snmp plugin: Don't expect null-terminated strings from the Net-SNMP
+ library.
+ * tail plugin: Call `clearerr(3)' after reading an EOF. This fixes
+ problems with some `libc's. Thanks to Matthias Lay for reporting the
+ bug.
+
+2008-09-04, Version 4.5.0
+ * collectd: Added the ability to flush certain identifiers.
+ * collectd: The concept of `notification meta data' has been
+ introduced.
+ * filecount plugin: The new filecount plugin counts the number of
+ files in a directory and its subdirectories.
+ * ipmi plugin: Sensor names have been changed to ensure unique names.
+ Notifications upon added and removed sensors can now be generated.
+ * notify_desktop plugin: This new plugin sends notifications to the
+ X desktop using the structure defined in the `Desktop Notification
+ Specification'.
+ * notify_email plugin: This new plugin sends out notifications via
+ email, using the `esmtp' library.
+ * onewire plugin: The new experimental(!) onewire plugin reads values,
+ such as temperatures, from sensors connected to the computer via the
+ onewire bus.
+ * perl plugin: Improved synchronized access to internal data structures
+ and fixed a possible dead-lock.
+ * perl plugin: Added the ability to flush certain identifiers and marked
+ plugin_flush_all() and plugin_flush_one() as deprecated in favor of
+ plugin_flush().
+ * perl plugin: Added the ability to configure Perl plugins.
+ * postgresql plugin: The new postgresql plugin collects statistics
+ about or from a PostgreSQL database.
+ * processes plugin: The `ProcessMatch' option has been added.
+ * rrdtool plugin: Implement throttling of the `update queue' to lessen
+ IO load.
+ * tcpconns plugin: This plugin has been ported to OpenBSD.
+ * thermal plugin: The new thermal plugin collects system temperatures
+ using Linux ACPI thermal zone data.
+
2008-10-16, Version 4.4.4
* build system: Change `--enable-<plugin>' to abort with an error if
dependencies are not met. Thanks to Bruno Prémont for the patch.
Values gathered by a custom program or script.
See collectd-exec(5).
+ - filecount
+ Count the number of files in directories.
+
- hddtemp
Harddisk temperatures using hddtempd.
Network UPS tools: UPS current, voltage, power, charge, utilisation,
temperature, etc. See upsd(8).
+ - onewire (EXPERIMENTAL!)
+ Read onewire sensors using the owcapu library of the owfs project.
+ Please read in collectd.conf(5) why this plugin is experimental.
+
- perl
The perl plugin implements a Perl-interpreter into collectd. You can
write your own plugins in Perl and return arbitrary values using this
Network latency: Time to reach the default gateway or another given
host.
+ - postgresql
+ PostgreSQL database statistics: active server connections, transaction
+ numbers, block IO, table row manipulations.
+
- processes
Process counts: Number of running, sleeping, zombie, ... processes.
* Notifications can be handled by the following plugins:
+ - notify_desktop
+ Send a desktop notification to a notification daemon, as defined in
+ the Desktop Notification Specification. To actually display the
+ notifications, notification-daemon is required.
+ See http://www.galago-project.org/specs/notification/.
+
+ - notify_email
+ Send an E-mail with the notification message to the configured
+ recipients.
+
- exec
Execute a program or script to handle the notification.
See collectd-exec(5).
used and should be found in various implementations for hopefully all
platforms.
+ * CoreFoundation.framework and IOKit.framework (optional)
+ For compiling on Darwin in general and the `apple_sensors' plugin in
+ particular.
+
* libcurl (optional)
If you want to use the `apache', `ascent', or `nginx' plugin.
+ * libesmtp (optional)
+ For the `notify_email' plugin.
+
* libhal (optional)
If present, the uuid plugin will check for UUID from HAL.
* libnetsnmp (optional)
For the `snmp' plugin.
+ * libnotify (optional)
+ For the `notify_desktop' plugin.
+
* liboping (optional, if not found a version shipped with this distribution
can be used)
Used by the `ping' plugin to send and receive ICMP packets.
+ * libowcapi (optional)
+ Used by the `onewire' plugin to read values from onewire sensors (or the
+ owserver(1) daemon).
+
* libpcap (optional)
Used to capture packets by the `dns' plugin.
Obviously used by the `perl' plugin. The library has to be compiled with
ithread support (introduced in Perl 5.6.0).
+ * libpq (optional)
+ The PostgreSQL C client library used by the `postgresql' plugin.
+
* librrd (optional; headers and library; rrdtool 1.0 and 1.2 both work fine)
If built without `librrd' the resulting binary will be `client only', i.e.
will send its values via multicast and not create any RRD files itself.
Alternatively you can chose to write CSV-files (Comma Separated Values)
instead.
+ * librt, libsocket, libkstat, libdevinfo (optional)
+ Various standard Solaris libraries which provide system functions.
+
* libsensors (optional)
To read from `lm_sensors', see the `sensors' plugin.
- * libstatgrab may be used to collect statistics on systems other than Linux
- and/or Solaris. Note that CPU- and disk-statistics, while being provided
- by this library, are not supported in collectd right now..
+ * libstatgrab (optional) may be used to collect statistics on systems other
+ than Linux and/or Solaris. Note that CPU- and disk-statistics, while being
+ provided by this library, are not supported in collectd right now..
<http://www.i-scream.org/libstatgrab/>
* libupsclient/nut (optional)
For the `nut' plugin which queries nut's `upsd'.
- * libxmms (optional)
-
- * librt, libsocket, libkstat, libdevinfo
- Various standard Solaris libraries which provide system functions.
-
- * CoreFoundation.framework and IOKit.framework
- For compiling on Darwin in general and the `apple_sensors' plugin in
- particular.
-
* libvirt (optional)
Collect statistics from virtual machines.
* libxml2 (optional)
Parse XML data. This is needed for the `ascent' and `libvirt' plugins.
+ * libxmms (optional)
+
Configuring / Compiling / Installing
------------------------------------
-For version 4.4:
-* PowerDNS plugin
-
-For version 4.3:
-* unixsock plugin: Remove the custom cache if possible.
+* Parse options/identifiers with spaces in them correctly.
+* Figure out what to do with the onewire plugin.
+* Custom notification messages?
src/battery.c: commend not working code.
TYPE_LOG
TYPE_NOTIF
TYPE_FLUSH
+ TYPE_CONFIG
TYPE_DATASET
) ],
'ds_types' => [ qw(
Exporter::export_ok_tags ('all');
my @plugins : shared = ();
+my %cf_callbacks : shared = ();
my %types = (
TYPE_INIT, "init",
sub plugin_call_all {
my $type = shift;
+ my %plugins;
+
our $cb_name = undef;
if (! defined $type) {
return;
}
- lock @plugins;
- foreach my $plugin (keys %{$plugins[$type]}) {
- my $p = $plugins[$type]->{$plugin};
+ {
+ lock %{$plugins[$type]};
+ %plugins = %{$plugins[$type]};
+ }
+
+ foreach my $plugin (keys %plugins) {
+ my $p = $plugins{$plugin};
my $status = 0;
return;
}
- if ((! defined $plugins[$type]) && (TYPE_DATASET != $type)) {
+ if ((! defined $plugins[$type]) && (TYPE_DATASET != $type)
+ && (TYPE_CONFIG != $type)) {
ERROR ("Collectd::plugin_register: Invalid type \"$type\"");
return;
}
if ((TYPE_DATASET == $type) && ("ARRAY" eq ref $data)) {
return plugin_register_data_set ($name, $data);
}
+ elsif ((TYPE_CONFIG == $type) && (! ref $data)) {
+ my $pkg = scalar caller;
+
+ if ($data !~ m/^$pkg\:\:/) {
+ $data = $pkg . "::" . $data;
+ }
+
+ lock %cf_callbacks;
+ $cf_callbacks{$name} = $data;
+ }
elsif ((TYPE_DATASET != $type) && (! ref $data)) {
my $pkg = scalar caller;
cb_name => $data,
);
- lock @plugins;
+ lock %{$plugins[$type]};
$plugins[$type]->{$name} = \%p;
}
else {
if (TYPE_DATASET == $type) {
return plugin_unregister_data_set ($name);
}
+ elsif (TYPE_CONFIG == $type) {
+ lock %cf_callbacks;
+ delete $cf_callbacks{$name};
+ }
elsif (defined $plugins[$type]) {
- lock @plugins;
+ lock %{$plugins[$type]};
delete $plugins[$type]->{$name};
}
else {
my %args = @_;
my $timeout = -1;
+ my @plugins = ();
+ my @ids = ();
DEBUG ("Collectd::plugin_flush:"
. (defined ($args{'timeout'}) ? " timeout = $args{'timeout'}" : "")
- . (defined ($args{'plugins'}) ? " plugins = $args{'plugins'}" : ""));
+ . (defined ($args{'plugins'}) ? " plugins = $args{'plugins'}" : "")
+ . (defined ($args{'identifiers'})
+ ? " identifiers = $args{'identifiers'}" : ""));
if (defined ($args{'timeout'}) && ($args{'timeout'} > 0)) {
$timeout = $args{'timeout'};
}
- if (! defined $args{'plugins'}) {
- plugin_flush_all ($timeout);
+ if (defined ($args{'plugins'})) {
+ if ("ARRAY" eq ref ($args{'plugins'})) {
+ @plugins = @{$args{'plugins'}};
+ }
+ else {
+ @plugins = ($args{'plugins'});
+ }
}
else {
- if ("ARRAY" eq ref ($args{'plugins'})) {
- foreach my $plugin (@{$args{'plugins'}}) {
- plugin_flush_one ($timeout, $plugin);
- }
+ @plugins = (undef);
+ }
+
+ if (defined ($args{'identifiers'})) {
+ if ("ARRAY" eq ref ($args{'identifiers'})) {
+ @ids = @{$args{'identifiers'}};
}
else {
- plugin_flush_one ($timeout, $args{'plugins'});
+ @ids = ($args{'identifiers'});
}
}
+ else {
+ @ids = (undef);
+ }
+
+ foreach my $plugin (@plugins) {
+ foreach my $id (@ids) {
+ _plugin_flush($plugin, $timeout, $id);
+ }
+ }
+}
+
+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 _plugin_dispatch_config {
+ my $plugin = shift;
+ my $config = shift;
+
+ our $cb_name = undef;
+
+ if (! (defined ($plugin) && defined ($config))) {
+ return;
+ }
+
+ if (! defined $cf_callbacks{$plugin}) {
+ WARNING ("Found a configuration for the \"$plugin\" plugin, but "
+ . "the plugin isn't loaded or didn't register "
+ . "a configuration callback.");
+ return;
+ }
+
+ {
+ lock %cf_callbacks;
+ $cb_name = $cf_callbacks{$plugin};
+ }
+ call_by_name ($config);
}
1;
use IO::Socket::UNIX;
use Regexp::Common (qw(number));
+our $Debug = 0;
+
return (1);
+sub _debug
+{
+ if (!$Debug)
+ {
+ return;
+ }
+ print @_;
+}
+
sub _create_socket
{
my $path = shift;
return ($sock);
} # _create_socket
-=head1 VALUE IDENTIFIER
+=head1 VALUE IDENTIFIERS
The values in the collectd are identified using an five-tuple (host, plugin,
plugin-instance, type, type-instance) where only plugin-instance and
return ($ident);
} # _parse_identifier
+sub _escape_argument
+{
+ my $string = shift;
+
+ if ($string =~ m/^\w+$/)
+ {
+ return ("$string");
+ }
+
+ $string =~ s#\\#\\\\#g;
+ $string =~ s#"#\\"#g;
+ $string = "\"$string\"";
+
+ return ($string);
+}
+
=head1 PUBLIC METHODS
=over 4
my %args = @_;
my $status;
- my $fh = $obj->{'sock'} or confess;
+ my $fh = $obj->{'sock'} or confess ('object has no filehandle');
my $msg;
my $identifier;
$identifier = _create_identifier (\%args) or return;
- $msg = "GETVAL $identifier\n";
- #print "-> $msg";
- send ($fh, $msg, 0) or confess ("send: $!");
+ $msg = 'GETVAL ' . _escape_argument ($identifier) . "\n";
+ _debug "-> $msg";
+ print $fh $msg;
- $msg = undef;
- recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
- #print "<- $msg";
+ $msg = <$fh>;
+ chomp ($msg);
+ _debug "<- $msg\n";
($status, $msg) = split (' ', $msg, 2);
if ($status <= 0)
return;
}
- for (split (' ', $msg))
+ for (my $i = 0; $i < $status; $i++)
{
- my $entry = $_;
+ my $entry = <$fh>;
+ chomp ($entry);
+ _debug "<- $entry\n";
+
if ($entry =~ m/^(\w+)=NaN$/)
{
$ret->{$1} = undef;
Submits a value-list to the daemon. If the B<time> argument is omitted
C<time()> is used. The required argument B<values> is a reference to an array
of values that is to be submitted. The number of values must match the number
-of values expected for the given B<type> (see L<VALUE IDENTIFIER>), though this
-is checked by the daemon, not the Perl module. Also, gauge data-sources
+of values expected for the given B<type> (see L<VALUE IDENTIFIERS>), though
+this is checked by the daemon, not the Perl module. Also, gauge data-sources
(e.E<nbsp>g. system-load) may be C<undef>. Returns true upon success and false
otherwise.
if (defined $args{'interval'})
{
- $interval = ' interval=' . $args{'interval'};
+ $interval = ' interval='
+ . _escape_argument ($args{'interval'});
}
$identifier = _create_identifier (\%args) or return;
$values = join (':', $time, map { defined ($_) ? $_ : 'U' } (@{$args{'values'}}));
}
- $msg = "PUTVAL $identifier$interval $values\n";
- #print "-> $msg";
- send ($fh, $msg, 0) or confess ("send: $!");
- $msg = undef;
- recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
- #print "<- $msg";
+ $msg = 'PUTVAL '
+ . _escape_argument ($identifier)
+ . $interval
+ . ' ' . _escape_argument ($values) . "\n";
+ _debug "-> $msg";
+ print $fh $msg;
+
+ $msg = <$fh>;
+ chomp ($msg);
+ _debug "<- $msg\n";
($status, $msg) = split (' ', $msg, 2);
return (1) if ($status == 0);
my $status;
my $fh = $obj->{'sock'} or confess;
- $msg = "LISTVAL\n";
- send ($fh, $msg, 0) or confess ("send: $!");
+ _debug "LISTVAL\n";
+ print $fh "LISTVAL\n";
$msg = <$fh>;
+ chomp ($msg);
+ _debug "<- $msg\n";
($status, $msg) = split (' ', $msg, 2);
if ($status < 0)
{
$msg = <$fh>;
chomp ($msg);
+ _debug "<- $msg\n";
($time, $ident) = split (' ', $msg, 2);
my $fh = $obj->{'sock'} or confess;
my $msg; # message sent to the socket
- my $opt_msg; # message of the notification
if (!$args{'message'})
{
$args{'time'} = time ();
}
- $opt_msg = $args{'message'};
- delete ($args{'message'});
-
$msg = 'PUTNOTIF '
- . join (' ', map { $_ . '=' . $args{$_} } (keys %args))
- . " message=$opt_msg\n";
+ . join (' ', map { $_ . '=' . _escape_argument ($args{$_}) } (keys %args))
+ . "\n";
- send ($fh, $msg, 0) or confess ("send: $!");
- $msg = undef;
- recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
+ _debug "-> $msg";
+ print $fh $msg;
+
+ $msg = <$fh>;
+ chomp ($msg);
+ _debug "<- $msg\n";
($status, $msg) = split (' ', $msg, 2);
return (1) if ($status == 0);
return;
} # putnotif
-=item I<$obj>-E<gt>B<flush> (B<timeout> =E<gt> I<$timeout>, B<plugins> =E<gt> [...]);
+=item I<$obj>-E<gt>B<flush> (B<timeout> =E<gt> I<$timeout>, B<plugins> =E<gt> [...], B<identifier> =E<gt> [...]);
Flush cached data.
=item B<plugins>
-If this option is specified, only the selected plugins will be flushed.
+If this option is specified, only the selected plugins will be flushed. The
+argument is a reference to an array of strings.
+
+=item B<identifier>
+
+If this option is specified, only the given identifier(s) will be flushed. The
+argument is a reference to an array of identifiers. Identifiers, in this case,
+are hash references and have the members as outlined in L<VALUE IDENTIFIERS>.
=back
my $status = 0;
my $msg = "FLUSH";
- if ($args{'timeout'})
+ if (defined ($args{'timeout'}))
{
$msg .= " timeout=" . $args{'timeout'};
}
}
}
+ if ($args{'identifier'})
+ {
+ for (@{$args{'identifier'}})
+ {
+ my $identifier = $_;
+ my $ident_str;
+
+ if (ref ($identifier) ne 'HASH')
+ {
+ cluck ("The argument of the `identifier' "
+ . "option must be an array reference "
+ . "of hash references.");
+ return;
+ }
+
+ $ident_str = _create_identifier ($identifier);
+ if (!$ident_str)
+ {
+ return;
+ }
+
+ $msg .= ' identifier=' . _escape_argument ($ident_str);
+ }
+ }
+
$msg .= "\n";
- send ($fh, $msg, 0) or confess ("send: $!");
- $msg = undef;
- recv ($fh, $msg, 1024, 0) or confess ("recv: $!");
+ _debug "-> $msg";
+ print $fh $msg;
+
+ $msg = <$fh>;
+ chomp ($msg);
+ _debug "<- $msg\n";
($status, $msg) = split (' ', $msg, 2);
return (1) if ($status == 0);
return;
}
+sub error
+{
+ my $obj = shift;
+ if ($obj->{'error'})
+ {
+ return ($obj->{'error'});
+ }
+ return;
+}
+
=item I<$obj>-E<gt>destroy ();
Closes the socket before the object is destroyed. This function is also
*darwin*)
ac_system="Darwin"
;;
+ *openbsd*)
+ ac_system="OpenBSD"
+ ;;
*)
ac_system="unknown"
esac
AC_HEADER_SYS_WAIT
AC_HEADER_DIRENT
-AC_CHECK_HEADERS(stdint.h stdio.h errno.h math.h stdarg.h syslog.h fcntl.h signal.h assert.h sys/types.h sys/socket.h sys/select.h poll.h netdb.h arpa/inet.h sys/resource.h sys/param.h kstat.h regex.h sys/ioctl.h endian.h sys/isa_defs.h)
+AC_CHECK_HEADERS(stdio.h stdint.h stdbool.h errno.h math.h stdarg.h syslog.h fcntl.h signal.h assert.h sys/types.h sys/socket.h sys/select.h poll.h netdb.h arpa/inet.h sys/resource.h sys/param.h kstat.h regex.h sys/ioctl.h endian.h sys/isa_defs.h)
# For ping library
AC_CHECK_HEADERS(netinet/in_systm.h, [], [],
fi
with_libkvm="no"
+AC_CHECK_LIB(kvm, kvm_getprocs, [with_kvm_getprocs="yes"], [with_kvm_getprocs="no"])
+if test "x$with_kvm_getprocs" = "xyes"
+then
+ AC_DEFINE(HAVE_LIBKVM_GETPROCS, 1,
+ [Define to 1 if you have the 'kvm' library with the 'kvm_getprocs' symbol (-lkvm)])
+ with_libkvm="yes"
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETPROCS, test "x$with_kvm_getprocs" = "xyes")
+
AC_CHECK_LIB(kvm, kvm_getswapinfo, [with_kvm_getswapinfo="yes"], [with_kvm_getswapinfo="no"])
if test "x$with_kvm_getswapinfo" = "xyes"
then
fi
AM_CONDITIONAL(BUILD_WITH_LIBKVM_GETSWAPINFO, test "x$with_kvm_getswapinfo" = "xyes")
+AC_CHECK_LIB(kvm, kvm_nlist, [with_kvm_nlist="yes"], [with_kvm_nlist="no"])
+if test "x$with_kvm_nlist" = "xyes"
+then
+ AC_DEFINE(HAVE_LIBKVM_NLIST, 1,
+ [Define to 1 if you have the 'kvm' library with the 'kvm_nlist' symbol (-lkvm)])
+ with_libkvm="yes"
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBKVM_NLIST, test "x$with_kvm_nlist" = "xyes")
+
+AC_CHECK_LIB(kvm, kvm_openfiles, [with_kvm_openfiles="yes"], [with_kvm_openfiles="no"])
+if test "x$with_kvm_openfiles" = "xyes"
+then
+ AC_DEFINE(HAVE_LIBKVM_NLIST, 1,
+ [Define to 1 if you have the 'kvm' library with the 'kvm_openfiles' symbol (-lkvm)])
+ with_libkvm="yes"
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBKVM_OPENFILES, test "x$with_kvm_openfiles" = "xyes")
+
with_sensors_cflags=""
with_sensors_ldflags=""
AC_ARG_WITH(lm-sensors, [AS_HELP_STRING([--with-lm-sensors@<:@=PREFIX@:>@], [Path to lm_sensors.])],
AM_CONDITIONAL(BUILD_WITH_LIBOPING, test "x$with_liboping" = "xyes")
AM_CONDITIONAL(BUILD_WITH_OWN_LIBOPING, test "x$with_own_liboping" = "xyes")
+with_libowcapi_cppflags=""
+with_libowcapi_libs="-lowcapi"
+AC_ARG_WITH(libowcapi, [AS_HELP_STRING([--with-libowcapi@<:@=PREFIX@:>@], [Path to libowcapi.])],
+[
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ then
+ with_libowcapi_cppflags="-I$withval/include"
+ with_libowcapi_libs="-L$withval/lib -lowcapi"
+ with_libowcapi="yes"
+ else
+ with_libowcapi="$withval"
+ fi
+],
+[
+ with_libowcapi="yes"
+])
+if test "x$with_libowcapi" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$with_libowcapi_cppflags"
+
+ AC_CHECK_HEADERS(owcapi.h, [with_libowcapi="yes"], [with_libowcapi="no (owcapi.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libowcapi" = "xyes"
+then
+ SAVE_LDFLAGS="$LDFLAGS"
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ LDFLAGS="$with_libowcapi_libs"
+ CPPFLAGS="$with_libowcapi_cppflags"
+
+ AC_CHECK_LIB(owcapi, OW_get, [with_libowcapi="yes"], [with_libowcapi="no (libowcapi not found)"])
+
+ LDFLAGS="$SAVE_LDFLAGS"
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libowcapi" = "xyes"
+then
+ BUILD_WITH_LIBOWCAPI_CPPFLAGS="$with_libowcapi_cppflags"
+ BUILD_WITH_LIBOWCAPI_LIBS="$with_libowcapi_libs"
+ AC_SUBST(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBOWCAPI_LIBS)
+fi
+
+
AC_ARG_WITH(libpcap, [AS_HELP_STRING([--with-libpcap@<:@=PREFIX@:>@], [Path to libpcap.])],
[
if test "x$withval" != "xno" && test "x$withval" != "xyes"
[Wether or not to use the pcap library])
AM_CONDITIONAL(BUILD_WITH_LIBPCAP, test "x$with_libpcap" = "xyes")
+AC_ARG_WITH(libesmtp, [AS_HELP_STRING([--with-libesmtp@<:@=PREFIX@:>@], [Path to libesmtp.])],
+[
+ if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ then
+ LDFLAGS="$LDFLAGS -L$withval/lib"
+ CPPFLAGS="$CPPFLAGS -I$withval/include -D_THREAD_SAFE"
+ with_libesmtp="yes"
+ else
+ with_libesmtp="$withval"
+ fi
+],
+[
+ with_libesmtp="yes"
+])
+if test "x$with_libesmtp" = "xyes"
+then
+ AC_CHECK_LIB(esmtp, smtp_create_session,
+ [
+ AC_DEFINE(HAVE_LIBESMTP, 1, [Define to 1 if you have the esmtp library (-lesmtp).])
+ ], [with_libesmtp="no (libesmtp not found)"])
+fi
+if test "x$with_libesmtp" = "xyes"
+then
+ AC_CHECK_HEADERS(libesmtp.h,
+ [
+ AC_DEFINE(HAVE_LIBESMTP_H, 1, [Define to 1 if you have the <libesmtp.h> header file.])
+ ], [with_libesmtp="no (libesmtp.h not found)"])
+fi
+if test "x$with_libesmtp" = "xyes"
+then
+ collect_libesmtp=1
+else
+ collect_libesmtp=0
+fi
+AC_DEFINE_UNQUOTED(COLLECT_LIBESMTP, [$collect_libesmtp],
+ [Wether or not to use the esmtp library])
+AM_CONDITIONAL(BUILD_WITH_LIBESMTP, test "x$with_libesmtp" = "xyes")
+
perl_interpreter="perl"
AC_ARG_WITH(libperl, [AS_HELP_STRING([--with-libperl@<:@=PREFIX@:>@], [Path to libperl.])],
[
- if test "x$withval" != "xno" && test "x$withval" != "xyes"
+ if test -x "$withval"
+ then
+ perl_interpreter="$withval"
+ with_libperl="yes"
+ else if test "x$withval" != "xno" && test "x$withval" != "xyes"
then
LDFLAGS="$LDFLAGS -L$withval/lib"
CPPFLAGS="$CPPFLAGS -I$withval/include"
with_libperl="yes"
else
with_libperl="$withval"
- fi
+ fi; fi
],
[
with_libperl="yes"
perl_interpreter=`which "$perl_interpreter" 2> /dev/null`
if test -x "$perl_interpreter"
then
- AC_MSG_RESULT([yes])
+ AC_MSG_RESULT([yes ($perl_interpreter)])
else
perl_interpreter=""
AC_MSG_RESULT([no])
AC_LINK_IFELSE(
AC_LANG_PROGRAM(
[[
+#define PERL_NO_GET_CONTEXT
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
]],
[[
- PerlInterpreter *perl = NULL;
- Perl_load_module (perl, PERL_LOADMOD_NOIMPORT,
+ dTHX;
+ load_module (PERL_LOADMOD_NOIMPORT,
newSVpv ("Collectd::Plugin::FooBar", 24),
Nullsv);
]]),
fi
AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
+PKG_CHECK_MODULES([LIBNOTIFY], [libnotify],
+ [with_libnotify="yes"],
+ [with_libnotify="no ($LIBNOTIFY_PKG_ERRORS)"])
+
with_libupsclient="no (pkg-config isn't available)"
with_libupsclient_cflags=""
with_libupsclient_libs=""
AC_SUBST(BUILD_WITH_OPENIPMI_LIBS)
fi
+dnl Check for libpq.
+with_pg_config="pg_config"
+with_libpq_includedir=""
+with_libpq_libdir=""
+with_libpq_cppflags=""
+with_libpq_ldflags=""
+AC_ARG_WITH(libpq, [AS_HELP_STRING([--with-libpq@<:@=PREFIX@:>@],
+ [Path to libpq.])],
+[
+ if test "x$withval" = "xno"
+ then
+ with_libpq="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_libpq="yes"
+ else
+ if test -f "$withval" && test -x "$withval";
+ then
+ with_pg_config="$withval"
+ else if test -x "$withval/bin/pg_config"
+ then
+ with_pg_config="$withval/bin/pg_config"
+ fi; fi
+ with_libpq="yes"
+ fi; fi
+],
+[
+ with_libpq="yes"
+])
+if test "x$with_libpq" = "xyes"
+then
+ with_libpq_includedir=`$with_pg_config --includedir 2> /dev/null`
+ pg_config_status=$?
+
+ if test $pg_config_status -eq 0
+ then
+ if test -n "$with_libpq_includedir"; then
+ for dir in $with_libpq_includedir; do
+ with_libpq_cppflags="$with_libpq_cppflags -I$dir"
+ done
+ fi
+ else
+ AC_MSG_WARN([$with_pg_config returned with status $pg_config_status])
+ fi
+
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libpq_cppflags"
+
+ AC_CHECK_HEADERS(libpq-fe.h, [],
+ [with_libpq="no (libpq-fe.h not found)"], [])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_libpq" = "xyes"
+then
+ with_libpq_libdir=`$with_pg_config --libdir 2> /dev/null`
+ pg_config_status=$?
+
+ if test $pg_config_status -eq 0
+ then
+ if test -n "$with_libpq_libdir"; then
+ for dir in $with_libpq_libdir; do
+ with_libpq_ldflags="$with_libpq_ldflags -L$dir"
+ done
+ fi
+ else
+ AC_MSG_WARN([$with_pg_config returned with status $pg_config_status])
+ fi
+
+ SAVE_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $with_libpq_ldflags"
+
+ AC_CHECK_LIB(pq, PQconnectdb,
+ [with_libpq="yes"],
+ [with_libpq="no (symbol 'PQconnectdb' not found)"])
+
+ LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_libpq" = "xyes"
+then
+ BUILD_WITH_LIBPQ_CPPFLAGS="$with_libpq_cppflags"
+ BUILD_WITH_LIBPQ_LDFLAGS="$with_libpq_ldflags"
+ AC_SUBST(BUILD_WITH_LIBPQ_CPPFLAGS)
+ AC_SUBST(BUILD_WITH_LIBPQ_LDFLAGS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBPQ, test "x$with_libpq" = "xyes")
+
dnl Check for libvirt and libxml2 libraries.
with_libxml2="no (pkg-config isn't available)"
with_libxml2_cflags=""
plugin_swap="no"
plugin_tape="no"
plugin_tcpconns="no"
+plugin_thermal="no"
plugin_users="no"
plugin_vmem="no"
plugin_vserver="no"
plugin_serial="yes"
plugin_swap="yes"
plugin_tcpconns="yes"
+ plugin_thermal="yes"
plugin_vmem="yes"
plugin_vserver="yes"
plugin_wireless="yes"
fi
fi
+if test "x$ac_system" = "xOpenBSD"
+then
+ plugin_tcpconns="yes"
+fi
+
# Mac OS X devices
if test "x$with_libiokit" = "xyes"
then
plugin_processes="yes"
fi
+if test "x$with_kvm_getprocs" = "xyes"
+then
+ plugin_processes="yes"
+fi
+
if test "x$with_kvm_getswapinfo" = "xyes"
then
plugin_swap="yes"
fi
+if test "x$with_kvm_openfiles$with_kvm_nlist" = "xyesyes"
+then
+ plugin_tcpconns="yes"
+fi
+
if test "x$have_getutent" = "xyes"
then
plugin_users="yes"
AC_PLUGIN([cpu], [$plugin_cpu], [CPU usage statistics])
AC_PLUGIN([cpufreq], [$plugin_cpufreq], [CPU frequency statistics])
AC_PLUGIN([csv], [yes], [CSV output plugin])
+AC_PLUGIN([notify_desktop], [$with_libnotify], [Desktop notifications])
AC_PLUGIN([df], [$plugin_df], [Filesystem usage statistics])
AC_PLUGIN([disk], [$plugin_disk], [Disk usage statistics])
AC_PLUGIN([dns], [$with_libpcap], [DNS traffic analysis])
AC_PLUGIN([email], [yes], [EMail statistics])
AC_PLUGIN([entropy], [$plugin_entropy], [Entropy statistics])
AC_PLUGIN([exec], [yes], [Execution of external programs])
+AC_PLUGIN([filecount], [yes], [Count files in directories])
AC_PLUGIN([hddtemp], [yes], [Query hddtempd])
AC_PLUGIN([interface], [$plugin_interface], [Interface traffic statistics])
AC_PLUGIN([iptables], [$with_libiptc], [IPTables rule counters])
AC_PLUGIN([network], [yes], [Network communication plugin])
AC_PLUGIN([nfs], [$plugin_nfs], [NFS statistics])
AC_PLUGIN([nginx], [$with_libcurl], [nginx statistics])
+AC_PLUGIN([notify_email], [$with_libesmtp], [Email notifier])
AC_PLUGIN([ntpd], [yes], [NTPd statistics])
AC_PLUGIN([nut], [$with_libupsclient], [Network UPS tools statistics])
+AC_PLUGIN([onewire], [$with_libowcapi], [OneWire sensor statistics])
AC_PLUGIN([perl], [$plugin_perl], [Embed a Perl interpreter])
AC_PLUGIN([ping], [$with_liboping], [Network latency statistics])
+AC_PLUGIN([postgresql], [$with_libpq], [PostgreSQL database statistics])
AC_PLUGIN([powerdns], [yes], [PowerDNS statistics])
AC_PLUGIN([processes], [$plugin_processes], [Process statistics])
AC_PLUGIN([rrdtool], [$with_rrdtool], [RRDTool output plugin])
AC_PLUGIN([tape], [$plugin_tape], [Tape drive statistics])
AC_PLUGIN([tcpconns], [$plugin_tcpconns], [TCP connection statistics])
AC_PLUGIN([teamspeak2], [yes], [TeamSpeak2 server statistics])
+AC_PLUGIN([thermal], [$plugin_thermal], [Linux ACPI thermal zone statistics])
AC_PLUGIN([unixsock], [yes], [Unixsock communication plugin])
AC_PLUGIN([users], [$plugin_users], [User statistics])
AC_PLUGIN([uuid], [yes], [UUID as hostname plugin])
Configuration:
Libraries:
- libcurl . . . . . . $with_libcurl
- libiokit . . . . . $with_libiokit
- libiptc . . . . . . $with_libiptc
- libkstat . . . . . $with_kstat
- libkvm . . . . . . $with_libkvm
- libmysql . . . . . $with_libmysql
- libnetlink . . . . $with_libnetlink
- libnetsnmp . . . . $with_libnetsnmp
- liboconfig . . . . $with_liboconfig
- libopenipmi . . . . $with_libopenipmipthread
- liboping . . . . . $with_liboping
- libpcap . . . . . . $with_libpcap
- libperl . . . . . . $with_libperl
- libpthread . . . . $with_libpthread
- librrd . . . . . . $with_rrdtool
- libsensors . . . . $with_lm_sensors
- libstatgrab . . . . $with_libstatgrab
- libupsclient . . . $with_libupsclient
- libvirt . . . . . . $with_libvirt
- libxml2 . . . . . . $with_libxml2
- libxmms . . . . . . $with_libxmms
+ libcurl . . . . . . . $with_libcurl
+ libesmtp . . . . . . $with_libesmtp
+ libiokit . . . . . . $with_libiokit
+ libiptc . . . . . . . $with_libiptc
+ libkstat . . . . . . $with_kstat
+ libkvm . . . . . . . $with_libkvm
+ libmysql . . . . . . $with_libmysql
+ libnetlink . . . . . $with_libnetlink
+ libnetsnmp . . . . . $with_libnetsnmp
+ libnotify . . . . . . $with_libnotify
+ liboconfig . . . . . $with_liboconfig
+ libopenipmi . . . . . $with_libopenipmipthread
+ liboping . . . . . . $with_liboping
+ libpcap . . . . . . . $with_libpcap
+ libperl . . . . . . . $with_libperl
+ libpthread . . . . . $with_libpthread
+ libpq . . . . . . . . $with_libpq
+ librrd . . . . . . . $with_rrdtool
+ libsensors . . . . . $with_lm_sensors
+ libstatgrab . . . . . $with_libstatgrab
+ libupsclient . . . . $with_libupsclient
+ libvirt . . . . . . . $with_libvirt
+ libxml2 . . . . . . . $with_libxml2
+ libxmms . . . . . . . $with_libxmms
Features:
- daemon mode . . . . $enable_daemon
- debug . . . . . . . $enable_debug
+ daemon mode . . . . . $enable_daemon
+ debug . . . . . . . . $enable_debug
Bindings:
- perl . . . . . . . $with_perl_bindings
+ perl . . . . . . . . $with_perl_bindings
Modules:
- apache . . . . . . $enable_apache
- apcups . . . . . . $enable_apcups
- apple_sensors . . . $enable_apple_sensors
- ascent . . . . . . $enable_ascent
- battery . . . . . . $enable_battery
- cpu . . . . . . . . $enable_cpu
- cpufreq . . . . . . $enable_cpufreq
- csv . . . . . . . . $enable_csv
- df . . . . . . . . $enable_df
- disk . . . . . . . $enable_disk
- dns . . . . . . . . $enable_dns
- email . . . . . . . $enable_email
- entropy . . . . . . $enable_entropy
- exec . . . . . . . $enable_exec
- hddtemp . . . . . . $enable_hddtemp
- interface . . . . . $enable_interface
- iptables . . . . . $enable_iptables
- ipmi . . . . . . . $enable_ipmi
- ipvs . . . . . . . $enable_ipvs
- irq . . . . . . . . $enable_irq
- libvirt . . . . . . $enable_libvirt
- load . . . . . . . $enable_load
- logfile . . . . . . $enable_logfile
- mbmon . . . . . . . $enable_mbmon
- memcached . . . . . $enable_memcached
- memory . . . . . . $enable_memory
- multimeter . . . . $enable_multimeter
- mysql . . . . . . . $enable_mysql
- netlink . . . . . . $enable_netlink
- network . . . . . . $enable_network
- nfs . . . . . . . . $enable_nfs
- nginx . . . . . . . $enable_nginx
- ntpd . . . . . . . $enable_ntpd
- nut . . . . . . . . $enable_nut
- perl . . . . . . . $enable_perl
- ping . . . . . . . $enable_ping
- powerdns . . . . . $enable_powerdns
- processes . . . . . $enable_processes
- rrdtool . . . . . . $enable_rrdtool
- sensors . . . . . . $enable_sensors
- serial . . . . . . $enable_serial
- snmp . . . . . . . $enable_snmp
- swap . . . . . . . $enable_swap
- syslog . . . . . . $enable_syslog
- tail . . . . . . . $enable_tail
- tape . . . . . . . $enable_tape
- tcpconns . . . . . $enable_tcpconns
- teamspeak2 . . . . $enable_teamspeak2
- unixsock . . . . . $enable_unixsock
- users . . . . . . . $enable_users
- uuid . . . . . . . $enable_uuid
- vmem . . . . . . . $enable_vmem
- vserver . . . . . . $enable_vserver
- wireless . . . . . $enable_wireless
- xmms . . . . . . . $enable_xmms
+ apache . . . . . . . $enable_apache
+ apcups . . . . . . . $enable_apcups
+ apple_sensors . . . . $enable_apple_sensors
+ ascent . . . . . . . $enable_ascent
+ battery . . . . . . . $enable_battery
+ cpu . . . . . . . . . $enable_cpu
+ cpufreq . . . . . . . $enable_cpufreq
+ csv . . . . . . . . . $enable_csv
+ df . . . . . . . . . $enable_df
+ disk . . . . . . . . $enable_disk
+ dns . . . . . . . . . $enable_dns
+ email . . . . . . . . $enable_email
+ entropy . . . . . . . $enable_entropy
+ exec . . . . . . . . $enable_exec
+ filecount . . . . . . $enable_filecount
+ hddtemp . . . . . . . $enable_hddtemp
+ interface . . . . . . $enable_interface
+ iptables . . . . . . $enable_iptables
+ ipmi . . . . . . . . $enable_ipmi
+ ipvs . . . . . . . . $enable_ipvs
+ irq . . . . . . . . . $enable_irq
+ libvirt . . . . . . . $enable_libvirt
+ load . . . . . . . . $enable_load
+ logfile . . . . . . . $enable_logfile
+ mbmon . . . . . . . . $enable_mbmon
+ memcached . . . . . . $enable_memcached
+ memory . . . . . . . $enable_memory
+ multimeter . . . . . $enable_multimeter
+ mysql . . . . . . . . $enable_mysql
+ netlink . . . . . . . $enable_netlink
+ network . . . . . . . $enable_network
+ nfs . . . . . . . . . $enable_nfs
+ nginx . . . . . . . . $enable_nginx
+ notify_desktop . . . $enable_notify_desktop
+ notify_email . . . . $enable_notify_email
+ ntpd . . . . . . . . $enable_ntpd
+ nut . . . . . . . . . $enable_nut
+ onewire . . . . . . . $enable_onewire
+ perl . . . . . . . . $enable_perl
+ ping . . . . . . . . $enable_ping
+ postgresql . . . . . $enable_postgresql
+ powerdns . . . . . . $enable_powerdns
+ processes . . . . . . $enable_processes
+ rrdtool . . . . . . . $enable_rrdtool
+ sensors . . . . . . . $enable_sensors
+ serial . . . . . . . $enable_serial
+ snmp . . . . . . . . $enable_snmp
+ swap . . . . . . . . $enable_swap
+ syslog . . . . . . . $enable_syslog
+ tail . . . . . . . . $enable_tail
+ tape . . . . . . . . $enable_tape
+ tcpconns . . . . . . $enable_tcpconns
+ teamspeak2 . . . . . $enable_teamspeak2
+ thermal . . . . . . . $enable_thermal
+ unixsock . . . . . . $enable_unixsock
+ users . . . . . . . . $enable_users
+ uuid . . . . . . . . $enable_uuid
+ vmem . . . . . . . . $enable_vmem
+ vserver . . . . . . . $enable_vserver
+ wireless . . . . . . $enable_wireless
+ xmms . . . . . . . . $enable_xmms
EOF
'GPRINT:ping_avg:AVERAGE:%4.1lf ms Avg,',
'GPRINT:ping_max:MAX:%4.1lf ms Max,',
'GPRINT:ping_avg:LAST:%4.1lf ms Last'],
+ pg_blks => ['DEF:pg_blks_avg={file}:value:AVERAGE',
+ 'DEF:pg_blks_min={file}:value:MIN',
+ 'DEF:pg_blks_max={file}:value:MAX',
+ "AREA:pg_blks_max#$HalfBlue",
+ "AREA:pg_blks_min#$Canvas",
+ "LINE1:pg_blks_avg#$FullBlue:Blocks",
+ 'GPRINT:pg_blks_min:MIN:%4.1lf%s Min,',
+ 'GPRINT:pg_blks_avg:AVERAGE:%4.1lf%s Avg,',
+ 'GPRINT:pg_blks_max:MAX:%4.1lf%s Max,',
+ 'GPRINT:pg_blks_avg:LAST:%4.1lf%s Last'],
+ pg_db_size => ['DEF:pg_db_size_avg={file}:value:AVERAGE',
+ 'DEF:pg_db_size_min={file}:value:MIN',
+ 'DEF:pg_db_size_max={file}:value:MAX',
+ "AREA:pg_db_size_max#$HalfBlue",
+ "AREA:pg_db_size_min#$Canvas",
+ "LINE1:pg_db_size_avg#$FullBlue:Bytes",
+ 'GPRINT:pg_db_size_min:MIN:%4.1lf%s Min,',
+ 'GPRINT:pg_db_size_avg:AVERAGE:%4.1lf%s Avg,',
+ 'GPRINT:pg_db_size_max:MAX:%4.1lf%s Max,',
+ 'GPRINT:pg_db_size_avg:LAST:%4.1lf%s Last'],
+ pg_n_tup_c => ['DEF:pg_n_tup_avg={file}:value:AVERAGE',
+ 'DEF:pg_n_tup_min={file}:value:MIN',
+ 'DEF:pg_n_tup_max={file}:value:MAX',
+ "AREA:pg_n_tup_max#$HalfBlue",
+ "AREA:pg_n_tup_min#$Canvas",
+ "LINE1:pg_n_tup_avg#$FullBlue:Tuples",
+ 'GPRINT:pg_n_tup_min:MIN:%4.1lf%s Min,',
+ 'GPRINT:pg_n_tup_avg:AVERAGE:%4.1lf%s Avg,',
+ 'GPRINT:pg_n_tup_max:MAX:%4.1lf%s Max,',
+ 'GPRINT:pg_n_tup_avg:LAST:%4.1lf%s Last'],
+ pg_n_tup_g => ['DEF:pg_n_tup_avg={file}:value:AVERAGE',
+ 'DEF:pg_n_tup_min={file}:value:MIN',
+ 'DEF:pg_n_tup_max={file}:value:MAX',
+ "AREA:pg_n_tup_max#$HalfBlue",
+ "AREA:pg_n_tup_min#$Canvas",
+ "LINE1:pg_n_tup_avg#$FullBlue:Tuples",
+ 'GPRINT:pg_n_tup_min:MIN:%4.1lf%s Min,',
+ 'GPRINT:pg_n_tup_avg:AVERAGE:%4.1lf%s Avg,',
+ 'GPRINT:pg_n_tup_max:MAX:%4.1lf%s Max,',
+ 'GPRINT:pg_n_tup_avg:LAST:%4.1lf%s Last'],
+ pg_numbackends => ['DEF:pg_numbackends_avg={file}:value:AVERAGE',
+ 'DEF:pg_numbackends_min={file}:value:MIN',
+ 'DEF:pg_numbackends_max={file}:value:MAX',
+ "AREA:pg_numbackends_max#$HalfBlue",
+ "AREA:pg_numbackends_min#$Canvas",
+ "LINE1:pg_numbackends_avg#$FullBlue:Backends",
+ 'GPRINT:pg_numbackends_min:MIN:%4.1lf%s Min,',
+ 'GPRINT:pg_numbackends_avg:AVERAGE:%4.1lf%s Avg,',
+ 'GPRINT:pg_numbackends_max:MAX:%4.1lf%s Max,',
+ 'GPRINT:pg_numbackends_avg:LAST:%4.1lf%s Last'],
+ pg_scan => ['DEF:pg_scan_avg={file}:value:AVERAGE',
+ 'DEF:pg_scan_min={file}:value:MIN',
+ 'DEF:pg_scan_max={file}:value:MAX',
+ "AREA:pg_scan_max#$HalfBlue",
+ "AREA:pg_scan_min#$Canvas",
+ "LINE1:pg_scan_avg#$FullBlue:Scans",
+ 'GPRINT:pg_scan_min:MIN:%4.1lf%s Min,',
+ 'GPRINT:pg_scan_avg:AVERAGE:%4.1lf%s Avg,',
+ 'GPRINT:pg_scan_max:MAX:%4.1lf%s Max,',
+ 'GPRINT:pg_scan_avg:LAST:%4.1lf%s Last'],
+ pg_xact => ['DEF:pg_xact_avg={file}:value:AVERAGE',
+ 'DEF:pg_xact_min={file}:value:MIN',
+ 'DEF:pg_xact_max={file}:value:MAX',
+ "AREA:pg_xact_max#$HalfBlue",
+ "AREA:pg_xact_min#$Canvas",
+ "LINE1:pg_xact_avg#$FullBlue:Transactions",
+ 'GPRINT:pg_xact_min:MIN:%4.1lf%s Min,',
+ 'GPRINT:pg_xact_avg:AVERAGE:%4.1lf%s Avg,',
+ 'GPRINT:pg_xact_max:MAX:%4.1lf%s Max,',
+ 'GPRINT:pg_xact_avg:LAST:%4.1lf%s Last'],
power => ['-v', 'Watt',
'DEF:avg={file}:value:AVERAGE',
'DEF:min={file}:value:MIN',
elsif ($option eq "timeout") {
$args{"timeout"} = $value;
}
+ elsif ($option eq "identifier") {
+ my $id = getid (\$value);
+ if (!$id)
+ {
+ print STDERR "Not a valid identifier: \"$value\"\n";
+ next;
+ }
+ push @{$args{"identifier"}}, $id;
+ }
else {
print STDERR "Invalid option \"$option\".\n";
return;
vl.values = values;
vl.values_len = 1;
vl.time = time (NULL);
- strcpy (vl.host, hostname_g);
- strcpy (vl.plugin, "myplugin");
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "myplugin", sizeof (vl.plugin));
/* optionally set vl.plugin_instance and vl.type_instance to reasonable
* values (default: "") */
AM_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
endif
AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
+AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
sbin_PROGRAMS = collectd collectdmon
bin_PROGRAMS = collectd-nagios
plugin.c plugin.h \
utils_avltree.c utils_avltree.h \
utils_cache.c utils_cache.h \
+ utils_complain.c utils_complain.h \
utils_ignorelist.c utils_ignorelist.h \
utils_llist.c utils_llist.h \
utils_tail_match.c utils_tail_match.h \
types_list.c types_list.h
collectd_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
-collectd_CFLAGS =
+collectd_CFLAGS = $(AM_CFLAGS)
collectd_LDFLAGS = -export-dynamic
collectd_LDADD =
collectd_DEPENDENCIES =
pkglib_LTLIBRARIES += apache.la
apache_la_SOURCES = apache.c
apache_la_LDFLAGS = -module -avoid-version
-apache_la_CFLAGS =
+apache_la_CFLAGS = $(AM_CFLAGS)
apache_la_LIBADD =
collectd_LDADD += "-dlopen" apache.la
if BUILD_WITH_LIBCURL
pkglib_LTLIBRARIES += ascent.la
ascent_la_SOURCES = ascent.c
ascent_la_LDFLAGS = -module -avoid-version
-ascent_la_CFLAGS = $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+ascent_la_CFLAGS = $(AM_CFLAGS) \
+ $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
ascent_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
collectd_LDADD += "-dlopen" ascent.la
collectd_DEPENDENCIES += ascent.la
if BUILD_PLUGIN_CPU
pkglib_LTLIBRARIES += cpu.la
cpu_la_SOURCES = cpu.c
-cpu_la_CFLAGS =
+cpu_la_CFLAGS = $(AM_CFLAGS)
cpu_la_LDFLAGS = -module -avoid-version
cpu_la_LIBADD =
if BUILD_WITH_LIBKSTAT
if BUILD_PLUGIN_DISK
pkglib_LTLIBRARIES += disk.la
disk_la_SOURCES = disk.c
-disk_la_CFLAGS =
+disk_la_CFLAGS = $(AM_CFLAGS)
disk_la_LDFLAGS = -module -avoid-version
disk_la_LIBADD =
if BUILD_WITH_LIBKSTAT
if BUILD_PLUGIN_EXEC
pkglib_LTLIBRARIES += exec.la
exec_la_SOURCES = exec.c \
+ utils_parse_option.h utils_parse_option.c \
utils_cmd_putnotif.c utils_cmd_putnotif.h \
utils_cmd_putval.c utils_cmd_putval.h
exec_la_LDFLAGS = -module -avoid-version
collectd_DEPENDENCIES += exec.la
endif
+if BUILD_PLUGIN_FILECOUNT
+pkglib_LTLIBRARIES += filecount.la
+filecount_la_SOURCES = filecount.c
+filecount_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" filecount.la
+collectd_DEPENDENCIES += filecount.la
+endif
+
if BUILD_PLUGIN_HDDTEMP
pkglib_LTLIBRARIES += hddtemp.la
hddtemp_la_SOURCES = hddtemp.c
if BUILD_PLUGIN_INTERFACE
pkglib_LTLIBRARIES += interface.la
interface_la_SOURCES = interface.c
-interface_la_CFLAGS =
+interface_la_CFLAGS = $(AM_CFLAGS)
interface_la_LDFLAGS = -module -avoid-version
interface_la_LIBADD =
collectd_LDADD += "-dlopen" interface.la
if BUILD_PLUGIN_IPMI
pkglib_LTLIBRARIES += ipmi.la
ipmi_la_SOURCES = ipmi.c
-ipmi_la_CFLAGS = $(BUILD_WITH_OPENIPMI_CFLAGS)
+ipmi_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_OPENIPMI_CFLAGS)
ipmi_la_LDFLAGS = -module -avoid-version
ipmi_la_LIBADD = $(BUILD_WITH_OPENIPMI_LIBS)
collectd_LDADD += "-dlopen" ipmi.la
if BUILD_PLUGIN_IPVS
pkglib_LTLIBRARIES += ipvs.la
ipvs_la_SOURCES = ipvs.c
-ipvs_la_CFLAGS = $(KERNEL_CFLAGS)
+ipvs_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS)
ipvs_la_LDFLAGS = -module -avoid-version
collectd_LDADD += "-dlopen" ipvs.la
collectd_DEPENDENCIES += ipvs.la
if BUILD_PLUGIN_LIBVIRT
pkglib_LTLIBRARIES += libvirt.la
libvirt_la_SOURCES = libvirt.c
-libvirt_la_CFLAGS = $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+libvirt_la_CFLAGS = $(AM_CFLAGS) \
+ $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
libvirt_la_LIBADD = $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
libvirt_la_LDFLAGS = -module -avoid-version
collectd_LDADD += "-dlopen" libvirt.la
if BUILD_PLUGIN_LOAD
pkglib_LTLIBRARIES += load.la
load_la_SOURCES = load.c
-load_la_CFLAGS =
+load_la_CFLAGS = $(AM_CFLAGS)
load_la_LDFLAGS = -module -avoid-version
load_la_LIBADD =
collectd_LDADD += "-dlopen" load.la
pkglib_LTLIBRARIES += memcached.la
memcached_la_SOURCES = memcached.c
memcached_la_LDFLAGS = -module -avoid-version
-memcached_la_CFLAGS =
memcached_la_LIBADD =
if BUILD_WITH_LIBSOCKET
memcached_la_LDFLAGS += -lsocket
if BUILD_PLUGIN_MEMORY
pkglib_LTLIBRARIES += memory.la
memory_la_SOURCES = memory.c
-memory_la_CFLAGS =
+memory_la_CFLAGS = $(AM_CFLAGS)
memory_la_LDFLAGS = -module -avoid-version
memory_la_LIBADD =
collectd_LDADD += "-dlopen" memory.la
pkglib_LTLIBRARIES += mysql.la
mysql_la_SOURCES = mysql.c
mysql_la_LDFLAGS = -module -avoid-version
-mysql_la_CFLAGS =
+mysql_la_CFLAGS = $(AM_CFLAGS)
mysql_la_LIBADD =
collectd_LDADD += "-dlopen" mysql.la
if BUILD_WITH_LIBMYSQL
pkglib_LTLIBRARIES += netlink.la
netlink_la_SOURCES = netlink.c
netlink_la_LDFLAGS = -module -avoid-version
-netlink_la_CFLAGS = $(BUILD_WITH_LIBNETLINK_CFLAGS)
+netlink_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBNETLINK_CFLAGS)
netlink_la_LIBADD = $(BUILD_WITH_LIBNETLINK_LIBS)
collectd_LDADD += "-dlopen" netlink.la
collectd_DEPENDENCIES += netlink.la
collectd_DEPENDENCIES += nginx.la
endif
+if BUILD_PLUGIN_NOTIFY_DESKTOP
+pkglib_LTLIBRARIES += notify_desktop.la
+notify_desktop_la_SOURCES = notify_desktop.c
+notify_desktop_la_CFLAGS = $(AM_CFLAGS) $(LIBNOTIFY_CFLAGS)
+notify_desktop_la_LDFLAGS = -module -avoid-version $(LIBNOTIFY_LIBS)
+collectd_LDADD += "-dlopen" notify_desktop.la
+collectd_DEPENDENCIES += notify_desktop.la
+endif
+
+if BUILD_PLUGIN_NOTIFY_EMAIL
+pkglib_LTLIBRARIES += notify_email.la
+notify_email_la_SOURCES = notify_email.c
+notify_email_la_LDFLAGS = -L/usr/local/lib -lesmtp -lssl -lcrypto -pthread -module -avoid-version
+collectd_LDADD += "-dlopen" notify_email.la
+collectd_DEPENDENCIES += notify_email.la
+endif
+
if BUILD_PLUGIN_NTPD
pkglib_LTLIBRARIES += ntpd.la
ntpd_la_SOURCES = ntpd.c
collectd_DEPENDENCIES += nut.la
endif
+if BUILD_PLUGIN_ONEWIRE
+pkglib_LTLIBRARIES += onewire.la
+onewire_la_SOURCES = onewire.c
+onewire_la_CFLAGS = $(AM_CFLAGS)
+onewire_la_CPPFLAGS = $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
+onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS)
+onewire_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" onewire.la
+collectd_DEPENDENCIES += onewire.la
+endif
+
if BUILD_PLUGIN_PERL
pkglib_LTLIBRARIES += perl.la
perl_la_SOURCES = perl.c
+# Despite C99 providing the "bool" type thru stdbool.h, Perl defines its own
+# version of that type if HAS_BOOL is not defined... *sigh*
+perl_la_CPPFLAGS = $(AM_CPPFLAGS) -DHAS_BOOL=1
perl_la_CFLAGS = $(AM_CFLAGS) \
- $(PERL_CFLAGS) \
- -DXS_VERSION=\"$(VERSION)\" -DVERSION=\"$(VERSION)\"
+ $(PERL_CFLAGS) \
+ -DXS_VERSION=\"$(VERSION)\" -DVERSION=\"$(VERSION)\"
perl_la_LDFLAGS = -module -avoid-version \
- $(PERL_LDFLAGS)
+ $(PERL_LDFLAGS)
collectd_LDADD += "-dlopen" perl.la
collectd_DEPENDENCIES += perl.la
endif
collectd_DEPENDENCIES += ping.la
endif
+if BUILD_PLUGIN_POSTGRESQL
+pkglib_LTLIBRARIES += postgresql.la
+postgresql_la_SOURCES = postgresql.c
+postgresql_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPQ_CPPFLAGS)
+postgresql_la_LDFLAGS = -module -avoid-version \
+ $(BUILD_WITH_LIBPQ_LDFLAGS) -lpq
+collectd_LDADD += "-dlopen" postgresql.la
+collectd_DEPENDENCIES += postgresql.la
+endif
+
if BUILD_PLUGIN_POWERDNS
pkglib_LTLIBRARIES += powerdns.la
powerdns_la_SOURCES = powerdns.c
pkglib_LTLIBRARIES += processes.la
processes_la_SOURCES = processes.c
processes_la_LDFLAGS = -module -avoid-version
+processes_la_LIBADD =
collectd_LDADD += "-dlopen" processes.la
collectd_DEPENDENCIES += processes.la
+if BUILD_WITH_LIBKVM_GETPROCS
+processes_la_LIBADD += -lkvm
+endif
endif
if BUILD_PLUGIN_RRDTOOL
pkglib_LTLIBRARIES += rrdtool.la
rrdtool_la_SOURCES = rrdtool.c
rrdtool_la_LDFLAGS = -module -avoid-version
-rrdtool_la_CFLAGS = $(BUILD_WITH_LIBRRD_CFLAGS)
+rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LDFLAGS)
collectd_LDADD += "-dlopen" rrdtool.la
collectd_DEPENDENCIES += rrdtool.la
if BUILD_PLUGIN_SENSORS
pkglib_LTLIBRARIES += sensors.la
sensors_la_SOURCES = sensors.c
-sensors_la_CFLAGS = $(BUILD_WITH_LIBSENSORS_CFLAGS)
+sensors_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBSENSORS_CFLAGS)
sensors_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBSENSORS_LDFLAGS)
sensors_la_LIBADD = -lsensors
collectd_LDADD += "-dlopen" sensors.la
pkglib_LTLIBRARIES += snmp.la
snmp_la_SOURCES = snmp.c
snmp_la_LDFLAGS = -module -avoid-version
-snmp_la_CFLAGS =
+snmp_la_CFLAGS = $(AM_CFLAGS)
snmp_la_LIBADD =
if BUILD_WITH_LIBNETSNMP
snmp_la_CFLAGS += $(BUILD_WITH_LIBSNMP_CFLAGS)
if BUILD_PLUGIN_SWAP
pkglib_LTLIBRARIES += swap.la
swap_la_SOURCES = swap.c
-swap_la_CFLAGS =
+swap_la_CFLAGS = $(AM_CFLAGS)
swap_la_LDFLAGS = -module -avoid-version
swap_la_LIBADD =
collectd_LDADD += "-dlopen" swap.la
pkglib_LTLIBRARIES += tcpconns.la
tcpconns_la_SOURCES = tcpconns.c
tcpconns_la_LDFLAGS = -module -avoid-version
+tcpconns_la_LIBADD =
collectd_LDADD += "-dlopen" tcpconns.la
collectd_DEPENDENCIES += tcpconns.la
+if BUILD_WITH_LIBKVM_NLIST
+tcpconns_la_LIBADD += -lkvm
+endif
endif
if BUILD_PLUGIN_TEAMSPEAK2
collectd_DEPENDENCIES += teamspeak2.la
endif
+if BUILD_PLUGIN_THERMAL
+pkglib_LTLIBRARIES += thermal.la
+thermal_la_SOURCES = thermal.c
+thermal_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" thermal.la
+collectd_DEPENDENCIES += thermal.la
+endif
+
if BUILD_PLUGIN_UNIXSOCK
pkglib_LTLIBRARIES += unixsock.la
unixsock_la_SOURCES = unixsock.c \
+ utils_parse_option.h utils_parse_option.c \
utils_cmd_flush.h utils_cmd_flush.c \
utils_cmd_getval.h utils_cmd_getval.c \
utils_cmd_listval.h utils_cmd_listval.c \
if BUILD_PLUGIN_USERS
pkglib_LTLIBRARIES += users.la
users_la_SOURCES = users.c
-users_la_CFLAGS =
+users_la_CFLAGS = $(AM_CFLAGS)
users_la_LDFLAGS = -module -avoid-version
users_la_LIBADD =
if BUILD_WITH_LIBSTATGRAB
if BUILD_PLUGIN_UUID
pkglib_LTLIBRARIES += uuid.la
uuid_la_SOURCES = uuid.c
-uuid_la_CFLAGS = $(BUILD_WITH_LIBHAL_CFLAGS)
+uuid_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBHAL_CFLAGS)
uuid_la_LIBADD = $(BUILD_WITH_LIBHAL_LIBS)
uuid_la_LDFLAGS = -module -avoid-version
collectd_LDADD += "-dlopen" uuid.la
EXTRA_DIST += collectd-email.pod collectd-exec.pod collectd-nagios.pod \
collectd-perl.pod collectd-snmp.pod collectd-unixsock.pod \
- collectd.conf.pod collectd.pod collectdmon.pod types.db.pod
+ collectd.conf.pod collectd.pod collectdmon.pod types.db.pod \
+ postgresql_default.conf
.pod.1:
- pod2man --release=$(VERSION) --center=$(PACKAGE) $< >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+ pod2man --release=$(VERSION) --center=$(PACKAGE) $< \
+ >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+ @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+ then \
+ echo "$@ has some POD errors!"; false; \
+ fi
.pod.5:
- pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+ pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< \
+ >.pod2man.tmp 2>/dev/null && mv -f .pod2man.tmp $@ || true
+ @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+ then \
+ echo "$@ has some POD errors!"; false; \
+ fi
install-exec-hook:
$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
$(INSTALL) -m 0640 collectd.conf $(DESTDIR)$(sysconfdir)/collectd.conf; \
fi; \
cp -f $(srcdir)/types.db $(DESTDIR)$(pkglibdir)/;
+ $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+ $(INSTALL) -m 0644 $(srcdir)/postgresql_default.conf \
+ $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
{
int status;
- status = snprintf (credentials, sizeof (credentials), "%s:%s",
+ status = ssnprintf (credentials, sizeof (credentials), "%s:%s",
user, (pass == NULL) ? "" : pass);
if (status >= sizeof (credentials))
{
"truncated.");
return (-1);
}
- credentials[sizeof (credentials) - 1] = '\0';
curl_easy_setopt (curl, CURLOPT_USERPWD, credentials);
}
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "apache", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
- {
- strncpy (vl.type_instance, type_instance,
+ sstrncpy (vl.type_instance, type_instance,
sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void submit_counter */
static void submit_gauge (const char *type, const char *type_instance,
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "apache", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
- {
- strncpy (vl.type_instance, type_instance,
+ sstrncpy (vl.type_instance, type_instance,
sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void submit_counter */
static void submit_scoreboard (char *buf)
assert ((port > 0x00000000) && (port <= 0x0000FFFF));
/* Convert the port to a string */
- snprintf (port_str, 8, "%i", port);
- port_str[7] = '\0';
+ ssnprintf (port_str, sizeof (port_str), "%i", port);
/* Resolve name */
memset ((void *) &ai_hints, '\0', sizeof (ai_hints));
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "apcups", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
}
static void apc_submit (struct apc_detail_s *apcups_detail)
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "apple_sensors", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_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);
}
static int as_read (void)
if (CFGetTypeID (property) != CFStringGetTypeID ())
continue;
if (!CFStringGetCString (property,
- type, 128,
+ type, sizeof (type),
kCFStringEncodingASCII))
continue;
- type[127] = '\0';
+ type[sizeof (type) - 1] = '\0';
/* Copy the sensor location. This will be used as `instance'. */
property = NULL;
if (CFGetTypeID (property) != CFStringGetTypeID ())
continue;
if (!CFStringGetCString (property,
- inst, 128,
+ inst, sizeof (inst),
kCFStringEncodingASCII))
continue;
- inst[127] = '\0';
+ inst[sizeof (inst) - 1] = '\0';
for (i = 0; i < 128; i++)
{
if (inst[i] == '\0')
typedef struct player_info_s player_info_t;
#define PLAYER_INFO_STATIC_INIT { -1, -1, -1, -1, -1 }
-static char *url = NULL;
-static char *user = NULL;
-static char *pass = NULL;
-static char *cacert = NULL;
+static char *url = NULL;
+static char *user = NULL;
+static char *pass = NULL;
+static char *verify_peer = NULL;
+static char *verify_host = NULL;
+static char *cacert = NULL;
static CURL *curl = NULL;
"URL",
"User",
"Password",
+ "VerifyPeer",
+ "VerifyHost",
"CACert"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
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 (type, &vl);
+ plugin_dispatch_values (&vl);
return (0);
} /* }}} int ascent_submit_gauge */
return (config_set (&user, value));
else if (strcasecmp (key, "Password") == 0)
return (config_set (&pass, value));
+ else if (strcasecmp (key, "VerifyPeer") == 0)
+ return (config_set (&verify_peer, value));
+ else if (strcasecmp (key, "VerifyHost") == 0)
+ return (config_set (&verify_host, value));
else if (strcasecmp (key, "CACert") == 0)
return (config_set (&cacert, value));
else
{
int status;
- status = snprintf (credentials, sizeof (credentials), "%s:%s",
+ status = ssnprintf (credentials, sizeof (credentials), "%s:%s",
user, (pass == NULL) ? "" : pass);
if (status >= sizeof (credentials))
{
"credentials have been truncated.");
return (-1);
}
- credentials[sizeof (credentials) - 1] = '\0';
curl_easy_setopt (curl, CURLOPT_USERPWD, credentials);
}
curl_easy_setopt (curl, CURLOPT_URL, url);
+ if ((verify_peer == NULL) || (strcmp (verify_peer, "true") == 0))
+ curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 1);
+ else
+ curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0);
+
+ if ((verify_host == NULL) || (strcmp (verify_host, "true") == 0))
+ curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 2);
+ else
+ curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0);
+
if (cacert != NULL)
curl_easy_setopt (curl, CURLOPT_CAINFO, cacert);
#elif KERNEL_LINUX
static int battery_pmu_num = 0;
static char *battery_pmu_file = "/proc/pmu/battery_%i";
+static const char *battery_acpi_dir = "/proc/acpi/battery";
#endif /* KERNEL_LINUX */
static int battery_init (void)
for (battery_pmu_num = 0; ; battery_pmu_num++)
{
- len = snprintf (filename, sizeof (filename), battery_pmu_file, battery_pmu_num);
+ len = ssnprintf (filename, sizeof (filename), battery_pmu_file, battery_pmu_num);
if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
break;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "battery", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void battery_submit */
#if HAVE_IOKIT_PS_IOPOWERSOURCES_H || HAVE_IOKIT_IOKITLIB_H
}
#endif /* HAVE_IOKIT_IOKITLIB_H */
+#if KERNEL_LINUX
+static int battery_read_acpi (const char *dir, const char *name,
+ void *user_data)
+{
+ double current = INVALID_VALUE;
+ double voltage = INVALID_VALUE;
+ double charge = INVALID_VALUE;
+ double *valptr = NULL;
+ int charging = 0;
+
+ char filename[256];
+ FILE *fh;
+
+ char buffer[1024];
+ char *fields[8];
+ int numfields;
+ char *endptr;
+ int len;
+
+ len = ssnprintf (filename, sizeof (filename), "%s/%s/state", battery_acpi_dir, name);
+
+ if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+ return -1;
+
+ if ((fh = fopen (filename, "r")) == NULL) {
+ char errbuf[1024];
+ ERROR ("Cannot open `%s': %s", filename,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return -1;
+ }
+
+ /*
+ * [11:00] <@tokkee> $ cat /proc/acpi/battery/BAT1/state
+ * [11:00] <@tokkee> present: yes
+ * [11:00] <@tokkee> capacity state: ok
+ * [11:00] <@tokkee> charging state: charging
+ * [11:00] <@tokkee> present rate: 1724 mA
+ * [11:00] <@tokkee> remaining capacity: 4136 mAh
+ * [11:00] <@tokkee> present voltage: 12428 mV
+ */
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
+ {
+ numfields = strsplit (buffer, fields, 8);
+
+ if (numfields < 3)
+ continue;
+
+ if ((strcmp (fields[0], "charging") == 0)
+ && (strcmp (fields[1], "state:") == 0))
+ {
+ if (strcmp (fields[2], "charging") == 0)
+ charging = 1;
+ else
+ charging = 0;
+ continue;
+ }
+
+ if ((strcmp (fields[0], "present") == 0)
+ && (strcmp (fields[1], "rate:") == 0))
+ valptr = ¤t;
+ else if ((strcmp (fields[0], "remaining") == 0)
+ && (strcmp (fields[1], "capacity:") == 0))
+ valptr = &charge;
+ else if ((strcmp (fields[0], "present") == 0)
+ && (strcmp (fields[1], "voltage:") == 0))
+ valptr = &voltage;
+ else
+ continue;
+
+ endptr = NULL;
+ errno = 0;
+ *valptr = strtod (fields[2], &endptr) / 1000.0;
+
+ if ((fields[2] == endptr) || (errno != 0))
+ *valptr = INVALID_VALUE;
+ } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
+
+ fclose (fh);
+
+ if ((current != INVALID_VALUE) && (charging == 0))
+ current *= -1;
+
+ if (charge != INVALID_VALUE)
+ battery_submit ("0", "charge", charge);
+ if (current != INVALID_VALUE)
+ battery_submit ("0", "current", current);
+ if (voltage != INVALID_VALUE)
+ battery_submit ("0", "voltage", voltage);
+
+ return 0;
+}
+#endif /* KERNEL_LINUX */
+
+
static int battery_read (void)
{
#if HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H
double charge = INVALID_VALUE;
double *valptr = NULL;
- len = snprintf (filename, sizeof (filename), battery_pmu_file, i);
+ len = ssnprintf (filename, sizeof (filename), battery_pmu_file, i);
if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
continue;
- len = snprintf (batnum_str, sizeof (batnum_str), "%i", i);
+ len = ssnprintf (batnum_str, sizeof (batnum_str), "%i", i);
if ((len < 0) || ((unsigned int)len >= sizeof (batnum_str)))
continue;
battery_submit ("0", "voltage", voltage);
}
- if (access ("/proc/acpi/battery", R_OK | X_OK) == 0)
- {
- double current = INVALID_VALUE;
- double voltage = INVALID_VALUE;
- double charge = INVALID_VALUE;
- double *valptr = NULL;
- int charging = 0;
-
- struct dirent *ent;
- DIR *dh;
+ walk_directory (battery_acpi_dir, battery_read_acpi,
+ /* user_data = */ NULL);
- if ((dh = opendir ("/proc/acpi/battery")) == NULL)
- {
- char errbuf[1024];
- ERROR ("Cannot open `/proc/acpi/battery': %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- return (-1);
- }
-
- while ((ent = readdir (dh)) != NULL)
- {
- if (ent->d_name[0] == '.')
- continue;
-
- len = snprintf (filename, sizeof (filename),
- "/proc/acpi/battery/%s/state",
- ent->d_name);
- if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
- continue;
-
- if ((fh = fopen (filename, "r")) == NULL)
- {
- char errbuf[1024];
- ERROR ("Cannot open `%s': %s", filename,
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- continue;
- }
-
- /*
- * [11:00] <@tokkee> $ cat /proc/acpi/battery/BAT1/state
- * [11:00] <@tokkee> present: yes
- * [11:00] <@tokkee> capacity state: ok
- * [11:00] <@tokkee> charging state: charging
- * [11:00] <@tokkee> present rate: 1724 mA
- * [11:00] <@tokkee> remaining capacity: 4136 mAh
- * [11:00] <@tokkee> present voltage: 12428 mV
- */
- while (fgets (buffer, sizeof (buffer), fh) != NULL)
- {
- numfields = strsplit (buffer, fields, 8);
-
- if (numfields < 3)
- continue;
-
- if ((strcmp (fields[0], "present") == 0)
- && (strcmp (fields[1], "rate:") == 0))
- valptr = ¤t;
- else if ((strcmp (fields[0], "remaining") == 0)
- && (strcmp (fields[1], "capacity:") == 0))
- valptr = &charge;
- else if ((strcmp (fields[0], "present") == 0)
- && (strcmp (fields[1], "voltage:") == 0))
- valptr = &voltage;
- else
- valptr = NULL;
-
- if ((strcmp (fields[0], "charging") == 0)
- && (strcmp (fields[1], "state:") == 0))
- {
- if (strcmp (fields[2], "charging") == 0)
- charging = 1;
- else
- charging = 0;
- }
-
- if (valptr != NULL)
- {
- char *endptr;
-
- endptr = NULL;
- errno = 0;
-
- *valptr = strtod (fields[2], &endptr) / 1000.0;
-
- if ((fields[2] == endptr) || (errno != 0))
- *valptr = INVALID_VALUE;
- }
- } /* while (fgets (buffer, sizeof (buffer), fh) != NULL) */
-
- fclose (fh);
-
- if ((current != INVALID_VALUE) && (charging == 0))
- current *= -1;
-
- if (charge != INVALID_VALUE)
- battery_submit ("0", "charge", charge);
- if (current != INVALID_VALUE)
- battery_submit ("0", "current", current);
- if (voltage != INVALID_VALUE)
- battery_submit ("0", "voltage", voltage);
- }
-
- closedir (dh);
- }
#endif /* KERNEL_LINUX */
return (0);
The I<OptionList> is an optional list of I<Options>, where each option if a
key-value-pair. A list of currently understood options can be found below, all
-other options will be ignored.
+other options will be ignored. Values that contain spaces must be quoted with
+double quotes.
I<Valuelist> is a colon-separated list of the time and the values, each either
an integer if the data-source is a counter, or a double if the data-source is
=item B<message=>I<Message> (B<REQUIRED>)
Sets the message of the notification. This is the message that will be made
-accessible to the user, so it should contain some useful information. This
-option must be the last option because the rest of the line will be its value,
-even if there are spaces and equal-signs following it! This option is
-mandatory.
+accessible to the user, so it should contain some useful information. As with
+all options: If the message includes spaces, it must be quoted with double
+quotes. This option is mandatory.
=item B<severity=failure>|B<warning>|B<okay> (B<REQUIRED>)
BaseName "Collectd::Plugin"
EnableDebugger ""
LoadPlugin "FooBar"
+
+ <Plugin FooBar>
+ Foo "Bar"
+ </Plugin>
</Plugin>
=head1 DESCRIPTION
Prepends I<Name>B<::> to all plugin names loaded after this option. This is
provided for convenience to keep plugin names short.
+=item E<lt>B<Plugin> I<Name>E<gt> block
+
+This block may be used to pass on configuration settings to a Perl plugin. The
+configuration is converted into a config-item data type which is passed to the
+registered configuration callback. See below for details about the config-item
+data type and how to register callbacks.
+
+The I<name> identifies the callback. It is used literally and independent of
+the B<BaseName> setting.
+
=item B<EnableDebugger> I<Package>[=I<option>,...]
Run collectd under the control of the Perl source debugger. If I<Package> is
=over 4
+=item configuration functions
+
+This type of functions is called during configuration if an appropriate
+B<Plugin> block has been encountered. It is called once for each B<Plugin>
+block which matches the name of the callback as provided with the
+B<plugin_register> method - see below.
+
=item init functions
This type of functions is called once after loading the module and before any
=over 4
+=item Config-Item
+
+A config-item is one structure which keeps the informations provided in the
+configuration file. The array of children keeps one entry for each
+configuration option. Each such entry is another config-item structure, which
+may nest further if nested blocks are used.
+
+ {
+ key => key,
+ values => [ val1, val2, ... ],
+ children => [ { ... }, { ... }, ... ]
+ }
+
=item Data-Set
A data-set is a list of one or more data-sources. Each data-source defines a
time => time (),
host => $hostname_g,
plugin => 'myplugin',
+ type => 'myplugin',
plugin_instance => '',
type_instance => ''
}
=over 4
+=item TYPE_CONFIG
+
=item TYPE_INIT
=item TYPE_READ
=over 4
+=item TYPE_CONFIG
+
+The only argument passed is I<config-item>. See above for the layout of this
+data type.
+
=item TYPE_INIT
=item TYPE_READ
=item TYPE_FLUSH
-The only argument passed is I<timeout> which indicates that only data older
-than I<timeout> seconds is to be flushed.
+The arguments passed are I<timeout> and I<identifier>. I<timeout> indicates
+that only data older than I<timeout> seconds is to be flushed. I<identifier>
+specifies which values are to be flushed.
=item TYPE_LOG
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.
-=item B<plugin_flush> ([B<timeout> => I<timeout>,] [B<plugins> => I<...>])
+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.
-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> ([B<timeout> => I<timeout>][, B<plugins> => I<...>][,
+B<identifiers> => I<...>])
+
+Flush one or more plugins. I<timeout> and the specified I<identifiers> are
+passed on to the registered flush-callbacks. If omitted, the timeout defaults
+to C<-1>. The identifier defaults to the undefined value. If the I<plugins>
+argument has been specified, only named plugins will be flushed. The value of
+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
=over 4
+=item B<TYPE_CONFIG>
+
=item B<TYPE_INIT>
=item B<TYPE_READ>
=item B<TYPE_LOG>
+=item B<TYPE_DATASET>
+
=back
=item B<:ds_types>
down. You should not rely on END blocks anyway - use B<shutdown functions>
instead.
+=item
+
+The perl plugin exports the internal API of collectd which is considered
+unstable and subject to change at any time. We try hard to not break backwards
+compatibility in the Perl API during the life cycle of one major release.
+However, this cannot be guaranteed at all times. Watch out for warnings
+dispatched by the perl plugin after upgrades.
+
=back
=head1 KNOWN BUGS
The I<OptionList> is an optional list of I<Options>, where each option is a
key-value-pair. A list of currently understood options can be found below, all
-other options will be ignored.
+other options will be ignored. Values that contain spaces must be quoted with
+double quotes.
I<Valuelist> is a colon-separated list of the time and the values, each either
an integer if the data-source is a counter, or a double if the data-source is
=item B<message=>I<Message> (B<REQUIRED>)
Sets the message of the notification. This is the message that will be made
-accessible to the user, so it should contain some useful information. This
-option must be the last option because the rest of the line will be its value,
-even if there are spaces and equal-signs following it! This option is
-mandatory.
+accessible to the user, so it should contain some useful information. As with
+all options: If the message includes spaces, it must be quoted with double
+quotes. This option is mandatory.
=item B<severity=failure>|B<warning>|B<okay> (B<REQUIRED>)
-> | PUTNOTIF type=temperature severity=warning time=1201094702 message=The roof is on fire!
<- | 0 Success
-=item B<FLUSH> [B<timeout=>I<Timeout>] [B<plugin=>I<Plugin> [...]]
+=item B<FLUSH> [B<timeout=>I<Timeout>] [B<plugin=>I<Plugin> [...]] [B<identifier=>I<Ident> [...]]
Flushes all cached data older than I<Timeout> seconds. If no timeout has been
-specified, it defaults to -1 which causes all data to be flushed. B<timeout>
-may be specified multiple times - each occurrence applies to plugins listed
-afterwards.
+specified, it defaults to -1 which causes all data to be flushed.
+
+If the B<plugin> option has been specified, only the I<Plugin> plugin will be
+flushed. You can have multiple B<plugin> options to flush multiple plugins in
+one go. If the B<plugin> option is not given all plugins providing a flush
+callback will be flushed.
-If specified, only specific plugins are flushed. Otherwise all plugins
-providing a flush callback are flushed.
+If the B<identifier> option is given only the specified values will be flushed.
+This is meant to be used by graphing or displaying frontends which want to have
+the lastest values for a specific graph. Again, you can specify the
+B<identifier> option multiple times to flush several values. If this option is
+not specified at all, all values will be flushed.
Example:
- -> | FLUSH
- <- | 0 Done
+ -> | FLUSH plugin=rrdtool identifier=localhost/df/df-root identifier=localhost/df/df-var
+ <- | 0 Done: 2 successful, 0 errors
=back
I<Hostname>/I<Plugin>/I<Type>
Where I<Plugin> and I<Type> are both either of type "I<Name>" or
-"I<Name>-I<Instance>". This sounds more complicated than it is, so here are
+"I<Name>-I<Instance>". If the identifier includes spaces, it must be quoted
+using double quotes. This sounds more complicated than it is, so here are
some examples:
myhost/cpu-0/cpu-user
myhost/load/load
myhost/memory/memory-used
myhost/disk-sda/disk_octets
+ "myups/snmp/temperature-Outlet 1"
=head1 ABSTRACTION LAYER
static void *do_flush (void *arg)
{
INFO ("Flushing all data.");
- plugin_flush_all (-1);
+ plugin_flush (NULL, -1, NULL);
INFO ("Finished flushing all data.");
pthread_exit (NULL);
return NULL;
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;
}
@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email
@BUILD_PLUGIN_ENTROPY_TRUE@LoadPlugin entropy
@BUILD_PLUGIN_EXEC_TRUE@LoadPlugin exec
+@BUILD_PLUGIN_FILECOUNT_TRUE@LoadPlugin filecount
@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
@BUILD_PLUGIN_IPTABLES_TRUE@LoadPlugin iptables
@BUILD_PLUGIN_NETWORK_TRUE@LoadPlugin network
@BUILD_PLUGIN_NFS_TRUE@LoadPlugin nfs
@BUILD_PLUGIN_NGINX_TRUE@LoadPlugin nginx
+@BUILD_PLUGIN_NOTIFY_DESKTOP_TRUE@LoadPlugin notify_desktop
+@BUILD_PLUGIN_NOTIFY_EMAIL_TRUE@LoadPlugin notify_email
@BUILD_PLUGIN_NTPD_TRUE@LoadPlugin ntpd
@BUILD_PLUGIN_NUT_TRUE@LoadPlugin nut
+@BUILD_PLUGIN_ONEWIRE_TRUE@LoadPlugin onewire
@BUILD_PLUGIN_PERL_TRUE@LoadPlugin perl
@BUILD_PLUGIN_PING_TRUE@LoadPlugin ping
+@BUILD_PLUGIN_POSTGRESQL_TRUE@LoadPlugin postgresql
@BUILD_PLUGIN_POWERDNS_TRUE@LoadPlugin powerdns
@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
@BUILD_PLUGIN_RRDTOOL_TRUE@LoadPlugin rrdtool
@BUILD_PLUGIN_TAPE_TRUE@LoadPlugin tape
@BUILD_PLUGIN_TCPCONNS_TRUE@LoadPlugin tcpconns
@BUILD_PLUGIN_TEAMSPEAK2_TRUE@LoadPlugin teamspeak2
+@BUILD_PLUGIN_THERMAL_TRUE@LoadPlugin thermal
@BUILD_PLUGIN_UNIXSOCK_TRUE@LoadPlugin unixsock
@BUILD_PLUGIN_USERS_TRUE@LoadPlugin users
@BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid
# NotificationExec "user:group" "/path/to/exec"
#</Plugin>
+#<Plugin filecount>
+# <Directory "/path/to/dir">
+# Instance "foodir"
+# Name "*.conf"
+# MTime "-5m"
+# Size "+10k"
+# </Directory>
+#</Plugin>
+
@BUILD_PLUGIN_HDDTEMP_TRUE@<Plugin hddtemp>
# Host "127.0.0.1"
# Port "7634"
# CACert "/etc/ssl/ca.crt"
#</Plugin>
+#<Plugin notify_desktop>
+# OkayTimeout 1000
+# WarningTimeout 5000
+# FailureTimeout 0
+#</Plugin>
+
+#<Plugin notify_email>
+# SMTPServer "localhost"
+# SMTPPort 25
+# SMTPUser "my-username"
+# SMTPPassword "my-password"
+# From "collectd@main0server.com"
+# # <WARNING/FAILURE/OK> on <hostname>. beware! do not use not more than two %s in this string!!!
+# Subject "Aaaaaa!! %s on %s!!!!!"
+# Recipient "email1@domain1.net"
+# Recipient "email2@domain2.com"
+#</Plugin>
+
#<Plugin ntpd>
# Host "localhost"
# Port 123
# UPS "upsname@hostname:port"
#</Plugin>
+#<Plugin onewire>
+# Device "-s localhost:4304"
+# Sensor "F10FCA000800"
+# IgnoreSelected false
+#</Plugin>
+
#<Plugin perl>
# IncludeDir "/my/include/path"
# BaseName "Collectd::Plugin"
# EnableDebugger ""
# LoadPlugin foo
+#
+# <Plugin foo>
+# Foo "Bar"
+# Qux "Baz"
+# </Plugin>
#</Plugin>
#<Plugin ping>
# TTL 255
#</Plugin>
+#<Plugin postgresql>
+# <Query magic>
+# Query "SELECT magic, spells FROM wizard WHERE host = $1;"
+# Param hostname
+# Column gauge magic
+# Column counter spells
+# </Query>
+#
+# <Database foo>
+# Host "hostname"
+# Port 5432
+# User "username"
+# Password "secret"
+#
+# SSLMode "prefer"
+# KRBSrvName "kerberos_service_name"
+#
+# Query magic
+# </Database>
+#
+# <Database bar>
+# Service "service_name"
+# </Database>
+#</Plugin>
+
#<Plugin powerdns>
# <Server "server_name">
# Collect "latency"
# Server "8767"
#</Plugin>
+#<Plugin thermal>
+# ForceUseProcfs false
+# Device "THRM"
+# IgnoreSelected false
+#</Plugin>
+
#<Plugin unixsock>
# SocketFile "@prefix@/var/run/@PACKAGE_NAME@-unixsock"
# SocketGroup "collectd"
ignored. Values are either string, enclosed in double-quotes,
(floating-point-)numbers or a boolean expression, i.E<nbsp>e. either B<true> or
B<false>. String containing of only alphanumeric characters and underscores do
-not need to be quoted.
+not need to be quoted. Lines may be wrapped by using `\' as the last character
+before the newline. This allows long lines to be split into multiple lines.
+Quoted strings may be wrapped as well. However, those are treated special in
+that whitespace at the beginning of the following lines will be ignored, which
+allows for nicely indenting the wrapped lines.
The configuration is read and processed in order, i.E<nbsp>e. from top to
bottom. So the plugins are loaded in the order listed in this config file. It
Optional password needed for authentication.
+=item B<VerifyPeer> B<true|false>
+
+Enable or disable peer SSL certificate verification. See
+L<http://curl.haxx.se/docs/sslcerts.html> for details. Enabled by default.
+
+=item B<VerifyHost> B<true|false>
+
+Enable or disable peer host name verification. If enabled, the plugin checks
+if the C<Common Name> or a C<Subject Alternate Name> field of the SSL
+certificate matches the host name provided by the B<URL> option. If this
+identity check fails, the connection is aborted. Obviously, only works when
+connecting to a SSL enabled server. Enabled by default.
+
=item B<CACert> I<File>
File that holds one or more SSL certificates. If you want to use HTTPS you will
=back
+=head2 Plugin C<filecount>
+
+The C<filecount> plugin counts the number of files in a certain directory (and
+its subdirectories) and their combined size. The configuration is very straight
+forward:
+
+ <Plugin "filecount">
+ <Directory "/var/qmail/queue/mess">
+ Instance "qmail-message"
+ </Directory>
+ <Directory "/var/qmail/queue/todo">
+ Instance "qmail-todo"
+ </Directory>
+ <Directory "/var/lib/php5">
+ Instance "php5-sessions"
+ Name "sess_*"
+ </Directory>
+ </Plugin>
+
+The example above counts the number of files in QMail's queue directories and
+the number of PHP5 sessions. Jfiy: The "todo" queue holds the messages that
+QMail has not yet looked at, the "message" queue holds the messages that were
+classified into "local" and "remote".
+
+As you can see, the configuration consists of one or more C<Directory> blocks,
+each of which specifies a directory in which to count the files. Within those
+blocks, the following options are recognized:
+
+=over 4
+
+=item B<Instance> I<Instance>
+
+Sets the plugin instance to I<Instance>. That instance name must be unique, but
+it's your responsibility, the plugin doesn't check for that. If not given, the
+instance is set to the directory name with all slashes replaced by underscores
+and all leading underscores removed.
+
+=item B<Name> I<Pattern>
+
+Only count files that match I<Pattern>, where I<Pattern> is a shell-like
+wildcard as understood by L<fnmatch(3)>. Only the B<filename> is checked
+against the pattern, not the entire path. In case this makes it easier for you:
+This option has been named after the B<-name> parameter to L<find(1)>.
+
+=item B<MTime> I<Age>
+
+Count only files of a specific age: If I<Age> is greater than zero, only files
+that haven't been touched in the last I<Age> seconds are counted. If I<Age> is
+a negative number, this is inversed. For example, if B<-60> is specified, only
+files that have been modified in the last minute will be counted.
+
+The number can also be followed by a "multiplier" to easily specify a larger
+timespan. When given in this notation, the argument must in quoted, i.E<nbsp>e.
+must be passed as string. So the B<-60> could also be written as B<"-1m"> (one
+minute). Valid multipliers are C<s> (second), C<m> (minute), C<h> (hour), C<d>
+(day), C<w> (week), and C<y> (year). There is no "month" multiplier. You can
+also specify fractional numbers, e.E<nbsp>g. B<"0.5d"> is identical to
+B<"12h">.
+
+=item B<Size> I<Size>
+
+Count only files of a specific size. When I<Size> is a positive number, only
+files that are at least this big are counted. If I<Size> is a negative number,
+this is inversed, i.E<nbsp>e. only files smaller than the absolute value of
+I<Size> are counted.
+
+As with the B<MTime> option, a "multiplier" may be added. For a detailed
+description see above. Valid multipliers here are C<b> (byte), C<k> (kilobyte),
+C<m> (megabyte), C<g> (gigabyte), C<t> (terabyte), and C<p> (petabyte). Please
+note that there are 1000 bytes in a kilobyte, not 1024.
+
+=back
+
=head2 Plugin C<hddtemp>
To get values from B<hddtemp> collectd connects to B<localhost> (127.0.0.1),
interfaces you're interested in. Sometimes, however, it's easier/preferred
to collect all interfaces I<except> a few ones. This option enables you to
do that: By setting B<IgnoreSelected> to I<true> the effect of
-B<Interface> is inversed: All selected interfaces are ignored and all
+B<Interface> is inverted: All selected interfaces are ignored and all
other interfaces are collected.
=back
the effect of B<Sensor> is inverted: All selected sensors are ignored and
all other sensors are collected.
+=item B<NotifySensorAdd> I<true>|I<false>
+
+If a sensor appears after initialization time of a minute a notification
+is sent.
+
+=item B<NotifySensorRemove> I<true>|I<false>
+
+If a sensor disappears a notification is sent.
+
+=item B<NotifySensorNotPresent> I<true>|I<false>
+
+If you have for example dual power supply and one of them is (un)plugged then
+a notification is sent.
+
=back
=head2 Plugin C<iptables>
can use the B<Irq>-option to pick the interrupt you're interested in.
Sometimes, however, it's easier/preferred to collect all interrupts I<except> a
few ones. This option enables you to do that: By setting B<IgnoreSelected> to
-I<true> the effect of B<Irq> is inversed: All selected interrupts are ignored
+I<true> the effect of B<Irq> is inverted: All selected interrupts are ignored
and all other interrupts are collected.
=back
The behaviour is the same as with all other similar plugins: If nothing is
selected at all, everything is collected. If some things are selected using the
options described above, only these statistics are collected. If you set
-B<IgnoreSelected> to B<true>, this behavior is inversed, i.E<nbsp>e. the
+B<IgnoreSelected> to B<true>, this behavior is inverted, i.E<nbsp>e. the
specified statistics will not be collected.
=back
=back
+=head2 Plugin C<notify_desktop>
+
+This plugin sends a desktop notification to a notification daemon, as defined
+in the Desktop Notification Specification. To actually display the
+notifications, B<notification-daemon> is required and B<collectd> has to be
+able to access the X server.
+
+The Desktop Notification Specification can be found at
+L<http://www.galago-project.org/specs/notification/>.
+
+=over 4
+
+=item B<OkayTimeout> I<timeout>
+
+=item B<WarningTimeout> I<timeout>
+
+=item B<FailureTimeout> I<timeout>
+
+Set the I<timeout>, in milliseconds, after which to expire the notification
+for C<OKAY>, C<WARNING> and C<FAILURE> severities respectively. If zero has
+been specified, the displayed notification will not be closed at all - the
+user has to do so herself. These options default to 5000. If a negative number
+has been specified, the default is used as well.
+
+=back
+
=head2 Plugin C<ntpd>
=over 4
=back
+=head2 Plugin C<onewire>
+
+B<EXPERIMENTAL!> See notes below.
+
+The C<onewire> plugin uses the B<owcapi> library from the B<owfs> project
+L<http://owfs.org/> to read sensors connected via the onewire bus.
+
+Currently only temperature sensors (sensors with the family code C<10>,
+e.E<nbsp>g. DS1820, DS18S20, DS1920) can be read. If you have other sensors you
+would like to have included, please send a sort request to the mailing list.
+
+Hubs (the DS2409 chips) are working, but read the note, why this plugin is
+experimental, below.
+
+=over 4
+
+=item B<Device> I<Device>
+
+Sets the device to read the values from. This can either be a "real" hardware
+device, such as a serial port or an USB port, or the address of the
+L<owserver(1)> socket, usually B<localhost:4304>.
+
+Though the documentation claims to automatically recognize the given address
+format, with versionE<nbsp>2.7p4 we had to specify the type explicitly. So
+with that version, the following configuration worked for us:
+
+ <Plugin onewire>
+ Device "-s localhost:4304"
+ </Plugin>
+
+This directive is B<required> and does not have a default value.
+
+=item B<Sensor> I<Sensor>
+
+Selects sensors to collect or to ignore, depending on B<IgnoreSelected>, see
+below. Sensors are specified without the family byte at the beginning, to you'd
+use C<F10FCA000800>, and B<not> include the leading C<10.> family byte and
+point.
+
+=item B<IgnoreSelected> I<true>|I<false>
+
+If no configuration if given, the B<onewire> plugin will collect data from all
+sensors found. This may not be practical, especially if sensors are added and
+removed regularly. Sometimes, however, it's easier/preferred to collect only
+specific sensors or all sensors I<except> a few specified ones. This option
+enables you to do that: By setting B<IgnoreSelected> to I<true> the effect of
+B<Sensor> is inverted: All selected interfaces are ignored and all other
+interfaces are collected.
+
+=back
+
+B<EXPERIMENTAL!> The C<onewire> plugin is experimental, because it doesn't yet
+work with big setups. It works with one sensor being attached to one
+controller, but as soon as you throw in a couple more senors and maybe a hub
+or two, reading all values will take more than ten seconds (the default
+interval). We will probably add some separate thread for reading the sensors
+and some cache or something like that, but it's not done yet. We will try to
+maintain backwards compatibility in the future, but we can't probmise. So in
+short: If it works for you: Great! But kaap in mind that the config I<might>
+change, though this is unlikely. Oh, and if you want to help improving this
+plugin, just send a short notice to the mailing list. ThanksE<nbsp>:)
+
=head2 Plugin C<perl>
This plugin embeds a Perl-interpreter into collectd and provides an interface
=back
+=head2 Plugin C<postgresql>
+
+The C<postgresql> plugin queries statistics from PostgreSQL databases. It
+keeps a persistent connection to all configured databases and tries to
+reconnect if the connection has been interrupted. A database is configured by
+specifying a B<Database> block as described below. The default statistics are
+collected from PostgreSQL's B<statistics collector> which thus has to be
+enabled for this plugin to work correctly. This should usually be the case by
+default. See the section "The Statistics Collector" of the B<PostgreSQL
+Documentation> for details.
+
+By specifying custom database queries using a B<Query> block as described
+below, you may collect any data that is available from some PostgreSQL
+database. This way, you are able to access statistics of external daemons
+which are available in a PostgreSQL database or use future or special
+statistics provided by PostgreSQL without the need to upgrade your collectd
+installation.
+
+The B<PostgreSQL Documentation> manual can be found at
+L<http://www.postgresql.org/docs/manuals/>.
+
+ <Plugin postgresql>
+ <Query magic>
+ Query "SELECT magic, spells FROM wizard WHERE host = $1;"
+ Param hostname
+ Column gauge magic
+ Column counter spells
+ </Query>
+
+ <Database foo>
+ Host "hostname"
+ Port "5432"
+ User "username"
+ Password "secret"
+ SSLMode "prefer"
+ KRBSrvName "kerberos_service_name"
+ Query magic
+ </Database>
+ <Database bar>
+ Service "service_name"
+ </Database>
+ </Plugin>
+
+The B<Query> block defines one database query which may later be used by a
+database definition. It accepts a single mandatory argument which specifies
+the name of the query. The names of all queries have to be unique. The
+following configuration options are available to define the query:
+
+=over 4
+
+=item B<Query> I<sql query>
+
+Specify the I<sql query> which the plugin should execute. The string may
+contain the tokens B<$1>, B<$2>, etc. which are used to reference the first,
+second, etc. parameter. The value of the parameters is specified by the
+B<Param> configuration option - see below for details. To include a literal
+B<$> character followed by a number, surround it with single quotes (B<'>).
+
+Any SQL command which may return data (such as C<SELECT> or C<SHOW>) is
+allowed. Note, however, that only a single command may be used. Semicolons are
+allowed as long as a single non-empty command has been specified only.
+
+=item B<Param> I<hostname>|I<database>|I<username>
+
+Specify the parameters which should be passed to the SQL query. The parameters
+are referred to in the SQL query as B<$1>, B<$2>, etc. in the same order as
+they appear in the configuration file. The value of the parameter is
+determined depending on the value of the B<Param> option as follows:
+
+=over 4
+
+=item I<hostname>
+
+The configured hostname of the database connection. If a UNIX domain socket is
+used, the parameter expands to "localhost".
+
+=item I<database>
+
+The name of the database of the current connection.
+
+=item I<username>
+
+The username used to connect to the database.
+
+=back
+
+Please note that parameters are only supported by PostgreSQL's protocol
+version 3 and above which was introduced in version 7.4 of PostgreSQL.
+
+=item B<Column> I<type> [I<type instance>]
+
+Specify the I<type> and optional I<type instance> used to dispatch the value
+of each result column. Detailed information about types and their
+configuration can be found in L<types.db(5)>. The number and order of the
+B<Column> options has to match the columns of the query result.
+
+=item B<MinPGVersion> I<version>
+
+=item B<MaxPGVersion> I<version>
+
+Specify the minimum or maximum version of PostgreSQL that this query should be
+used with. Some statistics might only be available with certain versions of
+PostgreSQL. This allows you to specify multiple queries with the same name but
+which apply to different versions, thus allowing you to use the same
+configuration in a heterogeneous environment.
+
+The I<version> has to be specified as the concatenation of the major, minor
+and patch-level versions, each represented as two-decimal-digit numbers. For
+example, version 8.2.3 will become 80203.
+
+=back
+
+The following predefined queries are available (the definitions can be found
+in the F<postgresql_default.conf> file which, by default, is available at
+C<I<prefix>/share/collectd/>):
+
+=over 4
+
+=item B<backends>
+
+This query collects the number of backends, i.E<nbsp>e. the number of
+connected clients.
+
+=item B<transactions>
+
+This query collects the numbers of committed and rolled-back transactions of
+the user tables.
+
+=item B<queries>
+
+This query collects the numbers of various table modifications (i.E<nbsp>e.
+insertions, updates, deletions) of the user tables.
+
+=item B<query_plans>
+
+This query collects the numbers of various table scans and returned tuples of
+the user tables.
+
+=item B<table_states>
+
+This query collects the numbers of live and dead rows in the user tables.
+
+=item B<disk_io>
+
+This query collects disk block access counts for user tables.
+
+=item B<disk_usage>
+
+This query collects the on-disk size of the database in bytes.
+
+=back
+
+The B<Database> block defines one PostgreSQL database for which to collect
+statistics. It accepts a single mandatory argument which specifies the
+database name. None of the other options are required. PostgreSQL will use
+default values as documented in the section "CONNECTING TO A DATABASE" in the
+L<psql(1)> manpage. However, be aware that those defaults may be influenced by
+the user collectd is run as and special environment variables. See the manpage
+for details.
+
+=over 4
+
+=item B<Host> I<hostname>
+
+Specify the hostname or IP of the PostgreSQL server to connect to. If the
+value begins with a slash, it is interpreted as the directory name in which to
+look for the UNIX domain socket.
+
+This option is also used to determine the hostname that is associated with a
+collected data set. If it has been omitted or either begins with with a slash
+or equals B<localhost> it will be replaced with the global hostname definition
+of collectd. Any other value will be passed literally to collectd when
+dispatching values. Also see the global B<Hostname> and B<FQDNLookup> options.
+
+=item B<Port> I<port>
+
+Specify the TCP port or the local UNIX domain socket file extension of the
+server.
+
+=item B<User> I<username>
+
+Specify the username to be used when connecting to the server.
+
+=item B<Password> I<password>
+
+Specify the password to be used when connecting to the server.
+
+=item B<SSLMode> I<disable>|I<allow>|I<prefer>|I<require>
+
+Specify whether to use an SSL connection when contacting the server. The
+following modes are supported:
+
+=over 4
+
+=item I<disable>
+
+Do not use SSL at all.
+
+=item I<allow>
+
+First, try to connect without using SSL. If that fails, try using SSL.
+
+=item I<prefer> (default)
+
+First, try to connect using SSL. If that fails, try without using SSL.
+
+=item I<require>
+
+Use SSL only.
+
+=back
+
+=item B<KRBSrvName> I<kerberos_service_name>
+
+Specify the Kerberos service name to use when authenticating with Kerberos 5
+or GSSAPI. See the sections "Kerberos authentication" and "GSSAPI" of the
+B<PostgreSQL Documentation> for details.
+
+=item B<Service> I<service_name>
+
+Specify the PostgreSQL service name to use for additional parameters. That
+service has to be defined in F<pg_service.conf> and holds additional
+connection parameters. See the section "The Connection Service File" in the
+B<PostgreSQL Documentation> for details.
+
+=item B<Query> I<query>
+
+Specify a I<query> which should be executed for the database connection. This
+may be any of the predefined or user-defined queries. If no such option is
+given, it defaults to "backends", "transactions", "queries", "query_plans",
+"table_states", "disk_io" and "disk_usage". Else, the specified queries are
+used only.
+
+=back
+
=head2 Plugin C<powerdns>
The C<powerdns> plugin queries statistics from an authoritative PowerDNS
=item B<CacheFlush> I<Seconds>
-When the C<rrdtool plugin> uses a cache (by setting B<CacheTimeout>, see below)
+When the C<rrdtool> plugin uses a cache (by setting B<CacheTimeout>, see below)
it writes all values for a certain RRD-file if the oldest value is older than
(or equal to) the number of seconds specified. If some RRD-file is not updated
anymore for some reason (the computer was shut down, the network is broken,
The trade off is that the graphs kind of "drag behind" and that more memory is
used.
+=item B<WritesPerSecond> B<Updates>
+
+When collecting many statistics with collectd and the C<rrdtool> plugin, you
+will run serious performance problems. The B<CacheFlush> setting and the
+internal update queue assert that collectd continues to work just fine even
+under heavy load, but the system may become very unresponsive and slow. This is
+a problem especially if you create graphs from the RRD files on the same
+machine, for example using the C<graph.cgi> script included in the
+C<contrib/collection3/> directory.
+
+This setting is designed for very large setups. Setting this option to a value
+between 25 and 80 updates per second, depending on your hardware, will leave
+the server responsive enough to draw graphs even while all the cached values
+are written to disk. Flushed values, i.E<nbsp>e. values that are forced to disk
+by the B<FLUSH> command, are B<not> effected by this limit. They are still
+written as fast as possible, so that web frontends have up to date data when
+generating graphs.
+
+For example: If you have 100,000 RRD files and set B<WritesPerSecond> to 30
+updates per second, writing all values to disk will take approximately
+56E<nbsp>minutes. Together with the flushing ability that's integrated into
+"collection3" you'll end up with a responsive and fast system, up to date
+graphs and basically a "backup" of your values every hour.
+
=back
=head2 Plugin C<sensors>
Thus, you can use the B<Sensor>-option to pick the sensors you're interested
in. Sometimes, however, it's easier/preferred to collect all sensors I<except> a
few ones. This option enables you to do that: By setting B<IgnoreSelected> to
-I<true> the effect of B<Sensor> is inversed: All selected sensors are ignored
+I<true> the effect of B<Sensor> is inverted: All selected sensors are ignored
and all other sensors are collected.
=back
=back
+=head2 Plugin C<thermal>
+
+=over 4
+
+=item B<ForceUseProcfs> I<true>|I<false>
+
+By default, the C<thermal> plugin tries to read the statistics from the Linux
+C<sysfs> interface. If that is not available, the plugin falls back to the
+C<procfs> interface. By setting this option to I<true>, you can force the
+plugin to use the latter. This option defaults to I<false>.
+
+=item B<Device> I<Device>
+
+Selects the name of the thermal device that you want to collect or ignore,
+depending on the value of the B<IgnoreSelected> option. This option may be
+used multiple times to specify a list of devices.
+
+=item B<IgnoreSelected> I<true>|I<false>
+
+Invert the selection: If set to true, all devices B<except> the ones that
+match the device names specified by the B<Device> option are collected. By
+default only selected devices are collected if a selection is made. If no
+selection is configured at all, B<all> devices are selected.
+
+=back
+
=head2 Plugin C<unixsock>
=over 4
L<hddtemp(8)>,
L<kstat(3KSTAT)>,
L<mbmon(1)>,
+L<psql(1)>,
L<rrdtool(1)>,
L<sensors(1)>
#if HAVE_STDINT_H
# include <stdint.h>
#endif
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#define PLUGINDIR PREFIX "/lib/" PACKAGE_NAME
#endif
+#ifndef PKGDATADIR
+#define PKGDATADIR PREFIX "/share/" PACKAGE_NAME
+#endif
+
#ifndef COLLECTD_GRP_NAME
# define COLLECTD_GRP_NAME "collectd"
#endif
return (dest);
} /* char *sstrncpy */
+int ssnprintf (char *dest, size_t n, const char *format, ...)
+{
+ int ret = 0;
+ va_list ap;
+
+ va_start (ap, format);
+ ret = vsnprintf (dest, n, format, ap);
+ dest[n - 1] = '\0';
+ va_end (ap);
+
+ return (ret);
+} /* int ssnprintf */
+
char *sstrdup (const char *s)
{
char *r;
pthread_mutex_lock (&strerror_r_lock);
temp = strerror (errnum);
- strncpy (buf, temp, buflen);
+ sstrncpy (buf, temp, buflen);
pthread_mutex_unlock (&strerror_r_lock);
}
if (buf[0] == '\0')
{
if ((temp != NULL) && (temp != buf) && (temp[0] != '\0'))
- strncpy (buf, temp, buflen);
+ sstrncpy (buf, temp, buflen);
else
- strncpy (buf, "strerror_r did not return "
+ sstrncpy (buf, "strerror_r did not return "
"an error message", buflen);
}
}
#else
if (strerror_r (errnum, buf, buflen) != 0)
{
- snprintf (buf, buflen, "Error #%i; "
+ ssnprintf (buf, buflen, "Error #%i; "
"Additionally, strerror_r failed.",
errnum);
}
#endif /* STRERROR_R_CHAR_P */
- buf[buflen - 1] = '\0';
return (buf);
} /* char *sstrerror */
if ((len = strlen (file_orig)) < 1)
return (-1);
- else if (len >= 512)
+ else if (len >= sizeof (file_copy))
return (-1);
/*
/*
* Create a copy for `strtok_r' to destroy
*/
- strncpy (file_copy, file_orig, 512);
- file_copy[511] = '\0';
+ sstrncpy (file_copy, file_orig, sizeof (file_copy));
/*
* Break into components. This will eat up several slashes in a row and
if (kc == NULL)
return (-1);
- snprintf (ident, 128, "%s,%i,%s", module, instance, name);
- ident[127] = '\0';
+ ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name);
if (*ksp_ptr == NULL)
{
if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
{
if ((type_instance == NULL) || (strlen (type_instance) == 0))
- status = snprintf (ret, ret_len, "%s/%s/%s",
+ status = ssnprintf (ret, ret_len, "%s/%s/%s",
hostname, plugin, type);
else
- status = snprintf (ret, ret_len, "%s/%s/%s-%s",
+ status = ssnprintf (ret, ret_len, "%s/%s/%s-%s",
hostname, plugin, type,
type_instance);
}
else
{
if ((type_instance == NULL) || (strlen (type_instance) == 0))
- status = snprintf (ret, ret_len, "%s/%s-%s/%s",
+ status = ssnprintf (ret, ret_len, "%s/%s-%s/%s",
hostname, plugin, plugin_instance,
type);
else
- status = snprintf (ret, ret_len, "%s/%s-%s/%s-%s",
+ status = ssnprintf (ret, ret_len, "%s/%s-%s/%s-%s",
hostname, plugin, plugin_instance,
type, type_instance);
}
n->severity = severity;
if (message != NULL)
- strncpy (n->message, message, sizeof (n->message));
+ sstrncpy (n->message, message, sizeof (n->message));
if (host != NULL)
- strncpy (n->host, host, sizeof (n->host));
+ sstrncpy (n->host, host, sizeof (n->host));
if (plugin != NULL)
- strncpy (n->plugin, plugin, sizeof (n->plugin));
+ sstrncpy (n->plugin, plugin, sizeof (n->plugin));
if (plugin_instance != NULL)
- strncpy (n->plugin_instance, plugin_instance,
+ sstrncpy (n->plugin_instance, plugin_instance,
sizeof (n->plugin_instance));
if (type != NULL)
- strncpy (n->type, type, sizeof (n->type));
+ sstrncpy (n->type, type, sizeof (n->type));
if (type_instance != NULL)
- strncpy (n->type_instance, type_instance,
+ sstrncpy (n->type_instance, type_instance,
sizeof (n->type_instance));
- n->message[sizeof (n->message) - 1] = '\0';
- n->host[sizeof (n->host) - 1] = '\0';
- n->plugin[sizeof (n->plugin) - 1] = '\0';
- n->plugin_instance[sizeof (n->plugin_instance) - 1] = '\0';
- n->type[sizeof (n->type) - 1] = '\0';
- n->type_instance[sizeof (n->type_instance) - 1] = '\0';
-
return (0);
} /* int notification_init */
+
+int walk_directory (const char *dir, dirwalk_callback_f callback,
+ void *user_data)
+{
+ struct dirent *ent;
+ DIR *dh;
+ int success;
+ int failure;
+
+ success = 0;
+ failure = 0;
+
+ if ((dh = opendir (dir)) == NULL)
+ {
+ char errbuf[1024];
+ ERROR ("walk_directory: Cannot open '%s': %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return -1;
+ }
+
+ while ((ent = readdir (dh)) != NULL)
+ {
+ int status;
+
+ if (ent->d_name[0] == '.')
+ continue;
+
+ status = (*callback) (dir, ent->d_name, user_data);
+ if (status != 0)
+ failure++;
+ else
+ success++;
+ }
+
+ closedir (dh);
+
+ if ((success == 0) && (failure > 0))
+ return (-1);
+ return (0);
+}
+
+int read_file_contents (const char *filename, char *buf, int bufsize)
+{
+ FILE *fh;
+ int n;
+
+ if ((fh = fopen (filename, "r")) == NULL)
+ return -1;
+
+ n = fread(buf, 1, bufsize, fh);
+ fclose(fh);
+
+ return n;
+}
+
+
#define STATIC_ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
char *sstrncpy (char *dest, const char *src, size_t n);
+int ssnprintf (char *dest, size_t n, const char *format, ...);
char *sstrdup(const char *s);
void *smalloc(size_t size);
char *sstrerror (int errnum, char *buf, size_t buflen);
notification_init (n, NOTIF_FAILURE, NULL, \
(vl)->host, (vl)->plugin, (vl)->plugin_instance, \
(ds)->type, (vl)->type_instance)
+
+typedef int (*dirwalk_callback_f)(const char *dirname, const char *filename,
+ void *user_data);
+int walk_directory (const char *dir, dirwalk_callback_f callback,
+ void *user_data);
+int read_file_contents (const char *filename, char *buf, int bufsize);
+
#endif /* COMMON_H */
for (i = 0; i < cf_cb->keys_num; i++)
{
- if (strcasecmp (cf_cb->keys[i], key) == 0)
+ if ((cf_cb->keys[i] != NULL)
+ && (strcasecmp (cf_cb->keys[i], key) == 0))
{
ret = (*cf_cb->callback) (key, value);
break;
else if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
{
char tmp[128];
- snprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number);
- tmp[127] = '\0';
+ ssnprintf (tmp, sizeof (tmp), "%lf", ci->values[0].value.number);
return (global_option_set (ci->key, tmp));
}
else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN)
int status = -1;
if (ci->values[i].type == OCONFIG_TYPE_STRING)
- status = snprintf (buffer_ptr, buffer_free, " %s",
+ status = ssnprintf (buffer_ptr, buffer_free, " %s",
ci->values[i].value.string);
else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
- status = snprintf (buffer_ptr, buffer_free, " %lf",
+ status = ssnprintf (buffer_ptr, buffer_free, " %lf",
ci->values[i].value.number);
else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
- status = snprintf (buffer_ptr, buffer_free, " %s",
+ status = ssnprintf (buffer_ptr, buffer_free, " %s",
ci->values[i].value.boolean
? "true" : "false");
if ((de->d_name[0] == '.') || (de->d_name[0] == '\0'))
continue;
- status = snprintf (name, sizeof (name), "%s/%s",
+ status = ssnprintf (name, sizeof (name), "%s/%s",
dir, de->d_name);
if (status >= sizeof (name))
{
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
- snprintf (vl.plugin_instance, sizeof (vl.type_instance),
+ ssnprintf (vl.plugin_instance, sizeof (vl.type_instance),
"%i", cpu_num);
- vl.plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
+ sstrncpy (vl.type, "cpu", sizeof (vl.type));
sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values ("cpu", &vl);
+ plugin_dispatch_values (&vl);
}
static int cpu_read (void)
while (1)
{
- status = snprintf (filename, sizeof (filename),
+ status = ssnprintf (filename, sizeof (filename),
"/sys/devices/system/cpu/cpu%d/cpufreq/"
"scaling_cur_freq", num_cpu);
if ((status < 1) || ((unsigned int)status >= sizeof (filename)))
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "cpufreq", sizeof (vl.plugin));
- snprintf (vl.type_instance, sizeof (vl.type_instance),
+ sstrncpy (vl.type, "cpufreq", sizeof (vl.type));
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance),
"%i", cpu_num);
- plugin_dispatch_values ("cpufreq", &vl);
+ plugin_dispatch_values (&vl);
}
static int cpufreq_read (void)
for (i = 0; i < num_cpu; i++)
{
- status = snprintf (filename, sizeof (filename),
+ status = ssnprintf (filename, sizeof (filename),
"/sys/devices/system/cpu/cpu%d/cpufreq/"
"scaling_cur_freq", i);
if ((status < 1) || ((unsigned int)status >= sizeof (filename)))
int i;
gauge_t *rates = NULL;
+ assert (0 == strcmp (ds->type, vl->type));
+
memset (buffer, '\0', buffer_len);
- status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
if ((status < 1) || (status >= buffer_len))
return (-1);
offset = status;
{
if (store_rates == 0)
{
- status = snprintf (buffer + offset,
+ status = ssnprintf (buffer + offset,
buffer_len - offset,
",%llu",
vl->values[i].counter);
"uc_get_rate failed.");
return (-1);
}
- status = snprintf (buffer + offset,
+ status = ssnprintf (buffer + offset,
buffer_len - offset,
",%lf", rates[i]);
}
}
else /* if (ds->ds[i].type == DS_TYPE_GAUGE) */
{
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
",%lf", vl->values[i].gauge);
}
int offset = 0;
int status;
+ assert (0 == strcmp (ds->type, vl->type));
+
if (datadir != NULL)
{
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s/", datadir);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
}
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s/", vl->host);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
if (strlen (vl->plugin_instance) > 0)
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s-%s/", vl->plugin, vl->plugin_instance);
else
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s/", vl->plugin);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
if (strlen (vl->type_instance) > 0)
- status = snprintf (buffer + offset, buffer_len - offset,
- "%s-%s", ds->type, vl->type_instance);
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s-%s", vl->type, vl->type_instance);
else
- status = snprintf (buffer + offset, buffer_len - offset,
- "%s", ds->type);
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s", vl->type);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
struct flock fl;
int status;
+ if (0 != strcmp (ds->type, vl->type)) {
+ ERROR ("csv plugin: DS type does not match value list type");
+ return -1;
+ }
+
if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
return (-1);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "df", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
+ sstrncpy (vl.type, "df", sizeof (vl.host));
+ sstrncpy (vl.type_instance, df_name, sizeof (vl.type_instance));
- plugin_dispatch_values ("df", &vl);
+ plugin_dispatch_values (&vl);
} /* void df_submit */
static int df_read (void)
if (strcmp (mnt_ptr->dir, "/") == 0)
{
- strncpy (mnt_name, "root", sizeof (mnt_name));
+ sstrncpy (mnt_name, "root", sizeof (mnt_name));
}
else
{
int i, len;
- strncpy (mnt_name, mnt_ptr->dir + 1, sizeof (mnt_name));
+ sstrncpy (mnt_name, mnt_ptr->dir + 1, sizeof (mnt_name));
len = strlen (mnt_name);
for (i = 0; i < len; i++)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "disk", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, plugin_instance,
+ sstrncpy (vl.plugin_instance, plugin_instance,
sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void disk_submit */
#if HAVE_IOKIT_IOKITLIB_H
write_tme = dict_get_value (stats_dict,
kIOBlockStorageDriverStatisticsTotalWriteTimeKey);
- if (snprintf (disk_name, 64, "%i-%i", disk_major, disk_minor) >= 64)
+ if (ssnprintf (disk_name, sizeof (disk_name),
+ "%i-%i", disk_major, disk_minor) >= sizeof (disk_name))
{
DEBUG ("snprintf (major, minor) failed.");
CFRelease (child_dict);
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "dns", sizeof (vl.plugin));
- 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 submit_counter */
static void submit_octets (counter_t queries, counter_t responses)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "dns", sizeof (vl.plugin));
+ sstrncpy (vl.type, "dns_octets", sizeof (vl.type));
- plugin_dispatch_values ("dns_octets", &vl);
+ plugin_dispatch_values (&vl);
} /* void submit_counter */
static int dns_read (void)
}
addr.sun_family = AF_UNIX;
-
- 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));
errno = 0;
if (-1 == bind (connector_socket, (struct sockaddr *)&addr,
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "email", sizeof (vl.plugin));
- 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
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "entropy", sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
+ sstrncpy (vl.type, "entropy", sizeof (vl.type));
- plugin_dispatch_values ("entropy", &vl);
+ plugin_dispatch_values (&vl);
}
static int entropy_read (void)
{
char *tmp = strrchr (ci->values[1].value.string, '/');
if (tmp == NULL)
- strncpy (buffer, ci->values[1].value.string, sizeof (buffer));
+ sstrncpy (buffer, ci->values[1].value.string, sizeof (buffer));
else
- strncpy (buffer, tmp + 1, sizeof (buffer));
- buffer[sizeof (buffer) - 1] = '\0';
+ sstrncpy (buffer, tmp + 1, sizeof (buffer));
}
pl->argv[0] = strdup (buffer);
if (pl->argv[0] == NULL)
{
if (ci->values[i + 1].type == OCONFIG_TYPE_NUMBER)
{
- snprintf (buffer, sizeof (buffer), "%lf",
+ ssnprintf (buffer, sizeof (buffer), "%lf",
ci->values[i + 1].value.number);
}
else
{
if (ci->values[i + 1].value.boolean)
- strncpy (buffer, "true", sizeof (buffer));
+ sstrncpy (buffer, "true", sizeof (buffer));
else
- strncpy (buffer, "false", sizeof (buffer));
+ sstrncpy (buffer, "false", sizeof (buffer));
}
- buffer[sizeof (buffer) - 1] = '\0';
pl->argv[i] = strdup (buffer);
}
static int parse_line (char *buffer) /* {{{ */
{
- char *fields[256];
- int fields_num;
-
- fields[0] = "PUTVAL";
- fields_num = strsplit (buffer, fields + 1, STATIC_ARRAY_SIZE(fields) - 1);
-
- if (strcasecmp (fields[1], "putval") == 0)
- return (handle_putval (stdout, fields + 1, fields_num));
- else if (strcasecmp (fields[1], "putnotif") == 0)
- return (handle_putnotif (stdout, fields + 1, fields_num));
-
- /* compatibility code */
- return (handle_putval (stdout, fields, fields_num + 1));
+ if (strncasecmp ("PUTVAL", buffer, strlen ("PUTVAL")) == 0)
+ return (handle_putval (stdout, buffer));
+ else if (strncasecmp ("PUTNOTIF", buffer, strlen ("PUTNOTIF")) == 0)
+ return (handle_putnotif (stdout, buffer));
+ else
+ {
+ /* For backwards compatibility */
+ char tmp[1220];
+ /* Let's annoy the user a bit.. */
+ INFO ("exec plugin: Prepending `PUTVAL' to this line: %s", buffer);
+ ssnprintf (tmp, sizeof (tmp), "PUTVAL %s", buffer);
+ return (handle_putval (stdout, tmp));
+ }
} /* int parse_line }}} */
static void *exec_read_one (void *arg) /* {{{ */
static void *exec_notification_one (void *arg) /* {{{ */
{
program_list_t *pl = ((program_list_and_notification_t *) arg)->pl;
- const notification_t *n = &((program_list_and_notification_t *) arg)->n;
+ notification_t *n = &((program_list_and_notification_t *) arg)->n;
+ notification_meta_t *meta;
int fd;
FILE *fh;
int pid;
if (strlen (n->type_instance) > 0)
fprintf (fh, "TypeInstance: %s\n", n->type_instance);
+ for (meta = n->meta; meta != NULL; meta = meta->next)
+ {
+ if (meta->type == NM_TYPE_STRING)
+ fprintf (fh, "%s: %s\n", meta->name, meta->nm_value.nm_string);
+ else if (meta->type == NM_TYPE_SIGNED_INT)
+ fprintf (fh, "%s: %"PRIi64"\n", meta->name, meta->nm_value.nm_signed_int);
+ else if (meta->type == NM_TYPE_UNSIGNED_INT)
+ fprintf (fh, "%s: %"PRIu64"\n", meta->name, meta->nm_value.nm_unsigned_int);
+ else if (meta->type == NM_TYPE_DOUBLE)
+ fprintf (fh, "%s: %e\n", meta->name, meta->nm_value.nm_double);
+ else if (meta->type == NM_TYPE_BOOLEAN)
+ fprintf (fh, "%s: %s\n", meta->name,
+ meta->nm_value.nm_boolean ? "true" : "false");
+ }
+
fprintf (fh, "\n%s\n", n->message);
fflush (fh);
DEBUG ("exec plugin: Child %i exited with status %i.",
pid, status);
+ plugin_notification_meta_free (n);
sfree (arg);
pthread_exit ((void *) 0);
return (NULL);
pln->pl = pl;
memcpy (&pln->n, n, sizeof (notification_t));
+ /* Set the `meta' member to NULL, otherwise `plugin_notification_meta_copy'
+ * will run into an endless loop. */
+ pln->n.meta = NULL;
+ plugin_notification_meta_copy (&pln->n, n);
+
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&t, &attr, exec_notification_one, (void *) pln);
--- /dev/null
+/**
+ * collectd - src/filecount.c
+ * Copyright (C) 2008 Alessandro Iurlano
+ * Copyright (C) 2008 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
+ * 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:
+ * Alessandro Iurlano <alessandro.iurlano at gmail.com>
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <fnmatch.h>
+
+struct fc_directory_conf_s
+{
+ char *path;
+ char *instance;
+
+ /* Data counters */
+ uint64_t files_num;
+ uint64_t files_size;
+
+ /* Selectors */
+ char *name;
+ int64_t mtime;
+ int64_t size;
+
+ /* Helper for the recursive functions */
+ time_t now;
+};
+typedef struct fc_directory_conf_s fc_directory_conf_t;
+
+static fc_directory_conf_t **directories = NULL;
+static size_t directories_num = 0;
+
+static void fc_submit_dir (const fc_directory_conf_t *dir)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = (gauge_t) dir->files_num;
+
+ vl.values = values;
+ vl.values_len = STATIC_ARRAY_SIZE (values);
+ vl.time = time (NULL);
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "filecount", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, dir->instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "files", sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+
+ values[0].gauge = (gauge_t) dir->files_size;
+ sstrncpy (vl.type, "bytes", sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+} /* void fc_submit_dir */
+
+/*
+ * Config:
+ * <Plugin filecount>
+ * <Directory /path/to/dir>
+ * Instance "foobar"
+ * Name "*.conf"
+ * MTime -3600
+ * Size "+10M"
+ * </Directory>
+ * </Plugin>
+ *
+ * Collect:
+ * - Number of files
+ * - Total size
+ */
+
+static int fc_config_set_instance (fc_directory_conf_t *dir, const char *str)
+{
+ char buffer[1024];
+ char *ptr;
+ char *copy;
+
+ sstrncpy (buffer, str, sizeof (buffer));
+ for (ptr = buffer; *ptr != 0; ptr++)
+ if (*ptr == '/')
+ *ptr = '_';
+
+ for (ptr = buffer; *ptr == '_'; ptr++)
+ /* do nothing */;
+
+ if (*ptr == 0)
+ return (-1);
+
+ copy = strdup (ptr);
+ if (copy == NULL)
+ return (-1);
+
+ sfree (dir->instance);
+ dir->instance = copy;
+
+ return (0);
+} /* int fc_config_set_instance */
+
+static int fc_config_add_dir_instance (fc_directory_conf_t *dir,
+ oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("filecount plugin: The `Instance' config option needs exactly "
+ "one string argument.");
+ return (-1);
+ }
+
+ return (fc_config_set_instance (dir, ci->values[0].value.string));
+} /* int fc_config_add_dir_instance */
+
+static int fc_config_add_dir_name (fc_directory_conf_t *dir,
+ oconfig_item_t *ci)
+{
+ char *temp;
+
+ if ((ci->values_num != 1)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("filecount plugin: The `Name' config option needs exactly one "
+ "string argument.");
+ return (-1);
+ }
+
+ temp = strdup (ci->values[0].value.string);
+ if (temp == NULL)
+ {
+ ERROR ("filecount plugin: strdup failed.");
+ return (-1);
+ }
+
+ sfree (dir->name);
+ dir->name = temp;
+
+ return (0);
+} /* int fc_config_add_dir_name */
+
+static int fc_config_add_dir_mtime (fc_directory_conf_t *dir,
+ oconfig_item_t *ci)
+{
+ char *endptr;
+ double temp;
+
+ if ((ci->values_num != 1)
+ || ((ci->values[0].type != OCONFIG_TYPE_STRING)
+ && (ci->values[0].type != OCONFIG_TYPE_NUMBER)))
+ {
+ WARNING ("filecount plugin: The `MTime' config option needs exactly one "
+ "string or numeric argument.");
+ return (-1);
+ }
+
+ if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
+ {
+ dir->mtime = (int64_t) ci->values[0].value.number;
+ return (0);
+ }
+
+ errno = 0;
+ endptr = NULL;
+ temp = strtod (ci->values[0].value.string, &endptr);
+ if ((errno != 0) || (endptr == NULL)
+ || (endptr == ci->values[0].value.string))
+ {
+ WARNING ("filecount plugin: Converting `%s' to a number failed.",
+ ci->values[0].value.string);
+ return (-1);
+ }
+
+ switch (*endptr)
+ {
+ case 0:
+ case 's':
+ case 'S':
+ break;
+
+ case 'm':
+ case 'M':
+ temp *= 60;
+ break;
+
+ case 'h':
+ case 'H':
+ temp *= 3600;
+ break;
+
+ case 'd':
+ case 'D':
+ temp *= 86400;
+ break;
+
+ case 'w':
+ case 'W':
+ temp *= 7 * 86400;
+ break;
+
+ case 'y':
+ case 'Y':
+ temp *= 31557600; /* == 365.25 * 86400 */
+ break;
+
+ default:
+ WARNING ("filecount plugin: Invalid suffix for `MTime': `%c'", *endptr);
+ return (-1);
+ } /* switch (*endptr) */
+
+ dir->mtime = (int64_t) temp;
+
+ return (0);
+} /* int fc_config_add_dir_mtime */
+
+static int fc_config_add_dir_size (fc_directory_conf_t *dir,
+ oconfig_item_t *ci)
+{
+ char *endptr;
+ double temp;
+
+ if ((ci->values_num != 1)
+ || ((ci->values[0].type != OCONFIG_TYPE_STRING)
+ && (ci->values[0].type != OCONFIG_TYPE_NUMBER)))
+ {
+ WARNING ("filecount plugin: The `Size' config option needs exactly one "
+ "string or numeric argument.");
+ return (-1);
+ }
+
+ if (ci->values[0].type == OCONFIG_TYPE_NUMBER)
+ {
+ dir->size = (int64_t) ci->values[0].value.number;
+ return (0);
+ }
+
+ errno = 0;
+ endptr = NULL;
+ temp = strtod (ci->values[0].value.string, &endptr);
+ if ((errno != 0) || (endptr == NULL)
+ || (endptr == ci->values[0].value.string))
+ {
+ WARNING ("filecount plugin: Converting `%s' to a number failed.",
+ ci->values[0].value.string);
+ return (-1);
+ }
+
+ switch (*endptr)
+ {
+ case 0:
+ case 'b':
+ case 'B':
+ break;
+
+ case 'k':
+ case 'K':
+ temp *= 1000.0;
+ break;
+
+ case 'm':
+ case 'M':
+ temp *= 1000.0 * 1000.0;
+ break;
+
+ case 'g':
+ case 'G':
+ temp *= 1000.0 * 1000.0 * 1000.0;
+ break;
+
+ case 't':
+ case 'T':
+ temp *= 1000.0 * 1000.0 * 1000.0 * 1000.0;
+ break;
+
+ case 'p':
+ case 'P':
+ temp *= 1000.0 * 1000.0 * 1000.0 * 1000.0 * 1000.0;
+ break;
+
+ default:
+ WARNING ("filecount plugin: Invalid suffix for `Size': `%c'", *endptr);
+ return (-1);
+ } /* switch (*endptr) */
+
+ dir->size = (int64_t) temp;
+
+ return (0);
+} /* int fc_config_add_dir_size */
+
+static int fc_config_add_dir (oconfig_item_t *ci)
+{
+ fc_directory_conf_t *dir;
+ int status;
+ int i;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("filecount plugin: `Directory' needs exactly one string "
+ "argument.");
+ return (-1);
+ }
+
+ /* Initialize `dir' */
+ dir = (fc_directory_conf_t *) malloc (sizeof (*dir));
+ if (dir == NULL)
+ {
+ ERROR ("filecount plugin: malloc failed.");
+ return (-1);
+ }
+ memset (dir, 0, sizeof (*dir));
+
+ dir->path = strdup (ci->values[0].value.string);
+ if (dir->path == NULL)
+ {
+ ERROR ("filecount plugin: strdup failed.");
+ return (-1);
+ }
+
+ fc_config_set_instance (dir, dir->path);
+
+ dir->name = NULL;
+ dir->mtime = 0;
+ dir->size = 0;
+
+ status = 0;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *option = ci->children + i;
+
+ if (strcasecmp ("Instance", option->key) == 0)
+ status = fc_config_add_dir_instance (dir, option);
+ else if (strcasecmp ("Name", option->key) == 0)
+ status = fc_config_add_dir_name (dir, option);
+ else if (strcasecmp ("MTime", option->key) == 0)
+ status = fc_config_add_dir_mtime (dir, option);
+ else if (strcasecmp ("Size", option->key) == 0)
+ status = fc_config_add_dir_size (dir, option);
+ else
+ {
+ WARNING ("filecount plugin: fc_config_add_dir: "
+ "Option `%s' not allowed here.", option->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (ci->children) */
+
+ if (status == 0)
+ {
+ fc_directory_conf_t **temp;
+
+ temp = (fc_directory_conf_t **) realloc (directories,
+ sizeof (*directories) * (directories_num + 1));
+ if (temp == NULL)
+ {
+ ERROR ("filecount plugin: realloc failed.");
+ status = -1;
+ }
+ else
+ {
+ directories = temp;
+ directories[directories_num] = dir;
+ directories_num++;
+ }
+ }
+
+ if (status != 0)
+ {
+ sfree (dir->name);
+ sfree (dir->instance);
+ sfree (dir->path);
+ sfree (dir);
+ return (-1);
+ }
+
+ return (0);
+} /* int fc_config_add_dir */
+
+static int fc_config (oconfig_item_t *ci)
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+ if (strcasecmp ("Directory", child->key) == 0)
+ fc_config_add_dir (child);
+ else
+ {
+ WARNING ("filecount plugin: Ignoring unknown config option `%s'.",
+ child->key);
+ }
+ } /* for (ci->children) */
+
+ return (0);
+} /* int fc_config */
+
+static int fc_init (void)
+{
+ if (directories_num < 1)
+ {
+ WARNING ("filecount plugin: No directories have been configured.");
+ return (-1);
+ }
+
+ return (0);
+} /* int fc_init */
+
+static int fc_read_dir_callback (const char *dirname, const char *filename,
+ void *user_data)
+{
+ fc_directory_conf_t *dir = user_data;
+ char abs_path[PATH_MAX];
+ struct stat statbuf;
+ int status;
+
+ if (dir == NULL)
+ return (-1);
+
+ ssnprintf (abs_path, sizeof (abs_path), "%s/%s", dirname, filename);
+
+ status = lstat (abs_path, &statbuf);
+ if (status != 0)
+ {
+ ERROR ("filecount plugin: stat (%s) failed.", abs_path);
+ return (-1);
+ }
+
+ if (S_ISDIR (statbuf.st_mode))
+ {
+ status = walk_directory (abs_path, fc_read_dir_callback, dir);
+ return (status);
+ }
+ else if (!S_ISREG (statbuf.st_mode))
+ {
+ return (0);
+ }
+
+ if (dir->name != NULL)
+ {
+ status = fnmatch (dir->name, filename, /* flags = */ 0);
+ if (status != 0)
+ return (0);
+ }
+
+ if (dir->mtime != 0)
+ {
+ time_t mtime = dir->now;
+
+ if (dir->mtime < 0)
+ mtime += dir->mtime;
+ else
+ mtime -= dir->mtime;
+
+ DEBUG ("filecount plugin: Only collecting files that were touched %s %u.",
+ (dir->mtime < 0) ? "after" : "before",
+ (unsigned int) mtime);
+
+ if (((dir->mtime < 0) && (statbuf.st_mtime < mtime))
+ || ((dir->mtime > 0) && (statbuf.st_mtime > mtime)))
+ return (0);
+ }
+
+ if (dir->size != 0)
+ {
+ off_t size;
+
+ if (dir->size < 0)
+ size = (off_t) ((-1) * dir->size);
+ else
+ size = (off_t) dir->size;
+
+ if (((dir->size < 0) && (statbuf.st_size > size))
+ || ((dir->size > 0) && (statbuf.st_size < size)))
+ return (0);
+ }
+
+ dir->files_num++;
+ dir->files_size += (uint64_t) statbuf.st_size;
+
+ return (0);
+} /* int fc_read_dir_callback */
+
+static int fc_read_dir (fc_directory_conf_t *dir)
+{
+ int status;
+
+ dir->files_num = 0;
+ dir->files_size = 0;
+
+ if (dir->mtime != 0)
+ dir->now = time (NULL);
+
+ status = walk_directory (dir->path, fc_read_dir_callback, dir);
+ if (status != 0)
+ {
+ WARNING ("filecount plugin: walk_directory (%s) failed.", dir->path);
+ return (-1);
+ }
+
+ fc_submit_dir (dir);
+
+ return (0);
+} /* int fc_read_dir */
+
+static int fc_read (void)
+{
+ size_t i;
+
+ for (i = 0; i < directories_num; i++)
+ fc_read_dir (directories[i]);
+
+ return (0);
+} /* int fc_read */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("filecount", fc_config);
+ plugin_register_init ("filecount", fc_init);
+ plugin_register_read ("filecount", fc_read);
+} /* void module_register */
+
+/*
+ * vim: set sw=2 sts=2 et :
+ */
{
int port = (int) (atof (value));
if ((port > 0) && (port <= 65535))
- snprintf (hddtemp_port, sizeof (hddtemp_port),
+ ssnprintf (hddtemp_port, sizeof (hddtemp_port),
"%i", port);
else
- strncpy (hddtemp_port, value, sizeof (hddtemp_port));
- hddtemp_port[sizeof (hddtemp_port) - 1] = '\0';
+ sstrncpy (hddtemp_port, value, sizeof (hddtemp_port));
}
else if (strcasecmp (key, "TranslateDevicename") == 0)
{
if ((ret = (char *) malloc (128 * sizeof (char))) == NULL)
return (NULL);
- if (snprintf (ret, 128, "%i-%i", list->major, list->minor) >= 128)
+ if (ssnprintf (ret, 128, "%i-%i", list->major, list->minor) >= 128)
{
free (ret);
return (NULL);
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "hddtemp", sizeof (vl.plugin));
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.type, "temperature", sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values ("temperature", &vl);
+ plugin_dispatch_values (&vl);
}
static int hddtemp_read (void)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "interface", sizeof (vl.plugin));
- 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)
/**
* collectd - src/ipmi.c
* Copyright (C) 2008 Florian octo Forster
+ * Copyright (C) 2008 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
*
* Authors:
* Florian octo Forster <octo at verplant.org>
+ * Peter Holik <peter at holik.at>
**/
#include "collectd.h"
struct c_ipmi_sensor_list_s
{
ipmi_sensor_id_t sensor_id;
+ char sensor_name[DATA_MAX_NAME_LEN];
+ char sensor_type[DATA_MAX_NAME_LEN];
+ int sensor_not_present;
c_ipmi_sensor_list_t *next;
};
static pthread_mutex_t sensor_list_lock = PTHREAD_MUTEX_INITIALIZER;
static c_ipmi_sensor_list_t *sensor_list = NULL;
+static int c_ipmi_init_in_progress = 0;
static int c_ipmi_active = 0;
static pthread_t thread_id = (pthread_t) 0;
static const char *config_keys[] =
{
"Sensor",
- "IgnoreSelected"
+ "IgnoreSelected",
+ "NotifySensorAdd",
+ "NotifySensorRemove",
+ "NotifySensorNotPresent"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
static ignorelist_t *ignorelist = NULL;
+static int c_ipmi_nofiy_add = 0;
+static int c_ipmi_nofiy_remove = 0;
+static int c_ipmi_nofiy_notpresent = 0;
+
/*
* Misc private functions
*/
value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- char sensor_name[IPMI_SENSOR_NAME_LEN];
- char *sensor_name_ptr;
- int sensor_type;
- const char *type;
-
- memset (sensor_name, 0, sizeof (sensor_name));
- ipmi_sensor_get_name (sensor, sensor_name, sizeof (sensor_name));
- sensor_name[sizeof (sensor_name) - 1] = 0;
-
- sensor_name_ptr = strstr (sensor_name, ").");
- if (sensor_name_ptr == NULL)
- sensor_name_ptr = sensor_name;
- else
- sensor_name_ptr += 2;
+ c_ipmi_sensor_list_t *list_item = (c_ipmi_sensor_list_t *)user_data;
if (err != 0)
{
- INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
- "because it failed with status %#x.",
- sensor_name_ptr, err);
- sensor_list_remove (sensor);
+ if ((err & 0xff) == IPMI_NOT_PRESENT_CC)
+ {
+ if (list_item->sensor_not_present == 0)
+ {
+ list_item->sensor_not_present = 1;
+
+ INFO ("ipmi plugin: sensor_read_handler: sensor %s "
+ "not present.", list_item->sensor_name);
+
+ if (c_ipmi_nofiy_notpresent)
+ {
+ notification_t n = { NOTIF_WARNING, time(NULL), "", "", "ipmi",
+ "", "", "", NULL };
+
+ sstrncpy (n.host, hostname_g, sizeof (n.host));
+ sstrncpy (n.type_instance, list_item->sensor_name,
+ sizeof (n.type_instance));
+ sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+ ssnprintf (n.message, sizeof (n.message),
+ "sensor %s not present", list_item->sensor_name);
+
+ plugin_dispatch_notification (&n);
+ }
+ }
+ }
+ else
+ {
+ INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
+ "because it failed with status %#x.",
+ list_item->sensor_name, err);
+ sensor_list_remove (sensor);
+ }
return;
}
+ else if (list_item->sensor_not_present == 1)
+ {
+ list_item->sensor_not_present = 0;
+
+ INFO ("ipmi plugin: sensor_read_handler: sensor %s present.",
+ list_item->sensor_name);
+
+ if (c_ipmi_nofiy_notpresent)
+ {
+ notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+ "", "", "", NULL };
+
+ sstrncpy (n.host, hostname_g, sizeof (n.host));
+ sstrncpy (n.type_instance, list_item->sensor_name,
+ sizeof (n.type_instance));
+ sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+ ssnprintf (n.message, sizeof (n.message),
+ "sensor %s present", list_item->sensor_name);
+
+ plugin_dispatch_notification (&n);
+ }
+ }
if (value_present != IPMI_BOTH_VALUES_PRESENT)
{
INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
"because it provides %s. If you need this sensor, "
"please file a bug report.",
- sensor_name_ptr,
+ list_item->sensor_name,
(value_present == IPMI_RAW_VALUE_PRESENT)
? "only the raw value"
: "no value");
return;
}
- /* Both `ignorelist' and `plugin_instance' may be NULL. */
- if (ignorelist_match (ignorelist, sensor_name_ptr) != 0)
+ values[0].gauge = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "ipmi", sizeof (vl.plugin));
+ sstrncpy (vl.type, list_item->sensor_type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, list_item->sensor_name, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+} /* void sensor_read_handler */
+
+static int sensor_list_add (ipmi_sensor_t *sensor)
+{
+ ipmi_sensor_id_t sensor_id;
+ c_ipmi_sensor_list_t *list_item;
+ c_ipmi_sensor_list_t *list_prev;
+
+ char sensor_name[DATA_MAX_NAME_LEN];
+ char *sensor_name_ptr;
+ int sensor_type, len;
+ const char *type;
+ ipmi_entity_t *ent = ipmi_sensor_get_entity(sensor);
+
+ sensor_id = ipmi_sensor_convert_to_id (sensor);
+
+ memset (sensor_name, 0, sizeof (sensor_name));
+ ipmi_sensor_get_name (sensor, sensor_name, sizeof (sensor_name));
+ sensor_name[sizeof (sensor_name) - 1] = 0;
+
+ len = DATA_MAX_NAME_LEN - strlen(sensor_name);
+ strncat(sensor_name, " ", len--);
+ strncat(sensor_name, ipmi_entity_get_entity_id_string(ent), len);
+
+ sensor_name_ptr = strstr (sensor_name, ").");
+ if (sensor_name_ptr == NULL)
+ sensor_name_ptr = sensor_name;
+ else
{
- sensor_list_remove (sensor);
- return;
+ char *sensor_name_ptr_id = strstr (sensor_name, "(");
+
+ sensor_name_ptr += 2;
+ len = DATA_MAX_NAME_LEN - strlen(sensor_name);
+ strncat(sensor_name, " ", len--);
+ strncat(sensor_name, sensor_name_ptr_id,
+ MIN(sensor_name_ptr - sensor_name_ptr_id - 1, len));
}
+ /* Both `ignorelist' and `plugin_instance' may be NULL. */
+ if (ignorelist_match (ignorelist, sensor_name_ptr) != 0)
+ return (0);
+
/* FIXME: Use rate unit or base unit to scale the value */
sensor_type = ipmi_sensor_get_sensor_type (sensor);
default:
{
const char *sensor_type_str;
-
+
sensor_type_str = ipmi_sensor_get_sensor_type_string (sensor);
- INFO ("ipmi plugin: sensor_read_handler: Removing sensor %s, "
+ INFO ("ipmi plugin: sensor_list_add: Ignore sensor %s, "
"because I don't know how to handle its type (%#x, %s). "
"If you need this sensor, please file a bug report.",
sensor_name_ptr, sensor_type, sensor_type_str);
- sensor_list_remove (sensor);
- return;
+ return (-1);
}
} /* switch (sensor_type) */
- values[0].gauge = value;
-
- vl.values = values;
- vl.values_len = 1;
- vl.time = time (NULL);
-
- sstrncpy (vl.host, hostname_g, sizeof (vl.host));
- sstrncpy (vl.plugin, "ipmi", sizeof (vl.plugin));
- sstrncpy (vl.type_instance, sensor_name_ptr, sizeof (vl.type_instance));
-
- plugin_dispatch_values (type, &vl);
-} /* void sensor_read_handler */
-
-static int sensor_list_add (ipmi_sensor_t *sensor)
-{
- ipmi_sensor_id_t sensor_id;
- c_ipmi_sensor_list_t *list_item;
- c_ipmi_sensor_list_t *list_prev;
-
- sensor_id = ipmi_sensor_convert_to_id (sensor);
-
pthread_mutex_lock (&sensor_list_lock);
list_prev = NULL;
else
sensor_list = list_item;
+ sstrncpy (list_item->sensor_name, sensor_name_ptr,
+ sizeof (list_item->sensor_name));
+ sstrncpy (list_item->sensor_type, type, sizeof (list_item->sensor_type));
+
pthread_mutex_unlock (&sensor_list_lock);
+ if (c_ipmi_nofiy_add && (c_ipmi_init_in_progress == 0))
+ {
+ notification_t n = { NOTIF_OKAY, time(NULL), "", "", "ipmi",
+ "", "", "", NULL };
+
+ sstrncpy (n.host, hostname_g, sizeof (n.host));
+ sstrncpy (n.type_instance, list_item->sensor_name,
+ sizeof (n.type_instance));
+ sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+ ssnprintf (n.message, sizeof (n.message),
+ "sensor %s added", list_item->sensor_name);
+
+ plugin_dispatch_notification (&n);
+ }
+
return (0);
} /* int sensor_list_add */
pthread_mutex_unlock (&sensor_list_lock);
+ if (c_ipmi_nofiy_remove && c_ipmi_active)
+ {
+ notification_t n = { NOTIF_WARNING, time(NULL), "", "",
+ "ipmi", "", "", "", NULL };
+
+ sstrncpy (n.host, hostname_g, sizeof (n.host));
+ sstrncpy (n.type_instance, list_item->sensor_name,
+ sizeof (n.type_instance));
+ sstrncpy (n.type, list_item->sensor_type, sizeof (n.type));
+ ssnprintf (n.message, sizeof (n.message),
+ "sensor %s removed", list_item->sensor_name);
+
+ plugin_dispatch_notification (&n);
+ }
+
free (list_item);
return (0);
} /* int sensor_list_remove */
list_item = list_item->next)
{
ipmi_sensor_id_get_reading (list_item->sensor_id,
- sensor_read_handler, /* user data = */ NULL);
+ sensor_read_handler, /* user data = */ list_item);
} /* for (list_item) */
pthread_mutex_unlock (&sensor_list_lock);
{
int invert = 1;
if ((strcasecmp ("True", value) == 0)
- || (strcasecmp ("Yes", value) == 0)
- || (strcasecmp ("On", value) == 0))
+ || (strcasecmp ("Yes", value) == 0)
+ || (strcasecmp ("On", value) == 0))
invert = 0;
ignorelist_set_invert (ignorelist, invert);
}
+ else if (strcasecmp ("NotifySensorAdd", key) == 0)
+ {
+ if ((strcasecmp ("True", value) == 0)
+ || (strcasecmp ("Yes", value) == 0)
+ || (strcasecmp ("On", value) == 0))
+ c_ipmi_nofiy_add = 1;
+ }
+ else if (strcasecmp ("NotifySensorRemove", key) == 0)
+ {
+ if ((strcasecmp ("True", value) == 0)
+ || (strcasecmp ("Yes", value) == 0)
+ || (strcasecmp ("On", value) == 0))
+ c_ipmi_nofiy_remove = 1;
+ }
+ else if (strcasecmp ("NotifySensorNotPresent", key) == 0)
+ {
+ if ((strcasecmp ("True", value) == 0)
+ || (strcasecmp ("Yes", value) == 0)
+ || (strcasecmp ("On", value) == 0))
+ c_ipmi_nofiy_notpresent = 1;
+ }
else
{
return (-1);
{
int status;
+ /* Don't send `ADD' notifications during startup (~ 1 minute) */
+ c_ipmi_init_in_progress = 1 + (60 / interval_g);
+
c_ipmi_active = 1;
status = pthread_create (&thread_id, /* attr = */ NULL, thread_main,
}
sensor_list_read_all ();
-
+
+ if (c_ipmi_init_in_progress > 0)
+ c_ipmi_init_in_progress--;
+ else
+ c_ipmi_init_in_progress = 0;
+
return (0);
} /* int c_ipmi_read */
table = fields[0];
chain = fields[1];
- table_len = strlen (table);
- if ((unsigned int)table_len >= sizeof(temp.table))
+ table_len = strlen (table) + 1;
+ if ((unsigned int)table_len > sizeof(temp.table))
{
ERROR ("Table `%s' too long.", table);
free (value_copy);
return (1);
}
- strncpy (temp.table, table, table_len);
- temp.table[table_len] = '\0';
+ sstrncpy (temp.table, table, table_len);
- chain_len = strlen (chain);
- if ((unsigned int)chain_len >= sizeof(temp.chain))
+ chain_len = strlen (chain) + 1;
+ if ((unsigned int)chain_len > sizeof(temp.chain))
{
ERROR ("Chain `%s' too long.", chain);
free (value_copy);
return (1);
}
- strncpy (temp.chain, chain, chain_len);
- temp.chain[chain_len] = '\0';
+ sstrncpy (temp.chain, chain, chain_len);
if (fields_num >= 3)
{
}
if (fields_num >= 4)
- strncpy (temp.name, fields[3], sizeof (temp.name) - 1);
+ sstrncpy (temp.name, fields[3], sizeof (temp.name));
free (value_copy);
value_copy = NULL;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "iptables", sizeof (vl.plugin));
- status = snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+ status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
"%s-%s", chain->table, chain->chain);
if ((status < 1) || ((unsigned int)status >= sizeof (vl.plugin_instance)))
return (0);
if (chain->name[0] != '\0')
{
- strncpy (vl.type_instance, chain->name, sizeof (vl.type_instance));
+ sstrncpy (vl.type_instance, chain->name, sizeof (vl.type_instance));
}
else
{
if (chain->rule_type == RTYPE_NUM)
- snprintf (vl.type_instance, sizeof (vl.type_instance),
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance),
"%i", chain->rule.num);
else
- strncpy (vl.type_instance, (char *) match->data,
+ sstrncpy (vl.type_instance, (char *) match->data,
sizeof (vl.type_instance));
}
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type));
values[0].counter = (counter_t) entry->counters.bcnt;
- plugin_dispatch_values ("ipt_bytes", &vl);
+ plugin_dispatch_values (&vl);
+ sstrncpy (vl.type, "ipt_packets", sizeof (vl.type));
values[0].counter = (counter_t) entry->counters.pcnt;
- plugin_dispatch_values ("ipt_packets", &vl);
+ plugin_dispatch_values (&vl);
return (0);
} /* void submit_match */
/* inet_ntoa() returns a pointer to a statically allocated buffer
* I hope non-glibc systems behave the same */
- len = snprintf (pi, size, "%s_%s%u", inet_ntoa (addr),
+ len = ssnprintf (pi, size, "%s_%s%u", inet_ntoa (addr),
(se->protocol == IPPROTO_TCP) ? "TCP" : "UDP",
ntohs (se->port));
/* inet_ntoa() returns a pointer to a statically allocated buffer
* I hope non-glibc systems behave the same */
- len = snprintf (ti, size, "%s_%u", inet_ntoa (addr),
+ len = ssnprintf (ti, size, "%s_%u", inet_ntoa (addr),
ntohs (de->port));
if ((0 > len) || (size <= len)) {
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
- sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total", sizeof (vl.type_instance));
+ sstrncpy (vl.type, "connections", sizeof (vl.type));
+ sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total",
+ sizeof (vl.type_instance));
- plugin_dispatch_values ("connections", &vl);
+ plugin_dispatch_values (&vl);
return;
} /* cipvs_submit_connections */
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "ipvs", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, pi, sizeof (vl.plugin_instance));
- sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total", sizeof (vl.type_instance));
+ sstrncpy (vl.type, t, sizeof (vl.type));
+ sstrncpy (vl.type_instance, (NULL != ti) ? ti : "total",
+ sizeof (vl.type_instance));
- plugin_dispatch_values (t, &vl);
+ plugin_dispatch_values (&vl);
return;
} /* cipvs_submit_if */
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "irq", sizeof (vl.plugin));
+ sstrncpy (vl.type, "irq", sizeof (vl.type));
- status = snprintf (vl.type_instance, sizeof (vl.type_instance),
+ status = ssnprintf (vl.type_instance, sizeof (vl.type_instance),
"%u", irq);
if ((status < 1) || ((unsigned int)status >= sizeof (vl.type_instance)))
return;
- plugin_dispatch_values ("irq", &vl);
+ plugin_dispatch_values (&vl);
} /* void irq_submit */
static int irq_read (void)
libiptc_la_CFLAGS = -DIPTABLES_VERSION=\"1.4.0\" -I$(KERNEL_DIR)/include
libiptc_la_SOURCES = libip4tc.c libip6tc.c \
- ipt_kernel_headers.h libip6tc.h libiptc.h linux_list.h
+ ipt_kernel_headers.h libip6tc.h libiptc.h linux_list.h \
+ xtables.h libxtc.h
/**
* oconfig - src/scanner.l
* Copyright (C) 2007 Florian octo Forster <octo at verplant.org>
+ * Copyright (C) 2008 Sebastian tokkee Harl <sh at tokkee.org>
*
* 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 "oconfig.h"
#include "aux_types.h"
#include "parser.h"
+
+/* multiline string buffer */
+static char *ml_buffer = NULL;
+static int ml_pos = 0;
+static int ml_len = 0;
+
+#define ml_free (ml_len - ml_pos)
+
+static void ml_append (char *);
+
+#ifdef yyterminate
+# undef yyterminate
+#endif
+#define yyterminate() \
+ do { free (ml_buffer); ml_buffer = NULL; ml_pos = 0; ml_len = 0; \
+ return YY_NULL; } while (0)
%}
%option yylineno
%option noyywrap
+%x ML
WHITE_SPACE [\ \t\b]
-QUOTED_STRING \"([^\\"]+|\\.)*\"
+NON_WHITE_SPACE [^\ \t\b]
+EOL (\r\n|\n)
+QUOTED_STRING ([^\\"]+|\\.)*
UNQUOTED_STRING [0-9A-Za-z_]+
HEX_NUMBER 0[xX][0-9a-fA-F]+
OCT_NUMBER 0[0-7]+
{WHITE_SPACE} |
{COMMENT} {/* ignore */}
-\n {return (EOL);}
+\\{EOL} {/* continue line */}
+
+{EOL} {return (EOL);}
"/" {return (SLASH);}
"<" {return (OPENBRAC);}
">" {return (CLOSEBRAC);}
{NUMBER} {yylval.number = strtod (yytext, NULL); return (NUMBER);}
-{QUOTED_STRING} {yylval.string = yytext; return (QUOTED_STRING);}
+\"{QUOTED_STRING}\" {yylval.string = yytext; return (QUOTED_STRING);}
{UNQUOTED_STRING} {yylval.string = yytext; return (UNQUOTED_STRING);}
+
+\"{QUOTED_STRING}\\{EOL} {
+ int len = strlen (yytext);
+
+ ml_pos = 0;
+
+ /* remove "\\<EOL>" */
+ if ('\r' == yytext[len - 2])
+ len -= 3;
+ else
+ len -= 2;
+ yytext[len] = '\0';
+
+ ml_append (yytext);
+ BEGIN (ML);
+}
+<ML>^{WHITE_SPACE}+ {/* remove leading white-space */}
+<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\\{EOL} {
+ int len = strlen (yytext);
+
+ /* remove "\\<EOL>" */
+ if ('\r' == yytext[len - 2])
+ len -= 3;
+ else
+ len -= 2;
+ yytext[len] = '\0';
+
+ ml_append(yytext);
+}
+<ML>{NON_WHITE_SPACE}{QUOTED_STRING}\" {
+ ml_append(yytext);
+ yylval.string = ml_buffer;
+
+ BEGIN (INITIAL);
+ return (QUOTED_STRING);
+}
%%
+static void ml_append (char *string)
+{
+ int len = strlen (string);
+ int s;
+
+ if (ml_free <= len) {
+ ml_len += len - ml_free + 1;
+ ml_buffer = (char *)realloc (ml_buffer, ml_len);
+ if (NULL == ml_buffer)
+ YY_FATAL_ERROR ("out of dynamic memory in ml_append");
+ }
+
+ s = snprintf (ml_buffer + ml_pos, ml_free, "%s", string);
+ if ((0 > s) || (ml_free <= s))
+ YY_FATAL_ERROR ("failed to write to multiline buffer");
+
+ ml_pos += s;
+ return;
+} /* ml_append */
+
ERROR ("libvirt plugin: malloc failed.");
return 0;
}
- snprintf (name, n, "%s:%s", domname, devpath);
+ ssnprintf (name, n, "%s:%s", domname, devpath);
r = ignorelist_match (il, name);
free (name);
return r;
vl->time = t;
vl->interval = interval_g;
- strncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
- vl->plugin[sizeof (vl->plugin) - 1] = '\0';
+ sstrncpy (vl->plugin, "libvirt", sizeof (vl->plugin));
vl->host[0] = '\0';
host_ptr = vl->host;
vl.values = values;
vl.values_len = 1;
- plugin_dispatch_values (type, &vl);
+ sstrncpy (vl.type, type, sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
}
static void
vl.values = values;
vl.values_len = 1;
- snprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%d", vcpu_nr);
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
}
static void
vl.values = values;
vl.values_len = 2;
- strncpy (vl.type_instance, devname, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, devname, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void submit_counter2 */
static int
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "load", sizeof (vl.plugin));
+ sstrncpy (vl.type, "load", sizeof (vl.type));
- plugin_dispatch_values ("load", &vl);
+ plugin_dispatch_values (&vl);
}
static int load_read (void)
int buf_len = sizeof (buf);
int status;
- status = snprintf (buf_ptr, buf_len, "Notification: severity = %s",
+ status = ssnprintf (buf_ptr, buf_len, "Notification: severity = %s",
(n->severity == NOTIF_FAILURE) ? "FAILURE"
: ((n->severity == NOTIF_WARNING) ? "WARNING"
: ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN")));
#define APPEND(bufptr, buflen, key, value) \
if ((buflen > 0) && (strlen (value) > 0)) { \
- int status = snprintf (bufptr, buflen, ", %s = %s", key, value); \
+ int status = ssnprintf (bufptr, buflen, ", %s = %s", key, value); \
if (status > 0) { \
bufptr += status; \
buflen -= status; \
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "mbmon", sizeof (vl.plugin));
- 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 mbmon_submit */
/* Trim trailing whitespace from a string. */
} else if (strcasecmp (key, "Port") == 0) {
int port = (int) (atof (value));
if ((port > 0) && (port <= 65535)) {
- snprintf (memcached_port, sizeof (memcached_port), "%i", port);
+ ssnprintf (memcached_port, sizeof (memcached_port), "%i", port);
} else {
- strncpy (memcached_port, value, sizeof (memcached_port));
+ sstrncpy (memcached_port, value, sizeof (memcached_port));
}
- memcached_port[sizeof (memcached_port) - 1] = '\0';
} else {
return -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));
if (type_inst != NULL)
- {
- strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void memcached_submit_cmd */
/* }}} */
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));
if (type_inst != NULL)
- {
- strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void memcached_submit_cmd */
/* }}} */
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));
if (type_inst != NULL)
- {
- strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
}
/* }}} */
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));
if (type_inst != NULL)
- {
- strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
}
/* }}} */
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "memory", sizeof (vl.plugin));
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ sstrncpy (vl.type, "memory", sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values ("memory", &vl);
+ plugin_dispatch_values (&vl);
}
static int memory_read (void)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "multimeter", sizeof (vl.plugin));
+ sstrncpy (vl.type, "multimeter", sizeof (vl.type));
- plugin_dispatch_values ("multimeter", &vl);
+ plugin_dispatch_values (&vl);
}
static int multimeter_read (void)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
- 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 counter_submit */
static void qcache_submit (counter_t hits, counter_t inserts,
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
+ sstrncpy (vl.type, "mysql_qcache", sizeof (vl.type));
- plugin_dispatch_values ("mysql_qcache", &vl);
+ plugin_dispatch_values (&vl);
} /* void qcache_submit */
static void threads_submit (gauge_t running, gauge_t connected, gauge_t cached,
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
+ sstrncpy (vl.type, "mysql_threads", sizeof (vl.type));
- plugin_dispatch_values ("mysql_threads", &vl);
+ plugin_dispatch_values (&vl);
} /* void threads_submit */
static void traffic_submit (counter_t rx, counter_t tx)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "mysql", sizeof (vl.plugin));
+ sstrncpy (vl.type, "mysql_octets", sizeof (vl.type));
- plugin_dispatch_values ("mysql_octets", &vl);
+ plugin_dispatch_values (&vl);
} /* void traffic_submit */
static int mysql_read (void)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+ sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void submit_one */
static void submit_two (const char *dev, const char *type,
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "netlink", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+ sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void submit_two */
static int link_filter (const struct sockaddr_nl *sa,
- const struct nlmsghdr *nmh, void *args)
+ struct nlmsghdr *nmh, void *args)
{
struct ifinfomsg *msg;
int msg_len;
} /* int link_filter */
static int qos_filter (const struct sockaddr_nl *sa,
- const struct nlmsghdr *nmh, void *args)
+ struct nlmsghdr *nmh, void *args)
{
struct tcmsg *msg;
int msg_len;
if (strcmp (tc_type, "filter") == 0)
numberic_id = msg->tcm_parent;
- snprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x",
+ ssnprintf (tc_inst, sizeof (tc_inst), "%s-%x:%x",
(const char *) RTA_DATA (attrs[TCA_KIND]),
numberic_id >> 16,
numberic_id & 0x0000FFFF);
- tc_inst[sizeof (tc_inst) - 1] = '\0';
}
DEBUG ("netlink plugin: qos_filter: got %s for %s (%i).",
struct gnet_stats_basic bs;
char type_instance[DATA_MAX_NAME_LEN];
- snprintf (type_instance, sizeof (type_instance), "%s-%s",
+ ssnprintf (type_instance, sizeof (type_instance), "%s-%s",
tc_type, tc_inst);
- type_instance[sizeof (type_instance) - 1] = '\0';
memset (&bs, '\0', sizeof (bs));
memcpy (&bs, RTA_DATA (attrs_stats[TCA_STATS_BASIC]),
struct tc_stats ts;
char type_instance[DATA_MAX_NAME_LEN];
- snprintf (type_instance, sizeof (type_instance), "%s-%s",
+ ssnprintf (type_instance, sizeof (type_instance), "%s-%s",
tc_type, tc_inst);
- type_instance[sizeof (type_instance) - 1] = '\0';
memset(&ts, '\0', sizeof (ts));
memcpy(&ts, RTA_DATA (attrs[TCA_STATS]),
return (0);
} /* int cache_flush */
-static int cache_check (const char *type, const value_list_t *vl)
+static int cache_check (const value_list_t *vl)
{
char key[1024];
time_t *value = NULL;
return (-1);
if (format_name (key, sizeof (key), vl->host, vl->plugin,
- vl->plugin_instance, type, vl->type_instance))
+ vl->plugin_instance, vl->type, vl->type_instance))
return (-1);
pthread_mutex_lock (&cache_lock);
int status;
value_list_t vl = VALUE_LIST_INIT;
- char type[DATA_MAX_NAME_LEN];
notification_t n;
DEBUG ("network plugin: parse_packet: buffer = %p; buffer_len = %i;",
buffer, buffer_len);
memset (&vl, '\0', sizeof (vl));
- memset (&type, '\0', sizeof (type));
memset (&n, '\0', sizeof (n));
status = 0;
if ((vl.time > 0)
&& (strlen (vl.host) > 0)
&& (strlen (vl.plugin) > 0)
- && (strlen (type) > 0)
- && (cache_check (type, &vl) == 0))
+ && (strlen (vl.type) > 0)
+ && (cache_check (&vl) == 0))
{
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
}
else
{
else if (pkg_type == TYPE_TYPE)
{
status = parse_part_string (&buffer, &buffer_len,
- type, sizeof (type));
+ vl.type, sizeof (vl.type));
if (status == 0)
- sstrncpy (n.type, type, sizeof (n.type));
+ sstrncpy (n.type, vl.type, sizeof (n.type));
}
else if (pkg_type == TYPE_TYPE_INSTANCE)
{
sstrncpy (vl_def->plugin_instance, vl->plugin_instance, sizeof (vl_def->plugin_instance));
}
- if (strcmp (type_def, ds->type) != 0)
+ if (strcmp (type_def, vl->type) != 0)
{
if (write_part_string (&buffer, &buffer_size, TYPE_TYPE,
- ds->type, strlen (ds->type)) != 0)
+ vl->type, strlen (vl->type)) != 0)
return (-1);
- sstrncpy (type_def, ds->type, sizeof (type_def));
+ sstrncpy (type_def, vl->type, sizeof (type_def));
}
if (strcmp (vl_def->type_instance, vl->type_instance) != 0)
/* If the value is already in the cache, we have received it via the
* network. We write it again if forwarding is activated. It's then in
* the cache and should we receive it again we will ignore it. */
- status = cache_check (ds->type, vl);
+ status = cache_check (vl);
if ((network_config_forward == 0)
&& (status != 0))
return (0);
return (0);
} /* int network_init */
-static int network_flush (int timeout)
+/*
+ * The flush option of the network plugin cannot flush individual identifiers.
+ * All the values are added to a buffer and sent when the buffer is full, the
+ * requested value may or may not be in there, it's not worth finding out. We
+ * just send the buffer if `flush' is called - if the requested value was in
+ * there, good. If not, well, then there is nothing to flush.. -octo
+ */
+static int network_flush (int timeout, const char *identifier)
{
pthread_mutex_lock (&send_buffer_lock);
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, plugin_instance,
+ sstrncpy (vl.plugin_instance, plugin_instance,
sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
for (i = 0; i < len; i++)
{
values[0].counter = val[i];
- strncpy (vl.type_instance, names[i],
+ sstrncpy (vl.type_instance, names[i],
sizeof (vl.type_instance));
DEBUG ("%s-%s/nfs_procedure-%s = %llu",
vl.plugin, vl.plugin_instance,
vl.type_instance, val[i]);
- plugin_dispatch_values ("nfs_procedure", &vl);
+ plugin_dispatch_values (&vl);
}
} /* void nfs_procedures_submit */
continue;
}
- snprintf (plugin_instance, sizeof (plugin_instance),
+ ssnprintf (plugin_instance, sizeof (plugin_instance),
"v2%s", inst);
- plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
if (values == NULL)
continue;
}
- snprintf (plugin_instance, sizeof (plugin_instance),
+ ssnprintf (plugin_instance, sizeof (plugin_instance),
"v3%s", inst);
- plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
if (values == NULL)
if (user != NULL)
{
- if (snprintf (credentials, 1024, "%s:%s", user, pass == NULL ? "" : pass) >= 1024)
+ if (ssnprintf (credentials, sizeof (credentials),
+ "%s:%s", user, pass == NULL ? "" : pass) >= sizeof (credentials))
{
ERROR ("nginx plugin: Credentials would have been truncated.");
return (-1);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "nginx", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (inst != NULL)
- {
- strncpy (vl.type_instance, inst, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
+ sstrncpy (vl.type_instance, inst, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void submit */
static int nginx_read (void)
--- /dev/null
+/**
+ * collectd - src/notify_desktop.c
+ * Copyright (C) 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Sebastian Harl <sh at tokkee.org>
+ **/
+
+/*
+ * This plugin sends desktop notifications to a notification daemon.
+ */
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+
+#include <glib.h>
+#include <libnotify/notify.h>
+
+#define log_info(...) INFO ("notify_desktop: " __VA_ARGS__)
+#define log_warn(...) WARNING ("notify_desktop: " __VA_ARGS__)
+#define log_err(...) ERROR ("notify_desktop: " __VA_ARGS__)
+
+#define DEFAULT_TIMEOUT 5000
+
+static int okay_timeout = DEFAULT_TIMEOUT;
+static int warn_timeout = DEFAULT_TIMEOUT;
+static int fail_timeout = DEFAULT_TIMEOUT;
+
+static int set_timeout (oconfig_item_t *ci, int *timeout)
+{
+ if ((0 != ci->children_num) || (1 != ci->values_num)
+ || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) {
+ log_err ("%s expects a single number argument.", ci->key);
+ return 1;
+ }
+
+ *timeout = (int)ci->values[0].value.number;
+ if (0 > *timeout)
+ *timeout = DEFAULT_TIMEOUT;
+ return 0;
+} /* set_timeout */
+
+static int c_notify_config (oconfig_item_t *ci)
+{
+ int i = 0;
+
+ for (i = 0; i < ci->children_num; ++i) {
+ oconfig_item_t *c = ci->children + i;
+
+ if (0 == strcasecmp (c->key, "OkayTimeout"))
+ set_timeout (c, &okay_timeout);
+ else if (0 == strcasecmp (c->key, "WarningTimeout"))
+ set_timeout (c, &warn_timeout);
+ else if (0 == strcasecmp (c->key, "FailureTimeout"))
+ set_timeout (c, &fail_timeout);
+ }
+ return 0;
+} /* c_notify_config */
+
+static int c_notify (const notification_t *n)
+{
+ NotifyNotification *notification = NULL;
+ NotifyUrgency urgency = NOTIFY_URGENCY_LOW;
+ int timeout = okay_timeout;
+
+ char summary[1024];
+
+ if (NOTIF_WARNING == n->severity) {
+ urgency = NOTIFY_URGENCY_NORMAL;
+ timeout = warn_timeout;
+ }
+ else if (NOTIF_FAILURE == n->severity) {
+ urgency = NOTIFY_URGENCY_CRITICAL;
+ timeout = fail_timeout;
+ }
+
+ ssnprintf (summary, sizeof (summary), "collectd %s notification",
+ (NOTIF_FAILURE == n->severity) ? "FAILURE"
+ : (NOTIF_WARNING == n->severity) ? "WARNING"
+ : (NOTIF_OKAY == n->severity) ? "OKAY" : "UNKNOWN");
+
+ notification = notify_notification_new (summary, n->message, NULL, NULL);
+ if (NULL == notification) {
+ log_err ("Failed to create a new notification.");
+ return -1;
+ }
+
+ notify_notification_set_urgency (notification, urgency);
+ notify_notification_set_timeout (notification, timeout);
+
+ if (! notify_notification_show (notification, NULL))
+ log_err ("Failed to display notification.");
+
+ g_object_unref (G_OBJECT (notification));
+ return 0;
+} /* c_notify */
+
+static int c_notify_shutdown (void)
+{
+ plugin_unregister_init ("notify_desktop");
+ plugin_unregister_notification ("notify_desktop");
+ plugin_unregister_shutdown ("notify_desktop");
+
+ if (notify_is_initted ())
+ notify_uninit ();
+ return 0;
+} /* c_notify_shutdown */
+
+static int c_notify_init (void)
+{
+ char *name = NULL;
+ char *vendor = NULL;
+ char *version = NULL;
+ char *spec_version = NULL;
+
+ if (! notify_init (PACKAGE_STRING)) {
+ log_err ("Failed to initialize libnotify.");
+ return -1;
+ }
+
+ if (! notify_get_server_info (&name, &vendor, &version, &spec_version))
+ log_warn ("Failed to get the notification server info. "
+ "Check if you have a notification daemon running.");
+ else {
+ log_info ("Found notification daemon: %s (%s) %s (spec version %s)",
+ name, vendor, version, spec_version);
+ free (name);
+ free (vendor);
+ free (version);
+ free (spec_version);
+ }
+
+ plugin_register_notification ("notify_desktop", c_notify);
+ plugin_register_shutdown ("notify_desktop", c_notify_shutdown);
+ return 0;
+} /* c_notify_init */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("notify_desktop", c_notify_config);
+ plugin_register_init ("notify_desktop", c_notify_init);
+ return;
+} /* module_register */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
--- /dev/null
+/**
+ * collectd - src/notify_email.c
+ * Copyright (C) 2008 Oleg King
+ *
+ * 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:
+ * Oleg King <king2 at kaluga.ru>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <auth-client.h>
+#include <libesmtp.h>
+
+#define MAXSTRING 256
+
+static const char *config_keys[] =
+{
+ "SMTPServer",
+ "SMTPPort",
+ "SMTPUser",
+ "SMTPPassword",
+ "From",
+ "Recipient",
+ "Subject"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static char **recipients;
+static int recipients_len = 0;
+
+static smtp_session_t session;
+static smtp_message_t message;
+static auth_context_t authctx = NULL;
+
+static int smtp_port = 25;
+static char *smtp_host = NULL;
+static char *smtp_user = NULL;
+static char *smtp_password = NULL;
+static char *email_from = NULL;
+static char *email_subject = NULL;
+
+#define DEFAULT_SMTP_HOST "localhost"
+#define DEFAULT_SMTP_FROM "root@localhost"
+#define DEFAULT_SMTP_SUBJECT "Collectd notify: %s@%s"
+
+/* Callback to get username and password */
+static int authinteract (auth_client_request_t request, char **result,
+ int fields, void *arg)
+{
+ int i;
+ for (i = 0; i < fields; i++)
+ {
+ if (request[i].flags & AUTH_USER)
+ result[i] = smtp_user;
+ else if (request[i].flags & AUTH_PASS)
+ result[i] = smtp_password;
+ else
+ return 0;
+ }
+ return 1;
+} /* int authinteract */
+
+/* Callback to print the recipient status */
+static void print_recipient_status (smtp_recipient_t recipient,
+ const char *mailbox, void *arg)
+{
+ const smtp_status_t *status;
+
+ status = smtp_recipient_status (recipient);
+ if (status->text[strlen(status->text) - 2] == '\r')
+ status->text[strlen(status->text) - 2] = 0;
+ INFO ("notify_email: notify sent to %s: %d %s", mailbox, status->code,
+ status->text);
+} /* void print_recipient_status */
+
+/* Callback to monitor SMTP activity */
+static void monitor_cb (const char *buf, int buflen, int writing, void *arg)
+{
+ char log_str[MAXSTRING];
+
+ sstrncpy (log_str, buf, sizeof (log_str));
+ if (buflen > 2)
+ log_str[buflen - 2] = 0; /* replace \n with \0 */
+
+ if (writing == SMTP_CB_HEADERS) {
+ DEBUG ("notify_email plugin: SMTP --- H: %s", log_str);
+ return;
+ }
+ DEBUG (writing
+ ? "notify_email plugin: SMTP >>> C: %s"
+ : "notify_email plugin: SMTP <<< S: %s",
+ log_str);
+} /* void monitor_cb */
+
+static int notify_email_init (void)
+{
+ char server[MAXSTRING];
+
+ auth_client_init();
+ if (!(session = smtp_create_session ())) {
+ ERROR ("notify_email plugin: cannot create SMTP session");
+ return (-1);
+ }
+
+ smtp_set_monitorcb (session, monitor_cb, NULL, 1);
+ smtp_set_hostname (session, hostname_g);
+ ssnprintf(server, sizeof (server), "%s:%i",
+ (smtp_host == NULL) ? DEFAULT_SMTP_HOST : smtp_host,
+ smtp_port);
+ smtp_set_server (session, server);
+
+ if (smtp_user && smtp_password) {
+ authctx = auth_create_context ();
+ auth_set_mechanism_flags (authctx, AUTH_PLUGIN_PLAIN, 0);
+ auth_set_interact_cb (authctx, authinteract, NULL);
+ }
+
+ if ( !smtp_auth_set_context (session, authctx)) {
+ ERROR ("notify_email plugin: cannot set SMTP auth context");
+ return (-1);
+ }
+
+ return (0);
+} /* int notify_email_init */
+
+static int notify_email_shutdown (void)
+{
+ smtp_destroy_session (session);
+ auth_destroy_context (authctx);
+ auth_client_exit();
+ return (0);
+} /* int notify_email_shutdown */
+
+static int notify_email_config (const char *key, const char *value)
+{
+ if (strcasecmp (key, "Recipient") == 0)
+ {
+ char **tmp;
+
+ tmp = (char **) realloc ((void *) recipients, (recipients_len + 1) * sizeof (char *));
+ if (tmp == NULL) {
+ ERROR ("notify_email: realloc failed.");
+ return (-1);
+ }
+
+ recipients = tmp;
+ recipients[recipients_len] = strdup (value);
+ if (recipients[recipients_len] == NULL) {
+ ERROR ("notify_email: strdup failed.");
+ return (-1);
+ }
+ recipients_len++;
+ }
+ else if (0 == strcasecmp (key, "SMTPServer")) {
+ sfree (smtp_host);
+ smtp_host = strdup (value);
+ }
+ else if (0 == strcasecmp (key, "SMTPPort")) {
+ int port_tmp = atoi (value);
+ if (port_tmp < 1 || port_tmp > 65535)
+ {
+ WARNING ("notify_email plugin: Invalid SMTP port: %i", port_tmp);
+ return (1);
+ }
+ smtp_port = port_tmp;
+ }
+ else if (0 == strcasecmp (key, "SMTPUser")) {
+ sfree (smtp_user);
+ smtp_user = strdup (value);
+ }
+ else if (0 == strcasecmp (key, "SMTPPassword")) {
+ sfree (smtp_password);
+ smtp_password = strdup (value);
+ }
+ else if (0 == strcasecmp (key, "From")) {
+ sfree (email_from);
+ email_from = strdup (value);
+ }
+ else if (0 == strcasecmp (key, "Subject")) {
+ sfree (email_subject);
+ email_subject = strdup (value);
+ }
+ else {
+ return -1;
+ }
+ return 0;
+} /* int notify_email_config (const char *, const char *) */
+
+static int notify_email_notification (const notification_t *n)
+{
+ smtp_recipient_t recipient;
+
+ struct tm timestamp_tm;
+ char timestamp_str[64];
+
+ char severity[32];
+ char subject[MAXSTRING];
+
+ char buf[4096] = "";
+ int buf_len = sizeof (buf);
+ int i;
+
+ ssnprintf (severity, sizeof (severity), "%s",
+ (n->severity == NOTIF_FAILURE) ? "FAILURE"
+ : ((n->severity == NOTIF_WARNING) ? "WARNING"
+ : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN")));
+
+ ssnprintf (subject, sizeof (subject),
+ (email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject,
+ severity, n->host);
+
+ localtime_r (&n->time, ×tamp_tm);
+ strftime (timestamp_str, sizeof (timestamp_str), "%Y-%m-%d %H:%M:%S",
+ ×tamp_tm);
+ timestamp_str[sizeof (timestamp_str) - 1] = '\0';
+
+ /* Let's make RFC822 message text with \r\n EOLs */
+ ssnprintf (buf, buf_len,
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/plain;\r\n"
+ "Content-Transfer-Encoding: 8bit\r\n"
+ "Subject: %s\r\n"
+ "\r\n"
+ "%s - %s@%s\r\n"
+ "\r\n"
+ "Message: %s",
+ subject,
+ timestamp_str,
+ severity,
+ n->host,
+ n->message);
+
+ if (!(message = smtp_add_message (session))) {
+ ERROR ("notify_email plugin: cannot set SMTP message");
+ return (-1);
+ }
+ smtp_set_reverse_path (message, email_from);
+ smtp_set_header (message, "To", NULL, NULL);
+ smtp_set_message_str (message, buf);
+
+ for (i = 0; i < recipients_len; i++)
+ recipient = smtp_add_recipient (message, recipients[i]);
+
+ /* Initiate a connection to the SMTP server and transfer the message. */
+ if (!smtp_start_session (session)) {
+ char buf[MAXSTRING];
+ ERROR ("notify_email plugin: SMTP server problem: %s",
+ smtp_strerror (smtp_errno (), buf, sizeof buf));
+ return (-1);
+ } else {
+ const smtp_status_t *status;
+ /* Report on the success or otherwise of the mail transfer. */
+ status = smtp_message_transfer_status (message);
+ DEBUG ("notify_email plugin: SMTP server report: %d %s",
+ status->code, (status->text != NULL) ? status->text : "\n");
+ smtp_enumerate_recipients (message, print_recipient_status, NULL);
+ }
+
+ return (0);
+} /* int notify_email_notification */
+
+void module_register (void)
+{
+ plugin_register_init ("notify_email", notify_email_init);
+ plugin_register_shutdown ("notify_email", notify_email_shutdown);
+ plugin_register_config ("notify_email", notify_email_config,
+ config_keys, config_keys_num);
+ plugin_register_notification ("notify_email", notify_email_notification);
+} /* void module_register (void) */
+
+/* vim: set sw=2 sts=2 ts=8 et : */
{
int port = (int) (atof (value));
if ((port > 0) && (port <= 65535))
- snprintf (ntpd_port, sizeof (ntpd_port),
+ ssnprintf (ntpd_port, sizeof (ntpd_port),
"%i", port);
else
- strncpy (ntpd_port, value, sizeof (ntpd_port));
- ntpd_port[sizeof (ntpd_port) - 1] = '\0';
+ sstrncpy (ntpd_port, value, sizeof (ntpd_port));
}
else if (strcasecmp (key, "ReverseLookups") == 0)
{
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "ntpd", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
}
/* returns `tv0 - tv1' in milliseconds or 0 if `tv1 > tv0' */
if (refclock_id < refclock_names_num)
{
- strncpy (peername, refclock_names[refclock_id],
+ sstrncpy (peername, refclock_names[refclock_id],
sizeof (peername));
}
else
addr_obj.s_addr = ptr->srcadr;
addr_str = inet_ntoa (addr_obj);
- strncpy (peername, addr_str, sizeof (peername));
+ sstrncpy (peername, addr_str, sizeof (peername));
}
}
else /* Normal network host. */
vl.values = values;
vl.values_len = STATIC_ARRAY_SIZE (values);
vl.time = time (NULL);
- strncpy (vl.host,
+ sstrncpy (vl.host,
(strcasecmp (ups->hostname, "localhost") == 0)
? hostname_g
: ups->hostname,
sizeof (vl.host));
sstrncpy (vl.plugin, "nut", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, ups->upsname, sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.plugin_instance, ups->upsname, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- vl.host[sizeof (vl.host) - 1] = '\0';
- vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
-
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void nut_submit */
static int nut_read_one (nut_ups_t *ups)
--- /dev/null
+/**
+ * collectd - src/owfs.c
+ * Copyright (C) 2008 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
+ * 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:
+ * Florian octo Forster <octo at noris.net>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_ignorelist.h"
+
+#include <owcapi.h>
+
+#define OW_FAMILY_LENGTH 8
+#define OW_FAMILY_MAX_FEATURES 2
+struct ow_family_features_s
+{
+ char family[OW_FAMILY_LENGTH];
+ struct
+ {
+ char filename[DATA_MAX_NAME_LEN];
+ char type[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
+ } features[OW_FAMILY_MAX_FEATURES];
+ size_t features_num;
+};
+typedef struct ow_family_features_s ow_family_features_t;
+
+/* see http://owfs.sourceforge.net/ow_table.html for a list of families */
+static ow_family_features_t ow_family_features[] =
+{
+ {
+ /* family = */ "10.",
+ {
+ {
+ /* filename = */ "temperature",
+ /* type = */ "temperature",
+ /* type_instance = */ ""
+ }
+ },
+ /* features_num = */ 1
+ }
+};
+static int ow_family_features_num = STATIC_ARRAY_SIZE (ow_family_features);
+
+static char *device_g = NULL;
+
+static const char *config_keys[] =
+{
+ "Device",
+ "IgnoreSelected",
+ "Sensor",
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static ignorelist_t *sensor_list;
+
+static int cow_load_config (const char *key, const char *value)
+{
+ if (sensor_list == NULL)
+ sensor_list = ignorelist_create (1);
+
+ if (strcasecmp (key, "Sensor") == 0)
+ {
+ if (ignorelist_add (sensor_list, value))
+ {
+ ERROR ("sensors plugin: "
+ "Cannot add value to ignorelist.");
+ return (1);
+ }
+ }
+ else if (strcasecmp (key, "IgnoreSelected") == 0)
+ {
+ ignorelist_set_invert (sensor_list, 1);
+ if ((strcasecmp (value, "True") == 0)
+ || (strcasecmp (value, "Yes") == 0)
+ || (strcasecmp (value, "On") == 0))
+ ignorelist_set_invert (sensor_list, 0);
+ }
+ else if (strcasecmp (key, "Device") == 0)
+ {
+ char *temp;
+ temp = strdup (value);
+ if (temp == NULL)
+ {
+ ERROR ("onewire plugin: strdup failed.");
+ return (1);
+ }
+ sfree (device_g);
+ device_g = temp;
+ }
+ else
+ {
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int cow_init (void)
+{
+ int status;
+
+ if (device_g == NULL)
+ {
+ ERROR ("onewire plugin: cow_init: No device configured.");
+ return (-1);
+ }
+
+ status = (int) OW_init (device_g);
+ if (status != 0)
+ {
+ ERROR ("onewire plugin: OW_init(%s) failed: %i.", device_g, status);
+ return (1);
+ }
+
+ return (0);
+} /* int cow_init */
+
+static int cow_read_values (const char *path, const char *name,
+ const ow_family_features_t *family_info)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+ int success = 0;
+ size_t i;
+
+ if (sensor_list != NULL)
+ {
+ DEBUG ("onewire plugin: Checking ignorelist for `%s'", name);
+ if (ignorelist_match (sensor_list, name) != 0)
+ return 0;
+ }
+
+ vl.values = values;
+ vl.values_len = 1;
+ vl.time = time (NULL);
+
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "onewire", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, name, sizeof (vl.plugin_instance));
+
+ for (i = 0; i < family_info->features_num; i++)
+ {
+ char *buffer;
+ size_t buffer_size;
+ int status;
+
+ char file[4096];
+ char *endptr;
+
+ snprintf (file, sizeof (file), "%s/%s",
+ path, family_info->features[i].filename);
+ file[sizeof (file) - 1] = 0;
+
+ buffer = NULL;
+ buffer_size = 0;
+ status = OW_get (file, &buffer, &buffer_size);
+ if (status < 0)
+ {
+ ERROR ("onewire plugin: OW_get (%s/%s) failed. status = %#x;",
+ path, family_info->features[i].filename, status);
+ return (-1);
+ }
+
+ endptr = NULL;
+ values[0].gauge = strtod (buffer, &endptr);
+ if (endptr == NULL)
+ {
+ ERROR ("onewire plugin: Buffer is not a number: %s", buffer);
+ status = -1;
+ continue;
+ }
+
+ sstrncpy (vl.type, family_info->features[i].type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, family_info->features[i].type_instance,
+ sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+ success++;
+
+ free (buffer);
+ } /* for (i = 0; i < features_num; i++) */
+
+ return ((success > 0) ? 0 : -1);
+} /* int cow_read_values */
+
+/* Forward declaration so the recursion below works */
+static int cow_read_bus (const char *path);
+
+/*
+ * cow_read_ds2409
+ *
+ * Handles:
+ * - DS2409 - MicroLAN Coupler
+ */
+static int cow_read_ds2409 (const char *path)
+{
+ char subpath[4096];
+ int status;
+
+ status = ssnprintf (subpath, sizeof (subpath), "%s/main", path);
+ if ((status > 0) && (status < sizeof (subpath)))
+ cow_read_bus (subpath);
+
+ status = ssnprintf (subpath, sizeof (subpath), "%s/aux", path);
+ if ((status > 0) && (status < sizeof (subpath)))
+ cow_read_bus (subpath);
+
+ return (0);
+} /* int cow_read_ds2409 */
+
+static int cow_read_bus (const char *path)
+{
+ char *buffer;
+ size_t buffer_size;
+ int status;
+
+ char *buffer_ptr;
+ char *dummy;
+ char *saveptr;
+ char subpath[4096];
+
+ status = OW_get (path, &buffer, &buffer_size);
+ if (status < 0)
+ {
+ ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;",
+ path, status);
+ return (-1);
+ }
+ DEBUG ("onewire plugin: OW_get (%s) returned: %s",
+ path, buffer);
+
+ dummy = buffer;
+ saveptr = NULL;
+ while ((buffer_ptr = strtok_r (dummy, ",/", &saveptr)) != NULL)
+ {
+ int i;
+
+ dummy = NULL;
+
+ if (strcmp ("/", path) == 0)
+ status = ssnprintf (subpath, sizeof (subpath), "/%s", buffer_ptr);
+ else
+ status = ssnprintf (subpath, sizeof (subpath), "%s/%s",
+ path, buffer_ptr);
+ if ((status <= 0) || (status >= sizeof (subpath)))
+ continue;
+
+ for (i = 0; i < ow_family_features_num; i++)
+ {
+ if (strncmp (ow_family_features[i].family, buffer_ptr,
+ strlen (ow_family_features[i].family)) != 0)
+ continue;
+
+ cow_read_values (subpath,
+ buffer_ptr + strlen (ow_family_features[i].family),
+ ow_family_features + i);
+ break;
+ }
+ if (i < ow_family_features_num)
+ continue;
+
+ /* DS2409 */
+ if (strncmp ("1F.", buffer_ptr, strlen ("1F.")) == 0)
+ {
+ cow_read_ds2409 (subpath);
+ continue;
+ }
+ } /* while (strtok_r) */
+
+ free (buffer);
+ return (0);
+} /* int cow_read_bus */
+
+static int cow_read (void)
+{
+ return (cow_read_bus ("/"));
+} /* int cow_read */
+
+static int cow_shutdown (void)
+{
+ OW_finish ();
+ ignorelist_free (sensor_list);
+ return (0);
+} /* int cow_shutdown */
+
+void module_register (void)
+{
+ plugin_register_init ("onewire", cow_init);
+ plugin_register_read ("onewire", cow_read);
+ plugin_register_shutdown ("onewire", cow_shutdown);
+ plugin_register_config ("onewire", cow_load_config,
+ config_keys, config_keys_num);
+}
+
+/* vim: set sw=2 sts=2 ts=8 et fdm=marker cindent : */
#define PLUGIN_TYPES 7
+#define PLUGIN_CONFIG 254
#define PLUGIN_DATASET 255
#define log_debug(...) DEBUG ("perl: " __VA_ARGS__)
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_flush);
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_flush", Collectd__plugin_flush },
{ "Collectd::plugin_dispatch_notification",
Collectd_plugin_dispatch_notification },
{ "Collectd::plugin_log", Collectd_plugin_log },
{ "Collectd::TYPE_LOG", PLUGIN_LOG },
{ "Collectd::TYPE_NOTIF", PLUGIN_NOTIF },
{ "Collectd::TYPE_FLUSH", PLUGIN_FLUSH },
+ { "Collectd::TYPE_CONFIG", PLUGIN_CONFIG },
{ "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))
return 0;
} /* static int notification2hv (notification_t *, HV *) */
+static int oconfig_item2hv (pTHX_ oconfig_item_t *ci, HV *hash)
+{
+ int i;
+
+ AV *values;
+ AV *children;
+
+ if (NULL == hv_store (hash, "key", 3, newSVpv (ci->key, 0), 0))
+ return -1;
+
+ values = newAV ();
+ if (0 < ci->values_num)
+ av_extend (values, ci->values_num);
+
+ if (NULL == hv_store (hash, "values", 6, newRV_noinc ((SV *)values), 0)) {
+ av_clear (values);
+ av_undef (values);
+ return -1;
+ }
+
+ for (i = 0; i < ci->values_num; ++i) {
+ SV *value;
+
+ switch (ci->values[i].type) {
+ case OCONFIG_TYPE_STRING:
+ value = newSVpv (ci->values[i].value.string, 0);
+ break;
+ case OCONFIG_TYPE_NUMBER:
+ value = newSVnv ((NV)ci->values[i].value.number);
+ break;
+ case OCONFIG_TYPE_BOOLEAN:
+ value = ci->values[i].value.boolean ? &PL_sv_yes : &PL_sv_no;
+ break;
+ default:
+ log_err ("oconfig_item2hv: Invalid value type %i.",
+ ci->values[i].type);
+ value = &PL_sv_undef;
+ }
+
+ if (NULL == av_store (values, i, value)) {
+ sv_free (value);
+ return -1;
+ }
+ }
+
+ /* ignoring 'parent' member which is uninteresting in this case */
+
+ children = newAV ();
+ if (0 < ci->children_num)
+ av_extend (children, ci->children_num);
+
+ if (NULL == hv_store (hash, "children", 8, newRV_noinc ((SV *)children), 0)) {
+ av_clear (children);
+ av_undef (children);
+ return -1;
+ }
+
+ for (i = 0; i < ci->children_num; ++i) {
+ HV *child = newHV ();
+
+ if (0 != oconfig_item2hv (aTHX_ ci->children + i, child)) {
+ hv_clear (child);
+ hv_undef (child);
+ return -1;
+ }
+
+ if (NULL == av_store (children, i, newRV_noinc ((SV *)child))) {
+ hv_clear (child);
+ hv_undef (child);
+ return -1;
+ }
+ }
+ return 0;
+} /* static int oconfig_item2hv (pTHX_ oconfig_item_t *, HV *) */
+
/*
* Internal functions.
*/
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)))))) {
log_err ("pplugin_dispatch_values: No valid values given.");
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 {
sstrncpy (list.host, hostname_g, sizeof (list.host));
}
- 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
* };
else if (PLUGIN_FLUSH == type) {
/*
* $_[0] = $timeout;
+ * $_[1] = $identifier;
*/
XPUSHs (sv_2mortal (newSViv (va_arg (ap, int))));
+ XPUSHs (sv_2mortal (newSVpv (va_arg (ap, char *), 0)));
}
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;
+
+ 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_ SvPV_nolen (ST (0)),
- (HV *)SvRV (values));
+ 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).
+ * Collectd::_plugin_flush (plugin, timeout, identifier).
+ *
+ * plugin:
+ * name of the plugin to flush
*
* timeout:
* timeout to use when flushing the data
*
- * name:
- * name of the plugin to flush
+ * identifier:
+ * data-set identifier to flush
*/
-static XS (Collectd_plugin_flush_one)
+static XS (Collectd__plugin_flush)
{
+ char *plugin = NULL;
+ int timeout = -1;
+ char *id = NULL;
+
dXSARGS;
- if (2 != items) {
- log_err ("Usage: Collectd::plugin_flush_one(timeout, name)");
+ if (3 != items) {
+ log_err ("Usage: Collectd::_plugin_flush(plugin, timeout, id)");
XSRETURN_EMPTY;
}
- log_debug ("Collectd::plugin_flush_one: timeout = %i, name = \"%s\"",
- (int)SvIV (ST (0)), SvPV_nolen (ST (1)));
+ if (SvOK (ST (0)))
+ plugin = SvPV_nolen (ST (0));
- if (0 == plugin_flush_one ((int)SvIV (ST (0)), SvPV_nolen (ST (1))))
- XSRETURN_YES;
- else
- XSRETURN_EMPTY;
-} /* static XS (Collectd_plugin_flush_one) */
+ if (SvOK (ST (1)))
+ timeout = (int)SvIV (ST (1));
-/*
- * 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;
- }
+ if (SvOK (ST (2)))
+ id = SvPV_nolen (ST (2));
- log_debug ("Collectd::plugin_flush_all: timeout = %i", (int)SvIV (ST (0)));
+ log_debug ("Collectd::_plugin_flush: plugin = \"%s\", timeout = %i, "
+ "id = \"%s\"", plugin, timeout, id);
- plugin_flush_all ((int)SvIV (ST (0)));
- XSRETURN_YES;
-} /* static XS (Collectd_plugin_flush_all) */
+ if (0 == plugin_flush (plugin, timeout, id))
+ XSRETURN_YES;
+ else
+ XSRETURN_EMPTY;
+} /* static XS (Collectd__plugin_flush) */
/*
* Collectd::plugin_dispatch_notification (notif).
XSRETURN_EMPTY;
}
- plugin_log (SvIV (ST (0)), SvPV_nolen (ST (1)));
+ plugin_log (SvIV (ST (0)), "%s", SvPV_nolen (ST (1)));
XSRETURN_YES;
} /* static XS (Collectd_plugin_log) */
return pplugin_call_all (aTHX_ PLUGIN_NOTIF, notif);
} /* static int perl_notify (const notification_t *) */
-static int perl_flush (const int timeout)
+static int perl_flush (int timeout, const char *identifier)
{
dTHX;
aTHX = t->interp;
}
- return pplugin_call_all (aTHX_ PLUGIN_FLUSH, timeout);
+ return pplugin_call_all (aTHX_ PLUGIN_FLUSH, timeout, identifier);
} /* static int perl_flush (const int) */
static int perl_shutdown (void)
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 *) */
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 *) */
return 0;
} /* static int perl_config_includedir (oconfig_item_it *) */
+/*
+ * <Plugin> block
+ */
+static int perl_config_plugin (pTHX_ oconfig_item_t *ci)
+{
+ int retvals = 0;
+ int ret = 0;
+
+ char *plugin;
+ HV *config;
+
+ dSP;
+
+ if ((1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("LoadPlugin expects a single string argument.");
+ return 1;
+ }
+
+ plugin = ci->values[0].value.string;
+ config = newHV ();
+
+ if (0 != oconfig_item2hv (aTHX_ ci, config)) {
+ hv_clear (config);
+ hv_undef (config);
+
+ log_err ("Unable to convert configuration to a Perl hash value.");
+ config = Nullhv;
+ }
+
+ ENTER;
+ SAVETMPS;
+
+ PUSHMARK (SP);
+
+ XPUSHs (sv_2mortal (newSVpv (plugin, 0)));
+ XPUSHs (sv_2mortal (newRV_noinc ((SV *)config)));
+
+ PUTBACK;
+
+ retvals = call_pv ("Collectd::_plugin_dispatch_config", G_SCALAR);
+
+ SPAGAIN;
+ if (0 < retvals) {
+ SV *tmp = POPs;
+ if (! SvTRUE (tmp))
+ ret = 1;
+ }
+ else
+ ret = 1;
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+ return ret;
+} /* static int perl_config_plugin (oconfig_item_it *) */
+
static int perl_config (oconfig_item_t *ci)
{
+ int status = 0;
int i = 0;
dTHXa (NULL);
for (i = 0; i < ci->children_num; ++i) {
oconfig_item_t *c = ci->children + i;
+ int current_status = 0;
if (NULL != perl_threads)
aTHX = PERL_GET_CONTEXT;
if (0 == strcasecmp (c->key, "LoadPlugin"))
- perl_config_loadplugin (aTHX_ c);
+ current_status = perl_config_loadplugin (aTHX_ c);
else if (0 == strcasecmp (c->key, "BaseName"))
- perl_config_basename (aTHX_ c);
+ current_status = perl_config_basename (aTHX_ c);
else if (0 == strcasecmp (c->key, "EnableDebugger"))
- perl_config_enabledebugger (aTHX_ c);
+ current_status = perl_config_enabledebugger (aTHX_ c);
else if (0 == strcasecmp (c->key, "IncludeDir"))
- perl_config_includedir (aTHX_ c);
+ current_status = perl_config_includedir (aTHX_ c);
+ else if (0 == strcasecmp (c->key, "Plugin"))
+ current_status = perl_config_plugin (aTHX_ c);
else
log_warn ("Ignoring unknown config key \"%s\".", c->key);
+
+ /* fatal error - it's up to perl_config_* to clean up */
+ if (0 > current_status) {
+ log_err ("Configuration failed with a fatal error - "
+ "plugin disabled!");
+ return current_status;
+ }
+
+ status += current_status;
}
- return 0;
+ return status;
} /* static int perl_config (oconfig_item_t *) */
void module_register (void)
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "ping", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, host, sizeof (vl.type_instance));
+ sstrncpy (vl.type_instance, host, sizeof (vl.type_instance));
+ sstrncpy (vl.type, "ping", sizeof (vl.type));
- plugin_dispatch_values ("ping", &vl);
+ plugin_dispatch_values (&vl);
}
static int ping_read (void)
**/
#include "collectd.h"
+#include "utils_complain.h"
#include <ltdl.h>
/* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
* type when matching the filename */
- if (snprintf (typename, BUFSIZE, "%s.so", type) >= BUFSIZE)
+ if (ssnprintf (typename, sizeof (typename),
+ "%s.so", type) >= sizeof (typename))
{
WARNING ("snprintf: truncated: `%s.so'", type);
return (-1);
if (strncasecmp (de->d_name, typename, typename_len))
continue;
- if (snprintf (filename, BUFSIZE, "%s/%s", dir, de->d_name) >= BUFSIZE)
+ if (ssnprintf (filename, sizeof (filename),
+ "%s/%s", dir, de->d_name) >= sizeof (filename))
{
WARNING ("snprintf: truncated: `%s/%s'", dir, de->d_name);
continue;
return (register_callback (&list_write, name, (void *) callback));
} /* int plugin_register_write */
-int plugin_register_flush (const char *name, int (*callback) (const int))
+int plugin_register_flush (const char *name,
+ int (*callback) (const int timeout, const char *identifier))
{
return (register_callback (&list_flush, name, (void *) callback));
} /* int plugin_register_flush */
pthread_mutex_unlock (&read_lock);
} /* void plugin_read_all */
-int plugin_flush_one (int timeout, const char *name)
+int plugin_flush (const char *plugin, int timeout, const char *identifier)
{
- int (*callback) (int);
- llentry_t *le;
- int status;
-
- if (list_flush == NULL)
- return (-1);
-
- le = llist_search (list_flush, name);
- if (le == NULL)
- return (-1);
- callback = (int (*) (int)) le->value;
-
- status = (*callback) (timeout);
-
- return (status);
-} /* int plugin_flush_ont */
-
-void plugin_flush_all (int timeout)
-{
- int (*callback) (int);
- llentry_t *le;
-
- if (list_flush == NULL)
- return;
-
- le = llist_head (list_flush);
- while (le != NULL)
- {
- callback = (int (*) (int)) le->value;
- le = le->next;
-
- (*callback) (timeout);
- }
-} /* void plugin_flush_all */
+ int (*callback) (int timeout, const char *identifier);
+ llentry_t *le;
+
+ if (list_flush == NULL)
+ return (0);
+
+ le = llist_head (list_flush);
+ while (le != NULL)
+ {
+ if ((plugin != NULL)
+ && (strcmp (plugin, le->key) != 0))
+ {
+ le = le->next;
+ continue;
+ }
+
+ callback = (int (*) (int, const char *)) le->value;
+ (*callback) (timeout, identifier);
+
+ le = le->next;
+ }
+ return (0);
+} /* int plugin_flush */
void plugin_shutdown_all (void)
{
}
} /* void plugin_shutdown_all */
-int plugin_dispatch_values (const char *name, value_list_t *vl)
+int plugin_dispatch_values (value_list_t *vl)
{
+ static c_complain_t no_write_complaint = C_COMPLAIN_INIT;
+
int (*callback) (const data_set_t *, const value_list_t *);
data_set_t *ds;
llentry_t *le;
- if (list_write == NULL)
- {
- ERROR ("plugin_dispatch_values: No write callback has been "
- "registered. Please load at least one plugin "
- "that provides a write function.");
+ if ((vl == NULL) || (*vl->type == '\0')) {
+ ERROR ("plugin_dispatch_values: Invalid value list.");
return (-1);
}
+ if (list_write == NULL)
+ c_complain_once (LOG_WARNING, &no_write_complaint,
+ "plugin_dispatch_values: No write callback has been "
+ "registered. Please load at least one output plugin, "
+ "if you want the collected data to be stored.");
+
if (data_sets == NULL)
{
ERROR ("plugin_dispatch_values: No data sets registered. "
return (-1);
}
- if (c_avl_get (data_sets, name, (void *) &ds) != 0)
+ if (c_avl_get (data_sets, vl->type, (void *) &ds) != 0)
{
- INFO ("plugin_dispatch_values: Dataset not found: %s", name);
+ INFO ("plugin_dispatch_values: Dataset not found: %s", vl->type);
return (-1);
}
(unsigned int) vl->time, vl->interval,
vl->host,
vl->plugin, vl->plugin_instance,
- ds->type, vl->type_instance);
+ vl->type, vl->type_instance);
+
+#if COLLECT_DEBUG
+ assert (0 == strcmp (ds->type, vl->type));
+#else
+ if (0 != strcmp (ds->type, vl->type))
+ WARNING ("plugin_dispatch_values: (ds->type = %s) != (vl->type = %s)",
+ ds->type, vl->type);
+#endif
#if COLLECT_DEBUG
assert (ds->ds_num == vl->values_len);
escape_slashes (vl->host, sizeof (vl->host));
escape_slashes (vl->plugin, sizeof (vl->plugin));
escape_slashes (vl->plugin_instance, sizeof (vl->plugin_instance));
+ escape_slashes (vl->type, sizeof (vl->type));
escape_slashes (vl->type_instance, sizeof (vl->type_instance));
/* Update the value cache */
return (ds);
} /* data_set_t *plugin_get_ds */
+
+static int plugin_notification_meta_add (notification_t *n,
+ const char *name,
+ enum notification_meta_type_e type,
+ const void *value)
+{
+ notification_meta_t *meta;
+ notification_meta_t *tail;
+
+ if ((n == NULL) || (name == NULL) || (value == NULL))
+ {
+ ERROR ("plugin_notification_meta_add: A pointer is NULL!");
+ return (-1);
+ }
+
+ meta = (notification_meta_t *) malloc (sizeof (notification_meta_t));
+ if (meta == NULL)
+ {
+ ERROR ("plugin_notification_meta_add: malloc failed.");
+ return (-1);
+ }
+ memset (meta, 0, sizeof (notification_meta_t));
+
+ sstrncpy (meta->name, name, sizeof (meta->name));
+ meta->type = type;
+
+ switch (type)
+ {
+ case NM_TYPE_STRING:
+ {
+ meta->nm_value.nm_string = strdup ((const char *) value);
+ if (meta->nm_value.nm_string == NULL)
+ {
+ ERROR ("plugin_notification_meta_add: strdup failed.");
+ sfree (meta);
+ return (-1);
+ }
+ break;
+ }
+ case NM_TYPE_SIGNED_INT:
+ {
+ meta->nm_value.nm_signed_int = *((int64_t *) value);
+ break;
+ }
+ case NM_TYPE_UNSIGNED_INT:
+ {
+ meta->nm_value.nm_unsigned_int = *((uint64_t *) value);
+ break;
+ }
+ case NM_TYPE_DOUBLE:
+ {
+ meta->nm_value.nm_double = *((double *) value);
+ break;
+ }
+ case NM_TYPE_BOOLEAN:
+ {
+ meta->nm_value.nm_boolean = *((bool *) value);
+ break;
+ }
+ default:
+ {
+ ERROR ("plugin_notification_meta_add: Unknown type: %i", type);
+ sfree (meta);
+ return (-1);
+ }
+ } /* switch (type) */
+
+ meta->next = NULL;
+ tail = n->meta;
+ while ((tail != NULL) && (tail->next != NULL))
+ tail = tail->next;
+
+ if (tail == NULL)
+ n->meta = meta;
+ else
+ tail->next = meta;
+
+ return (0);
+} /* int plugin_notification_meta_add */
+
+int plugin_notification_meta_add_string (notification_t *n,
+ const char *name,
+ const char *value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_STRING, value));
+}
+
+int plugin_notification_meta_add_signed_int (notification_t *n,
+ const char *name,
+ int64_t value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_SIGNED_INT, &value));
+}
+
+int plugin_notification_meta_add_unsigned_int (notification_t *n,
+ const char *name,
+ uint64_t value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_UNSIGNED_INT, &value));
+}
+
+int plugin_notification_meta_add_double (notification_t *n,
+ const char *name,
+ double value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_DOUBLE, &value));
+}
+
+int plugin_notification_meta_add_boolean (notification_t *n,
+ const char *name,
+ bool value)
+{
+ return (plugin_notification_meta_add (n, name, NM_TYPE_BOOLEAN, &value));
+}
+
+int plugin_notification_meta_copy (notification_t *dst,
+ const notification_t *src)
+{
+ notification_meta_t *meta;
+
+ assert (dst != NULL);
+ assert (src != NULL);
+ assert (dst != src);
+ assert ((src->meta == NULL) || (src->meta != dst->meta));
+
+ for (meta = src->meta; meta != NULL; meta = meta->next)
+ {
+ if (meta->type == NM_TYPE_STRING)
+ plugin_notification_meta_add_string (dst, meta->name,
+ meta->nm_value.nm_string);
+ else if (meta->type == NM_TYPE_SIGNED_INT)
+ plugin_notification_meta_add_signed_int (dst, meta->name,
+ meta->nm_value.nm_signed_int);
+ else if (meta->type == NM_TYPE_UNSIGNED_INT)
+ plugin_notification_meta_add_unsigned_int (dst, meta->name,
+ meta->nm_value.nm_unsigned_int);
+ else if (meta->type == NM_TYPE_DOUBLE)
+ plugin_notification_meta_add_double (dst, meta->name,
+ meta->nm_value.nm_double);
+ else if (meta->type == NM_TYPE_BOOLEAN)
+ plugin_notification_meta_add_boolean (dst, meta->name,
+ meta->nm_value.nm_boolean);
+ }
+
+ return (0);
+} /* int plugin_notification_meta_copy */
+
+int plugin_notification_meta_free (notification_t *n)
+{
+ notification_meta_t *this;
+ notification_meta_t *next;
+
+ if (n == NULL)
+ {
+ ERROR ("plugin_notification_meta_free: n == NULL!");
+ return (-1);
+ }
+
+ this = n->meta;
+ n->meta = NULL;
+ while (this != NULL)
+ {
+ next = this->next;
+
+ if (this->type == NM_TYPE_STRING)
+ {
+ free ((char *)this->nm_value.nm_string);
+ this->nm_value.nm_string = NULL;
+ }
+ sfree (this);
+
+ this = next;
+ }
+
+ return (0);
+} /* int plugin_notification_meta_free */
char host[DATA_MAX_NAME_LEN];
char plugin[DATA_MAX_NAME_LEN];
char plugin_instance[DATA_MAX_NAME_LEN];
+ char type[DATA_MAX_NAME_LEN];
char type_instance[DATA_MAX_NAME_LEN];
};
typedef struct value_list_s value_list_t;
-#define VALUE_LIST_INIT { NULL, 0, 0, interval_g, "localhost", "", "", "" }
-#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "" }
+#define VALUE_LIST_INIT { NULL, 0, 0, interval_g, "localhost", "", "", "", "" }
+#define VALUE_LIST_STATIC { NULL, 0, 0, 0, "localhost", "", "", "", "" }
struct data_source_s
{
};
typedef struct data_set_s data_set_t;
+enum notification_meta_type_e
+{
+ NM_TYPE_STRING,
+ NM_TYPE_SIGNED_INT,
+ NM_TYPE_UNSIGNED_INT,
+ NM_TYPE_DOUBLE,
+ NM_TYPE_BOOLEAN
+};
+
+typedef struct notification_meta_s
+{
+ char name[DATA_MAX_NAME_LEN];
+ enum notification_meta_type_e type;
+ union
+ {
+ const char *nm_string;
+ int64_t nm_signed_int;
+ uint64_t nm_unsigned_int;
+ double nm_double;
+ bool nm_boolean;
+ } nm_value;
+ struct notification_meta_s *next;
+} notification_meta_t;
+
typedef struct notification_s
{
int severity;
char plugin_instance[DATA_MAX_NAME_LEN];
char type[DATA_MAX_NAME_LEN];
char type_instance[DATA_MAX_NAME_LEN];
+ notification_meta_t *meta;
} notification_t;
/*
void plugin_init_all (void);
void plugin_read_all (void);
-void plugin_flush_all (int timeout);
void plugin_shutdown_all (void);
-int plugin_flush_one (int timeout, const char *name);
+int plugin_flush (const char *plugin, int timeout, const char *identifier);
/*
* The `plugin_register_*' functions are used to make `config', `init',
int plugin_register_write (const char *name,
int (*callback) (const data_set_t *ds, const value_list_t *vl));
int plugin_register_flush (const char *name,
- int (*callback) (const int));
+ int (*callback) (const int timeout, const char *identifier));
int plugin_register_shutdown (char *name,
int (*callback) (void));
int plugin_register_data_set (const data_set_t *ds);
* write-functions.
*
* ARGUMENTS
- * `name' Name/type of the data-set that describe the values in `vl'.
* `vl' Value list of the values that have been read by a `read'
* function.
*/
-int plugin_dispatch_values (const char *name, value_list_t *vl);
+int plugin_dispatch_values (value_list_t *vl);
int plugin_dispatch_notification (const notification_t *notif);
const data_set_t *plugin_get_ds (const char *name);
+int plugin_notification_meta_add_string (notification_t *n,
+ const char *name,
+ const char *value);
+int plugin_notification_meta_add_signed_int (notification_t *n,
+ const char *name,
+ int64_t value);
+int plugin_notification_meta_add_unsigned_int (notification_t *n,
+ const char *name,
+ uint64_t value);
+int plugin_notification_meta_add_double (notification_t *n,
+ const char *name,
+ double value);
+int plugin_notification_meta_add_boolean (notification_t *n,
+ const char *name,
+ bool value);
+
+int plugin_notification_meta_copy (notification_t *dst,
+ const notification_t *src);
+
+int plugin_notification_meta_free (notification_t *n);
+
#endif /* PLUGIN_H */
--- /dev/null
+/**
+ * collectd - src/postgresql.c
+ * Copyright (C) 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Sebastian Harl <sh at tokkee.org>
+ **/
+
+/*
+ * This module collects PostgreSQL database statistics.
+ */
+
+#include "collectd.h"
+#include "common.h"
+
+#include "configfile.h"
+#include "plugin.h"
+
+#include "utils_complain.h"
+
+#include <pg_config_manual.h>
+#include <libpq-fe.h>
+
+#define log_err(...) ERROR ("postgresql: " __VA_ARGS__)
+#define log_warn(...) WARNING ("postgresql: " __VA_ARGS__)
+#define log_info(...) INFO ("postgresql: " __VA_ARGS__)
+
+#ifndef C_PSQL_DEFAULT_CONF
+# define C_PSQL_DEFAULT_CONF PKGDATADIR "/postgresql_default.conf"
+#endif
+
+/* Appends the (parameter, value) pair to the string
+ * pointed to by 'buf' suitable to be used as argument
+ * for PQconnectdb(). If value equals NULL, the pair
+ * is ignored. */
+#define C_PSQL_PAR_APPEND(buf, buf_len, parameter, value) \
+ if ((0 < (buf_len)) && (NULL != (value)) && ('\0' != *(value))) { \
+ int s = ssnprintf (buf, buf_len, " %s = '%s'", parameter, value); \
+ if (0 < s) { \
+ buf += s; \
+ buf_len -= s; \
+ } \
+ }
+
+/* Returns the tuple (major, minor, patchlevel)
+ * for the given version number. */
+#define C_PSQL_SERVER_VERSION3(server_version) \
+ (server_version) / 10000, \
+ (server_version) / 100 - (int)((server_version) / 10000) * 100, \
+ (server_version) - (int)((server_version) / 100) * 100
+
+/* Returns true if the given host specifies a
+ * UNIX domain socket. */
+#define C_PSQL_IS_UNIX_DOMAIN_SOCKET(host) \
+ ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
+
+/* Returns the tuple (host, delimiter, port) for a
+ * given (host, port) pair. Depending on the value of
+ * 'host' a UNIX domain socket or a TCP socket is
+ * assumed. */
+#define C_PSQL_SOCKET3(host, port) \
+ ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \
+ C_PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \
+ port
+
+typedef enum {
+ C_PSQL_PARAM_HOST = 1,
+ C_PSQL_PARAM_DB,
+ C_PSQL_PARAM_USER,
+} c_psql_param_t;
+
+typedef struct {
+ char *type;
+ char *type_instance;
+ int ds_type;
+} c_psql_col_t;
+
+typedef struct {
+ char *name;
+ char *query;
+
+ c_psql_param_t *params;
+ int params_num;
+
+ c_psql_col_t *cols;
+ int cols_num;
+
+ int min_pg_version;
+ int max_pg_version;
+} c_psql_query_t;
+
+typedef struct {
+ PGconn *conn;
+ c_complain_t conn_complaint;
+
+ int proto_version;
+
+ int max_params_num;
+
+ /* user configuration */
+ c_psql_query_t **queries;
+ int queries_num;
+
+ char *host;
+ char *port;
+ char *database;
+ char *user;
+ char *password;
+
+ char *sslmode;
+
+ char *krbsrvname;
+
+ char *service;
+} c_psql_database_t;
+
+static char *def_queries[] = {
+ "backends",
+ "transactions",
+ "queries",
+ "query_plans",
+ "table_states",
+ "disk_io",
+ "disk_usage"
+};
+static int def_queries_num = STATIC_ARRAY_SIZE (def_queries);
+
+static c_psql_query_t *queries = NULL;
+static int queries_num = 0;
+
+static c_psql_database_t *databases = NULL;
+static int databases_num = 0;
+
+static c_psql_query_t *c_psql_query_new (const char *name)
+{
+ c_psql_query_t *query;
+
+ ++queries_num;
+ if (NULL == (queries = (c_psql_query_t *)realloc (queries,
+ queries_num * sizeof (*queries)))) {
+ log_err ("Out of memory.");
+ exit (5);
+ }
+ query = queries + queries_num - 1;
+
+ query->name = sstrdup (name);
+ query->query = NULL;
+
+ query->params = NULL;
+ query->params_num = 0;
+
+ query->cols = NULL;
+ query->cols_num = 0;
+
+ query->min_pg_version = 0;
+ query->max_pg_version = INT_MAX;
+ return query;
+} /* c_psql_query_new */
+
+static void c_psql_query_delete (c_psql_query_t *query)
+{
+ int i;
+
+ sfree (query->name);
+ sfree (query->query);
+
+ sfree (query->params);
+ query->params_num = 0;
+
+ for (i = 0; i < query->cols_num; ++i) {
+ sfree (query->cols[i].type);
+ sfree (query->cols[i].type_instance);
+ }
+ sfree (query->cols);
+ query->cols_num = 0;
+ return;
+} /* c_psql_query_delete */
+
+static c_psql_query_t *c_psql_query_get (const char *name, int server_version)
+{
+ int i;
+
+ for (i = 0; i < queries_num; ++i)
+ if (0 == strcasecmp (name, queries[i].name)
+ && ((-1 == server_version)
+ || ((queries[i].min_pg_version <= server_version)
+ && (server_version <= queries[i].max_pg_version))))
+ return queries + i;
+ return NULL;
+} /* c_psql_query_get */
+
+static c_psql_database_t *c_psql_database_new (const char *name)
+{
+ c_psql_database_t *db;
+
+ ++databases_num;
+ if (NULL == (databases = (c_psql_database_t *)realloc (databases,
+ databases_num * sizeof (*databases)))) {
+ log_err ("Out of memory.");
+ exit (5);
+ }
+
+ db = databases + (databases_num - 1);
+
+ db->conn = NULL;
+
+ db->conn_complaint.last = 0;
+ db->conn_complaint.interval = 0;
+
+ db->proto_version = 0;
+
+ db->max_params_num = 0;
+
+ db->queries = NULL;
+ db->queries_num = 0;
+
+ db->database = sstrdup (name);
+ db->host = NULL;
+ db->port = NULL;
+ db->user = NULL;
+ db->password = NULL;
+
+ db->sslmode = NULL;
+
+ db->krbsrvname = NULL;
+
+ db->service = NULL;
+ return db;
+} /* c_psql_database_new */
+
+static void c_psql_database_delete (c_psql_database_t *db)
+{
+ PQfinish (db->conn);
+ db->conn = NULL;
+
+ sfree (db->queries);
+ db->queries_num = 0;
+
+ sfree (db->database);
+ sfree (db->host);
+ sfree (db->port);
+ sfree (db->user);
+ sfree (db->password);
+
+ sfree (db->sslmode);
+
+ sfree (db->krbsrvname);
+
+ sfree (db->service);
+ return;
+} /* c_psql_database_delete */
+
+static void submit (const c_psql_database_t *db,
+ const char *type, const char *type_instance,
+ value_t *values, size_t values_len)
+{
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = values;
+ vl.values_len = values_len;
+ vl.time = time (NULL);
+
+ if (C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host)
+ || (0 == strcmp (db->host, "localhost")))
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ else
+ sstrncpy (vl.host, db->host, sizeof (vl.host));
+
+ sstrncpy (vl.plugin, "postgresql", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, db->database, sizeof (vl.plugin_instance));
+
+ sstrncpy (vl.type, type, sizeof (vl.type));
+
+ if (NULL != type_instance)
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+ return;
+} /* submit */
+
+static void submit_counter (const c_psql_database_t *db,
+ const char *type, const char *type_instance,
+ const char *value)
+{
+ value_t values[1];
+
+ if ((NULL == value) || ('\0' == *value))
+ return;
+
+ values[0].counter = atoll (value);
+ submit (db, type, type_instance, values, 1);
+ return;
+} /* submit_counter */
+
+static void submit_gauge (const c_psql_database_t *db,
+ const char *type, const char *type_instance,
+ const char *value)
+{
+ value_t values[1];
+
+ if ((NULL == value) || ('\0' == *value))
+ return;
+
+ values[0].gauge = atof (value);
+ submit (db, type, type_instance, values, 1);
+ return;
+} /* submit_gauge */
+
+static int c_psql_check_connection (c_psql_database_t *db)
+{
+ /* "ping" */
+ PQclear (PQexec (db->conn, "SELECT 42;"));
+
+ if (CONNECTION_OK != PQstatus (db->conn)) {
+ PQreset (db->conn);
+
+ /* trigger c_release() */
+ if (0 == db->conn_complaint.interval)
+ db->conn_complaint.interval = 1;
+
+ if (CONNECTION_OK != PQstatus (db->conn)) {
+ c_complain (LOG_ERR, &db->conn_complaint,
+ "Failed to connect to database %s: %s",
+ db->database, PQerrorMessage (db->conn));
+ return -1;
+ }
+
+ db->proto_version = PQprotocolVersion (db->conn);
+ if (3 > db->proto_version)
+ log_warn ("Protocol version %d does not support parameters.",
+ db->proto_version);
+ }
+
+ c_release (LOG_INFO, &db->conn_complaint,
+ "Successfully reconnected to database %s", PQdb (db->conn));
+ return 0;
+} /* c_psql_check_connection */
+
+static PGresult *c_psql_exec_query_params (c_psql_database_t *db,
+ c_psql_query_t *query)
+{
+ char *params[db->max_params_num];
+ int i;
+
+ assert (db->max_params_num >= query->params_num);
+
+ for (i = 0; i < query->params_num; ++i) {
+ switch (query->params[i]) {
+ case C_PSQL_PARAM_HOST:
+ params[i] = C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host)
+ ? "localhost" : db->host;
+ break;
+ case C_PSQL_PARAM_DB:
+ params[i] = db->database;
+ break;
+ case C_PSQL_PARAM_USER:
+ params[i] = db->user;
+ break;
+ default:
+ assert (0);
+ }
+ }
+
+ return PQexecParams (db->conn, query->query, query->params_num, NULL,
+ (const char *const *)((0 == query->params_num) ? NULL : params),
+ NULL, NULL, /* return text data */ 0);
+} /* c_psql_exec_query_params */
+
+static PGresult *c_psql_exec_query_noparams (c_psql_database_t *db,
+ c_psql_query_t *query)
+{
+ return PQexec (db->conn, query->query);
+} /* c_psql_exec_query_noparams */
+
+static int c_psql_exec_query (c_psql_database_t *db, int idx)
+{
+ c_psql_query_t *query;
+ PGresult *res;
+
+ int rows, cols;
+ int i;
+
+ if (idx >= db->queries_num)
+ return -1;
+
+ query = db->queries[idx];
+
+ if (3 <= db->proto_version)
+ res = c_psql_exec_query_params (db, query);
+ else if (0 == query->params_num)
+ res = c_psql_exec_query_noparams (db, query);
+ else {
+ log_err ("Connection to database \"%s\" does not support parameters "
+ "(protocol version %d) - cannot execute query \"%s\".",
+ db->database, db->proto_version, query->name);
+ return -1;
+ }
+
+ if (PGRES_TUPLES_OK != PQresultStatus (res)) {
+ log_err ("Failed to execute SQL query: %s",
+ PQerrorMessage (db->conn));
+ log_info ("SQL query was: %s", query->query);
+ PQclear (res);
+ return -1;
+ }
+
+ rows = PQntuples (res);
+ if (1 > rows) {
+ PQclear (res);
+ return 0;
+ }
+
+ cols = PQnfields (res);
+ if (query->cols_num != cols) {
+ log_err ("SQL query returned wrong number of fields "
+ "(expected: %i, got: %i)", query->cols_num, cols);
+ log_info ("SQL query was: %s", query->query);
+ PQclear (res);
+ return -1;
+ }
+
+ for (i = 0; i < rows; ++i) {
+ int j;
+
+ for (j = 0; j < cols; ++j) {
+ c_psql_col_t col = query->cols[j];
+
+ char *value = PQgetvalue (res, i, j);
+
+ if (col.ds_type == DS_TYPE_COUNTER)
+ submit_counter (db, col.type, col.type_instance, value);
+ else if (col.ds_type == DS_TYPE_GAUGE)
+ submit_gauge (db, col.type, col.type_instance, value);
+ }
+ }
+ PQclear (res);
+ return 0;
+} /* c_psql_exec_query */
+
+static int c_psql_read (void)
+{
+ int success = 0;
+ int i;
+
+ for (i = 0; i < databases_num; ++i) {
+ c_psql_database_t *db = databases + i;
+
+ int j;
+
+ assert (NULL != db->database);
+
+ if (0 != c_psql_check_connection (db))
+ continue;
+
+ for (j = 0; j < db->queries_num; ++j)
+ c_psql_exec_query (db, j);
+
+ ++success;
+ }
+
+ if (! success)
+ return -1;
+ return 0;
+} /* c_psql_read */
+
+static int c_psql_shutdown (void)
+{
+ int i;
+
+ if ((NULL == databases) || (0 == databases_num))
+ return 0;
+
+ plugin_unregister_read ("postgresql");
+ plugin_unregister_shutdown ("postgresql");
+
+ for (i = 0; i < databases_num; ++i) {
+ c_psql_database_t *db = databases + i;
+ c_psql_database_delete (db);
+ }
+
+ sfree (databases);
+ databases_num = 0;
+
+ for (i = 0; i < queries_num; ++i) {
+ c_psql_query_t *query = queries + i;
+ c_psql_query_delete (query);
+ }
+
+ sfree (queries);
+ queries_num = 0;
+ return 0;
+} /* c_psql_shutdown */
+
+static int c_psql_init (void)
+{
+ int i;
+
+ if ((NULL == databases) || (0 == databases_num))
+ return 0;
+
+ for (i = 0; i < queries_num; ++i) {
+ c_psql_query_t *query = queries + i;
+ int j;
+
+ for (j = 0; j < query->cols_num; ++j) {
+ c_psql_col_t *col = query->cols + j;
+ const data_set_t *ds;
+
+ ds = plugin_get_ds (col->type);
+ if (NULL == ds) {
+ log_err ("Column: Unknown type \"%s\".", col->type);
+ c_psql_shutdown ();
+ return -1;
+ }
+
+ if (1 != ds->ds_num) {
+ log_err ("Column: Invalid type \"%s\" - types defining "
+ "one data source are supported only (got: %i).",
+ col->type, ds->ds_num);
+ c_psql_shutdown ();
+ return -1;
+ }
+
+ col->ds_type = ds->ds[0].type;
+ }
+ }
+
+ for (i = 0; i < databases_num; ++i) {
+ c_psql_database_t *db = databases + i;
+
+ char conninfo[4096];
+ char *buf = conninfo;
+ int buf_len = sizeof (conninfo);
+ int status;
+
+ char *server_host;
+ int server_version;
+
+ int j;
+
+ /* this will happen during reinitialization */
+ if (NULL != db->conn) {
+ c_psql_check_connection (db);
+ continue;
+ }
+
+ status = ssnprintf (buf, buf_len, "dbname = '%s'", db->database);
+ if (0 < status) {
+ buf += status;
+ buf_len -= status;
+ }
+
+ C_PSQL_PAR_APPEND (buf, buf_len, "host", db->host);
+ C_PSQL_PAR_APPEND (buf, buf_len, "port", db->port);
+ C_PSQL_PAR_APPEND (buf, buf_len, "user", db->user);
+ C_PSQL_PAR_APPEND (buf, buf_len, "password", db->password);
+ C_PSQL_PAR_APPEND (buf, buf_len, "sslmode", db->sslmode);
+ C_PSQL_PAR_APPEND (buf, buf_len, "krbsrvname", db->krbsrvname);
+ C_PSQL_PAR_APPEND (buf, buf_len, "service", db->service);
+
+ db->conn = PQconnectdb (conninfo);
+ if (0 != c_psql_check_connection (db))
+ continue;
+
+ db->proto_version = PQprotocolVersion (db->conn);
+
+ server_host = PQhost (db->conn);
+ server_version = PQserverVersion (db->conn);
+ log_info ("Sucessfully connected to database %s (user %s) "
+ "at server %s%s%s (server version: %d.%d.%d, "
+ "protocol version: %d, pid: %d)",
+ PQdb (db->conn), PQuser (db->conn),
+ C_PSQL_SOCKET3 (server_host, PQport (db->conn)),
+ C_PSQL_SERVER_VERSION3 (server_version),
+ db->proto_version, PQbackendPID (db->conn));
+
+ if (3 > db->proto_version)
+ log_warn ("Protocol version %d does not support parameters.",
+ db->proto_version);
+
+ /* Now that we know the PostgreSQL server version, we can get the
+ * right version of each query definition. */
+ for (j = 0; j < db->queries_num; ++j) {
+ c_psql_query_t *tmp;
+
+ tmp = c_psql_query_get (db->queries[j]->name, server_version);
+
+ if (tmp == db->queries[j])
+ continue;
+
+ if (NULL == tmp) {
+ log_err ("Query \"%s\" not found for server version %i - "
+ "please check your configuration.",
+ db->queries[j]->name, server_version);
+
+ if (db->queries_num - j - 1 > 0)
+ memmove (db->queries + j, db->queries + j + 1,
+ (db->queries_num - j - 1) * sizeof (*db->queries));
+
+ --db->queries_num;
+ --j;
+ continue;
+ }
+
+ db->queries[j] = tmp;
+ }
+ }
+
+ plugin_register_read ("postgresql", c_psql_read);
+ plugin_register_shutdown ("postgresql", c_psql_shutdown);
+ return 0;
+} /* c_psql_init */
+
+static int config_set_s (char *name, char **var, const oconfig_item_t *ci)
+{
+ if ((0 != ci->children_num) || (1 != ci->values_num)
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("%s expects a single string argument.", name);
+ return 1;
+ }
+
+ sfree (*var);
+ *var = sstrdup (ci->values[0].value.string);
+ return 0;
+} /* config_set_s */
+
+static int config_set_i (char *name, int *var, const oconfig_item_t *ci)
+{
+ if ((0 != ci->children_num) || (1 != ci->values_num)
+ || (OCONFIG_TYPE_NUMBER != ci->values[0].type)) {
+ log_err ("%s expects a single number argument.", name);
+ return 1;
+ }
+
+ *var = (int)ci->values[0].value.number;
+ return 0;
+} /* config_set_i */
+
+static int config_set_param (c_psql_query_t *query, const oconfig_item_t *ci)
+{
+ c_psql_param_t param;
+ char *param_str;
+
+ if ((0 != ci->children_num) || (1 != ci->values_num)
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("Param expects a single string argument.");
+ return 1;
+ }
+
+ param_str = ci->values[0].value.string;
+ if (0 == strcasecmp (param_str, "hostname"))
+ param = C_PSQL_PARAM_HOST;
+ else if (0 == strcasecmp (param_str, "database"))
+ param = C_PSQL_PARAM_DB;
+ else if (0 == strcasecmp (param_str, "username"))
+ param = C_PSQL_PARAM_USER;
+ else {
+ log_err ("Invalid parameter \"%s\".", param_str);
+ return 1;
+ }
+
+ ++query->params_num;
+ if (NULL == (query->params = (c_psql_param_t *)realloc (query->params,
+ query->params_num * sizeof (*query->params)))) {
+ log_err ("Out of memory.");
+ exit (5);
+ }
+
+ query->params[query->params_num - 1] = param;
+ return 0;
+} /* config_set_param */
+
+static int config_set_column (c_psql_query_t *query, const oconfig_item_t *ci)
+{
+ c_psql_col_t *col;
+
+ int i;
+
+ if ((0 != ci->children_num)
+ || (1 > ci->values_num) || (2 < ci->values_num)) {
+ log_err ("Column expects either one or two arguments.");
+ return 1;
+ }
+
+ for (i = 0; i < ci->values_num; ++i) {
+ if (OCONFIG_TYPE_STRING != ci->values[i].type) {
+ log_err ("Column expects either one or two string arguments.");
+ return 1;
+ }
+ }
+
+ ++query->cols_num;
+ if (NULL == (query->cols = (c_psql_col_t *)realloc (query->cols,
+ query->cols_num * sizeof (*query->cols)))) {
+ log_err ("Out of memory.");
+ exit (5);
+ }
+
+ col = query->cols + query->cols_num - 1;
+
+ col->ds_type = -1;
+
+ col->type = sstrdup (ci->values[0].value.string);
+ col->type_instance = (2 == ci->values_num)
+ ? sstrdup (ci->values[1].value.string) : NULL;
+ return 0;
+} /* config_set_column */
+
+static int set_query (c_psql_database_t *db, const char *name)
+{
+ c_psql_query_t *query;
+
+ query = c_psql_query_get (name, -1);
+ if (NULL == query) {
+ log_err ("Query \"%s\" not found - please check your configuration.",
+ name);
+ return 1;
+ }
+
+ ++db->queries_num;
+ if (NULL == (db->queries = (c_psql_query_t **)realloc (db->queries,
+ db->queries_num * sizeof (*db->queries)))) {
+ log_err ("Out of memory.");
+ exit (5);
+ }
+
+ if (query->params_num > db->max_params_num)
+ db->max_params_num = query->params_num;
+
+ db->queries[db->queries_num - 1] = query;
+ return 0;
+} /* set_query */
+
+static int config_set_query (c_psql_database_t *db, const oconfig_item_t *ci)
+{
+ if ((0 != ci->children_num) || (1 != ci->values_num)
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("Query expects a single string argument.");
+ return 1;
+ }
+ return set_query (db, ci->values[0].value.string);
+} /* config_set_query */
+
+static int c_psql_config_query (oconfig_item_t *ci)
+{
+ c_psql_query_t *query;
+
+ int i;
+
+ if ((1 != ci->values_num)
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("<Query> expects a single string argument.");
+ return 1;
+ }
+
+ query = c_psql_query_new (ci->values[0].value.string);
+
+ for (i = 0; i < ci->children_num; ++i) {
+ oconfig_item_t *c = ci->children + i;
+
+ if (0 == strcasecmp (c->key, "Query"))
+ config_set_s ("Query", &query->query, c);
+ else if (0 == strcasecmp (c->key, "Param"))
+ config_set_param (query, c);
+ else if (0 == strcasecmp (c->key, "Column"))
+ config_set_column (query, c);
+ else if (0 == strcasecmp (c->key, "MinPGVersion"))
+ config_set_i ("MinPGVersion", &query->min_pg_version, c);
+ else if (0 == strcasecmp (c->key, "MaxPGVersion"))
+ config_set_i ("MaxPGVersion", &query->max_pg_version, c);
+ else
+ log_warn ("Ignoring unknown config key \"%s\".", c->key);
+ }
+
+ for (i = 0; i < queries_num - 1; ++i) {
+ c_psql_query_t *q = queries + i;
+
+ if ((0 == strcasecmp (q->name, query->name))
+ && (q->min_pg_version <= query->max_pg_version)
+ && (query->min_pg_version <= q->max_pg_version)) {
+ log_err ("Ignoring redefinition (with overlapping version ranges) "
+ "of query \"%s\".", query->name);
+ c_psql_query_delete (query);
+ --queries_num;
+ return 1;
+ }
+ }
+
+ if (query->min_pg_version > query->max_pg_version) {
+ log_err ("Query \"%s\": MinPGVersion > MaxPGVersion.",
+ query->name);
+ c_psql_query_delete (query);
+ --queries_num;
+ return 1;
+ }
+
+ if (NULL == query->query) {
+ log_err ("Query \"%s\" does not include an SQL query string - "
+ "please check your configuration.", query->name);
+ c_psql_query_delete (query);
+ --queries_num;
+ return 1;
+ }
+ return 0;
+} /* c_psql_config_query */
+
+static int c_psql_config_database (oconfig_item_t *ci)
+{
+ c_psql_database_t *db;
+
+ int i;
+
+ if ((1 != ci->values_num)
+ || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
+ log_err ("<Database> expects a single string argument.");
+ return 1;
+ }
+
+ db = c_psql_database_new (ci->values[0].value.string);
+
+ for (i = 0; i < ci->children_num; ++i) {
+ oconfig_item_t *c = ci->children + i;
+
+ if (0 == strcasecmp (c->key, "Host"))
+ config_set_s ("Host", &db->host, c);
+ else if (0 == strcasecmp (c->key, "Port"))
+ config_set_s ("Port", &db->port, c);
+ else if (0 == strcasecmp (c->key, "User"))
+ config_set_s ("User", &db->user, c);
+ else if (0 == strcasecmp (c->key, "Password"))
+ config_set_s ("Password", &db->password, c);
+ else if (0 == strcasecmp (c->key, "SSLMode"))
+ config_set_s ("SSLMode", &db->sslmode, c);
+ else if (0 == strcasecmp (c->key, "KRBSrvName"))
+ config_set_s ("KRBSrvName", &db->krbsrvname, c);
+ else if (0 == strcasecmp (c->key, "Service"))
+ config_set_s ("Service", &db->service, c);
+ else if (0 == strcasecmp (c->key, "Query"))
+ config_set_query (db, c);
+ else
+ log_warn ("Ignoring unknown config key \"%s\".", c->key);
+ }
+
+ if (NULL == db->queries) {
+ for (i = 0; i < def_queries_num; ++i)
+ set_query (db, def_queries[i]);
+ }
+ return 0;
+}
+
+static int c_psql_config (oconfig_item_t *ci)
+{
+ static int have_def_config = 0;
+
+ int i;
+
+ if (0 == have_def_config) {
+ oconfig_item_t *c;
+
+ have_def_config = 1;
+
+ c = oconfig_parse_file (C_PSQL_DEFAULT_CONF);
+ if (NULL == c)
+ log_err ("Failed to read default config ("C_PSQL_DEFAULT_CONF").");
+ else
+ c_psql_config (c);
+
+ if (NULL == queries)
+ log_err ("Default config ("C_PSQL_DEFAULT_CONF") did not define "
+ "any queries - please check your installation.");
+ }
+
+ for (i = 0; i < ci->children_num; ++i) {
+ oconfig_item_t *c = ci->children + i;
+
+ if (0 == strcasecmp (c->key, "Query"))
+ c_psql_config_query (c);
+ else if (0 == strcasecmp (c->key, "Database"))
+ c_psql_config_database (c);
+ else
+ log_warn ("Ignoring unknown config key \"%s\".", c->key);
+ }
+ return 0;
+} /* c_psql_config */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("postgresql", c_psql_config);
+ plugin_register_init ("postgresql", c_psql_init);
+} /* module_register */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
--- /dev/null
+# Pre-defined queries of collectd's postgresql plugin.
+
+<Query backends>
+ Query "SELECT count(*) \
+ FROM pg_stat_activity \
+ WHERE datname = $1;"
+
+ Param database
+
+ Column pg_numbackends
+</Query>
+
+<Query transactions>
+ Query "SELECT xact_commit, xact_rollback \
+ FROM pg_stat_database \
+ WHERE datname = $1;"
+
+ Param database
+
+ Column pg_xact commit
+ Column pg_xact rollback
+</Query>
+
+<Query queries>
+ Query "SELECT sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del) \
+ FROM pg_stat_user_tables;"
+
+ Column pg_n_tup_c ins
+ Column pg_n_tup_c upd
+ Column pg_n_tup_c del
+
+ MaxPGVersion 80299
+</Query>
+
+<Query queries>
+ Query "SELECT sum(n_tup_ins), sum(n_tup_upd), sum(n_tup_del), \
+ sum(n_tup_hot_upd) \
+ FROM pg_stat_user_tables;"
+
+ Column pg_n_tup_c ins
+ Column pg_n_tup_c upd
+ Column pg_n_tup_c del
+ Column pg_n_tup_c hot_upd
+
+ MinPGVersion 80300
+</Query>
+
+<Query query_plans>
+ Query "SELECT sum(seq_scan), sum(seq_tup_read), \
+ sum(idx_scan), sum(idx_tup_fetch) \
+ FROM pg_stat_user_tables;"
+
+ Column pg_scan seq
+ Column pg_scan seq_tup_read
+ Column pg_scan idx
+ Column pg_scan idx_tup_fetch
+</Query>
+
+<Query table_states>
+ Query "SELECT sum(n_live_tup), sum(n_dead_tup) \
+ FROM pg_stat_user_tables;"
+
+ Column pg_n_tup_g live
+ Column pg_n_tup_g dead
+
+ MinPGVersion 80300
+</Query>
+
+<Query disk_io>
+ Query "SELECT sum(heap_blks_read), sum(heap_blks_hit), \
+ sum(idx_blks_read), sum(idx_blks_hit), \
+ sum(toast_blks_read), sum(toast_blks_hit), \
+ sum(tidx_blks_read), sum(tidx_blks_hit) \
+ FROM pg_statio_user_tables;"
+
+ Column pg_blks heap_read
+ Column pg_blks heap_hit
+ Column pg_blks idx_read
+ Column pg_blks idx_hit
+ Column pg_blks toast_read
+ Column pg_blks toast_hit
+ Column pg_blks tidx_read
+ Column pg_blks tidx_hit
+</Query>
+
+<Query disk_usage>
+ Query "SELECT pg_database_size($1);"
+
+ Param database
+
+ Column pg_db_size
+</Query>
+
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "powerdns", sizeof (vl.plugin));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* }}} static void submit */
static int powerdns_get_data_dgram (list_item_t *item, /* {{{ */
memset (&sa_unix, 0, sizeof (sa_unix));
sa_unix.sun_family = AF_UNIX;
- strncpy (sa_unix.sun_path,
+ sstrncpy (sa_unix.sun_path,
(local_sockpath != NULL) ? local_sockpath : PDNS_LOCAL_SOCKPATH,
sizeof (sa_unix.sun_path));
- sa_unix.sun_path[sizeof (sa_unix.sun_path) - 1] = 0;
status = unlink (sa_unix.sun_path);
if ((status != 0) && (errno != ENOENT))
}
item->sockaddr.sun_family = AF_UNIX;
- sstrncpy (item->sockaddr.sun_path, socket_temp, UNIX_PATH_MAX);
+ sstrncpy (item->sockaddr.sun_path, socket_temp,
+ sizeof (item->sockaddr.sun_path));
e = llentry_create (item->instance, item);
if (e == NULL)
/**
* collectd - src/processes.c
* Copyright (C) 2005 Lyonel Vincent
- * Copyright (C) 2006-2007 Florian Forster (Mach code)
+ * Copyright (C) 2006-2008 Florian Forster (Mach code)
+ * Copyright (C) 2008 Oleg King
*
* 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:
* Lyonel Vincent <lyonel at ezix.org>
* Florian octo Forster <octo at verplant.org>
+ * Oleg King <king2 at kaluga.ru>
**/
#include "collectd.h"
# endif
/* #endif KERNEL_LINUX */
+#elif HAVE_LIBKVM_GETPROCS
+# include <kvm.h>
+# include <sys/user.h>
+# include <sys/proc.h>
+# if HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+# endif
+/* #endif HAVE_LIBKVM_GETPROCS */
+
#else
# error "No applicable input method."
#endif
+#if HAVE_REGEX_H
+# include <regex.h>
+#endif
+
#define BUFSIZE 256
static const char *config_keys[] =
{
"Process",
- NULL
+ "ProcessMatch"
};
-static int config_keys_num = 1;
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
typedef struct procstat_entry_s
{
typedef struct procstat
{
char name[PROCSTAT_NAME_LEN];
+#if HAVE_REGEX_H
+ regex_t *re;
+#endif
unsigned long num_proc;
unsigned long num_lwp;
#elif KERNEL_LINUX
static long pagesize_g;
-#endif /* KERNEL_LINUX */
+/* #endif KERNEL_LINUX */
-static void ps_list_register (const char *name)
+#elif HAVE_LIBKVM_GETPROCS
+/* no global variables */
+#endif /* HAVE_LIBKVM_GETPROCS */
+
+/* put name of process from config to list_head_g tree
+ list_head_g is a list of 'procstat_t' structs with
+ processes names we want to watch */
+static void ps_list_register (const char *name, const char *regexp)
{
procstat_t *new;
procstat_t *ptr;
+ int status;
- if ((new = (procstat_t *) malloc (sizeof (procstat_t))) == NULL)
+ new = (procstat_t *) malloc (sizeof (procstat_t));
+ if (new == NULL)
+ {
+ ERROR ("processes plugin: ps_list_register: malloc failed.");
return;
+ }
memset (new, 0, sizeof (procstat_t));
- strncpy (new->name, name, PROCSTAT_NAME_LEN);
+ sstrncpy (new->name, name, sizeof (new->name));
+
+#if HAVE_REGEX_H
+ if (regexp != NULL)
+ {
+ DEBUG ("ProcessMatch: adding \"%s\" as criteria to process %s.", regexp, name);
+ new->re = (regex_t *) malloc (sizeof (regex_t));
+ if (new->re == NULL)
+ {
+ ERROR ("processes plugin: ps_list_register: malloc failed.");
+ sfree (new);
+ return;
+ }
+ status = regcomp (new->re, regexp, REG_EXTENDED | REG_NOSUB);
+ if (status != 0)
+ {
+ DEBUG ("ProcessMatch: compiling the regular expression \"%s\" failed.", regexp);
+ sfree(new->re);
+ return;
+ }
+ }
+#else
+ if (regexp != NULL)
+ {
+ ERROR ("processes plugin: ps_list_register: "
+ "Regular expression \"%s\" found in config "
+ "file, but support for regular expressions "
+ "has been dispabled at compile time.",
+ regexp);
+ sfree (new);
+ return;
+ }
+#endif
+
for (ptr = list_head_g; ptr != NULL; ptr = ptr->next)
{
if (strcmp (ptr->name, name) == 0)
+ {
+ WARNING ("processes plugin: You have configured more "
+ "than one `Process' or "
+ "`ProcessMatch' with the same name. "
+ "All but the first setting will be "
+ "ignored.");
+ sfree (new->re);
+ sfree (new);
return;
+ }
+
if (ptr->next == NULL)
break;
}
list_head_g = new;
else
ptr->next = new;
-}
+} /* void ps_list_register */
-static procstat_t *ps_list_search (const char *name)
+/* try to match name against entry, returns 1 if success */
+static int ps_list_match (const char *name, const char *cmdline, procstat_t *ps)
{
- procstat_t *ptr;
+#if HAVE_REGEX_H
+ if (ps->re != NULL)
+ {
+ int status;
+ const char *str;
- for (ptr = list_head_g; ptr != NULL; ptr = ptr->next)
- if (strcmp (ptr->name, name) == 0)
- break;
+ str = cmdline;
+ if ((str == NULL) || (str[0] == 0))
+ str = name;
- return (ptr);
-}
+ assert (str != NULL);
+
+ status = regexec (ps->re, str,
+ /* nmatch = */ 0,
+ /* pmatch = */ NULL,
+ /* eflags = */ 0);
+ if (status == 0)
+ return (1);
+ }
+ else
+#endif
+ if (strcmp (ps->name, name) == 0)
+ return (1);
+
+ return (0);
+} /* int ps_list_match */
-static void ps_list_add (const char *name, procstat_entry_t *entry)
+/* add process entry to 'instances' of process 'name' (or refresh it) */
+static void ps_list_add (const char *name, const char *cmdline, 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))
+ for (ps = list_head_g; ps != NULL; ps = ps->next)
{
- procstat_entry_t *new;
+ if ((ps_list_match (name, cmdline, ps)) == 0)
+ continue;
- new = (procstat_entry_t *) malloc (sizeof (procstat_entry_t));
- if (new == NULL)
- return;
- memset (new, 0, sizeof (procstat_entry_t));
- new->id = entry->id;
+ for (pse = ps->instances; pse != NULL; pse = pse->next)
+ if ((pse->id == entry->id) || (pse->next == NULL))
+ break;
- if (pse == NULL)
- ps->instances = new;
- else
- pse->next = new;
-
- pse = new;
- }
+ 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->age = 0;
- pse->num_proc = entry->num_proc;
- pse->num_lwp = entry->num_lwp;
- pse->vmem_rss = entry->vmem_rss;
+ pse = new;
+ }
- ps->num_proc += pse->num_proc;
- ps->num_lwp += pse->num_lwp;
- ps->vmem_rss += pse->vmem_rss;
+ pse->age = 0;
+ pse->num_proc = entry->num_proc;
+ pse->num_lwp = entry->num_lwp;
+ pse->vmem_rss = entry->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;
+ ps->num_proc += pse->num_proc;
+ ps->num_lwp += pse->num_lwp;
+ ps->vmem_rss += pse->vmem_rss;
- pse->vmem_majflt_counter += entry->vmem_majflt;
- pse->vmem_majflt = entry->vmem_majflt;
- }
- else
- {
- if (entry->vmem_minflt_counter < pse->vmem_minflt_counter)
+ if ((entry->vmem_minflt_counter == 0)
+ && (entry->vmem_majflt_counter == 0))
{
- 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;
+ pse->vmem_minflt_counter += entry->vmem_minflt;
+ pse->vmem_minflt = entry->vmem_minflt;
- if (entry->vmem_majflt_counter < pse->vmem_majflt_counter)
- {
- pse->vmem_majflt = entry->vmem_majflt_counter
- + (ULONG_MAX - pse->vmem_majflt_counter);
+ pse->vmem_majflt_counter += entry->vmem_majflt;
+ pse->vmem_majflt = entry->vmem_majflt;
}
else
{
- pse->vmem_majflt = entry->vmem_majflt_counter - pse->vmem_majflt_counter;
+ 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;
}
- 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;
+ ps->vmem_minflt_counter += pse->vmem_minflt;
+ ps->vmem_majflt_counter += pse->vmem_majflt;
- pse->cpu_system_counter += entry->cpu_system;
- pse->cpu_system = entry->cpu_system;
- }
- else
- {
- if (entry->cpu_user_counter < pse->cpu_user_counter)
+ if ((entry->cpu_user_counter == 0)
+ && (entry->cpu_system_counter == 0))
{
- 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;
+ pse->cpu_user_counter += entry->cpu_user;
+ pse->cpu_user = entry->cpu_user;
- if (entry->cpu_system_counter < pse->cpu_system_counter)
- {
- pse->cpu_system = entry->cpu_system_counter
- + (ULONG_MAX - pse->cpu_system_counter);
+ pse->cpu_system_counter += entry->cpu_system;
+ pse->cpu_system = entry->cpu_system;
}
else
{
- pse->cpu_system = entry->cpu_system_counter - pse->cpu_system_counter;
+ 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;
}
- pse->cpu_system_counter = entry->cpu_system_counter;
- }
- ps->cpu_user_counter += pse->cpu_user;
- ps->cpu_system_counter += pse->cpu_system;
+ ps->cpu_user_counter += pse->cpu_user;
+ ps->cpu_system_counter += pse->cpu_system;
+ }
}
+/* remove old entries from instances of processes in list_head_g */
static void ps_list_reset (void)
{
procstat_t *ps;
} /* for (ps = list_head_g; ps != NULL; ps = ps->next) */
}
+/* put all pre-defined 'Process' names from config to list_head_g tree */
static int ps_config (const char *key, const char *value)
{
if (strcasecmp (key, "Process") == 0)
{
- ps_list_register (value);
+ ps_list_register (value, NULL);
+ }
+ else if (strcasecmp (key, "ProcessMatch") == 0)
+ {
+ char *new_val;
+ char *fields[3];
+ int fields_num;
+
+ new_val = strdup (value);
+ if (new_val == NULL)
+ return (1);
+ fields_num = strsplit (new_val, fields,
+ STATIC_ARRAY_SIZE (fields));
+ if (fields_num != 2)
+ {
+ sfree (new_val);
+ return (1);
+ }
+ ps_list_register (fields[0], fields[1]);
+ sfree (new_val);
}
else
{
pagesize_g = sysconf(_SC_PAGESIZE);
DEBUG ("pagesize_g = %li; CONFIG_HZ = %i;",
pagesize_g, CONFIG_HZ);
-#endif /* KERNEL_LINUX */
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_LIBKVM_GETPROCS
+/* no initialization */
+#endif /* HAVE_LIBKVM_GETPROCS */
return (0);
} /* int ps_init */
+/* submit global state (e.g.: qty of zombies, running, etc..) */
static void ps_submit_state (const char *state, double value)
{
value_t values[1];
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, state, sizeof (vl.type_instance));
+ sstrncpy (vl.type, "ps_state", sizeof (vl.type));
+ sstrncpy (vl.type_instance, state, sizeof (vl.type_instance));
- plugin_dispatch_values ("ps_state", &vl);
+ plugin_dispatch_values (&vl);
}
+/* submit info about specific process (e.g.: memory taken, cpu usage, etc..) */
static void ps_submit_proc_list (procstat_t *ps)
{
value_t values[2];
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance));
+ sstrncpy (vl.plugin_instance, ps->name, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "ps_rss", sizeof (vl.type));
vl.values[0].gauge = ps->vmem_rss;
vl.values_len = 1;
- plugin_dispatch_values ("ps_rss", &vl);
+ plugin_dispatch_values (&vl);
+ sstrncpy (vl.type, "ps_cputime", sizeof (vl.type));
vl.values[0].counter = ps->cpu_user_counter;
vl.values[1].counter = ps->cpu_system_counter;
vl.values_len = 2;
- plugin_dispatch_values ("ps_cputime", &vl);
+ plugin_dispatch_values (&vl);
+ sstrncpy (vl.type, "ps_count", sizeof (vl.type));
vl.values[0].gauge = ps->num_proc;
vl.values[1].gauge = ps->num_lwp;
vl.values_len = 2;
- plugin_dispatch_values ("ps_count", &vl);
+ plugin_dispatch_values (&vl);
+ sstrncpy (vl.type, "ps_pagefaults", sizeof (vl.type));
vl.values[0].counter = ps->vmem_minflt_counter;
vl.values[1].counter = ps->vmem_majflt_counter;
vl.values_len = 2;
- plugin_dispatch_values ("ps_pagefaults", &vl);
+ plugin_dispatch_values (&vl);
DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; vmem_rss = %lu; "
"vmem_minflt_counter = %lu; vmem_majflt_counter = %lu; "
ps->cpu_user_counter, ps->cpu_system_counter);
} /* void ps_submit_proc_list */
+/* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
#if KERNEL_LINUX
static int *ps_read_tasks (int pid)
{
DIR *dh;
struct dirent *ent;
- snprintf (dirname, 64, "/proc/%i/task", pid);
- dirname[63] = '\0';
+ ssnprintf (dirname, sizeof (dirname), "/proc/%i/task", pid);
if ((dh = opendir (dirname)) == NULL)
{
{
char filename[64];
char buffer[1024];
- FILE *fh;
char *fields[64];
char fields_len;
memset (ps, 0, sizeof (procstat_t));
- snprintf (filename, 64, "/proc/%i/stat", pid);
- filename[63] = '\0';
+ ssnprintf (filename, sizeof (filename), "/proc/%i/stat", pid);
- if ((fh = fopen (filename, "r")) == NULL)
+ i = read_file_contents (filename, buffer, sizeof(buffer) - 1);
+ if (i <= 0)
return (-1);
-
- if (fgets (buffer, 1024, fh) == NULL)
- {
- fclose (fh);
- return (-1);
- }
-
- fclose (fh);
+ buffer[i] = 0;
fields_len = strsplit (buffer, fields, 64);
if (fields_len < 24)
return (0);
}
#endif /* HAVE_THREAD_INFO */
+/* ------- end of additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
+/* do actual readings from kernel */
static int ps_read (void)
{
#if HAVE_THREAD_INFO
if (mach_get_task_name (task_list[task],
&task_pid,
task_name, PROCSTAT_NAME_LEN) == 0)
- ps = ps_list_search (task_name);
+ {
+ /* search for at least one match */
+ for (ps = list_head_g; ps != NULL; ps = ps->next)
+ /* FIXME: cmdline should be here instead of NULL */
+ if (ps_list_match (task_name, NULL, ps) == 1)
+ break;
+ }
/* Collect more detailed statistics for this process */
if (ps != NULL)
}
if (ps != NULL)
- ps_list_add (task_name, &pse);
+ /* FIXME: cmdline should be here instead of NULL */
+ ps_list_add (task_name, NULL, &pse);
} /* for (task_list) */
if ((status = vm_deallocate (port_task_self,
case 'W': paging++; break;
}
- ps_list_add (ps.name, &pse);
+ /* FIXME: cmdline should be here instead of NULL */
+ ps_list_add (ps.name, NULL, &pse);
}
closedir (proc);
for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
ps_submit_proc_list (ps_ptr);
-#endif /* KERNEL_LINUX */
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_LIBKVM_GETPROCS
+ int running = 0;
+ int sleeping = 0;
+ int zombies = 0;
+ int stopped = 0;
+ int blocked = 0;
+ int idle = 0;
+ int wait = 0;
+
+ kvm_t *kd;
+ char errbuf[1024];
+ char cmdline[ARG_MAX];
+ char *cmdline_ptr;
+ struct kinfo_proc *procs; /* array of processes */
+ char **argv;
+ int count; /* returns number of processes */
+ int i;
+
+ procstat_t *ps_ptr;
+ procstat_entry_t pse;
+
+ ps_list_reset ();
+
+ /* Open the kvm interface, get a descriptor */
+ kd = kvm_open (NULL, NULL, NULL, 0, errbuf);
+ if (kd == NULL)
+ {
+ ERROR ("processes plugin: Cannot open kvm interface: %s",
+ errbuf);
+ return (0);
+ }
+
+ /* Get the list of processes. */
+ procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count);
+ if (procs == NULL)
+ {
+ kvm_close (kd);
+ ERROR ("processes plugin: Cannot get kvm processes list: %s",
+ kvm_geterr(kd));
+ return (0);
+ }
+
+ /* Iterate through the processes in kinfo_proc */
+ for (i = 0; i < count; i++)
+ {
+ /* retrieve the arguments */
+ cmdline[0] = 0;
+ cmdline_ptr = NULL;
+
+ argv = kvm_getargv (kd, (const struct kinfo_proc *) &(procs[i]), 0);
+ if (argv != NULL)
+ {
+ int status;
+ int argc;
+
+ argc = 0;
+ while (argv[argc] != NULL)
+ argc++;
+
+ status = strjoin (cmdline, sizeof (cmdline),
+ argv, argc, " ");
+
+ if (status < 0)
+ {
+ WARNING ("processes plugin: Command line did "
+ "not fit into buffer.");
+ }
+ else
+ {
+ cmdline_ptr = &cmdline[0];
+ }
+ }
+
+ pse.id = procs[i].ki_pid;
+ pse.age = 0;
+
+ pse.num_proc = 1;
+ pse.num_lwp = procs[i].ki_numthreads;
+
+ pse.vmem_rss = procs[i].ki_rssize * getpagesize();
+ pse.vmem_minflt = 0;
+ pse.vmem_minflt_counter = procs[i].ki_rusage.ru_minflt;
+ pse.vmem_majflt = 0;
+ pse.vmem_majflt_counter = procs[i].ki_rusage.ru_majflt;
+
+ pse.cpu_user = 0;
+ pse.cpu_user_counter = procs[i].ki_rusage.ru_utime.tv_sec
+ * 1000
+ + procs[i].ki_rusage.ru_utime.tv_usec;
+ pse.cpu_system = 0;
+ pse.cpu_system_counter = procs[i].ki_rusage.ru_stime.tv_sec
+ * 1000
+ + procs[i].ki_rusage.ru_stime.tv_usec;
+
+ switch (procs[i].ki_stat)
+ {
+ case SSTOP: stopped++; break;
+ case SSLEEP: sleeping++; break;
+ case SRUN: running++; break;
+ case SIDL: idle++; break;
+ case SWAIT: wait++; break;
+ case SLOCK: blocked++; break;
+ case SZOMB: zombies++; break;
+ }
+
+ ps_list_add (procs[i].ki_comm, cmdline_ptr, &pse);
+ }
+
+ kvm_close(kd);
+
+ ps_submit_state ("running", running);
+ ps_submit_state ("sleeping", sleeping);
+ ps_submit_state ("zombies", zombies);
+ ps_submit_state ("stopped", stopped);
+ ps_submit_state ("blocked", blocked);
+ ps_submit_state ("idle", idle);
+ ps_submit_state ("wait", wait);
+
+ for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
+ ps_submit_proc_list (ps_ptr);
+#endif /* HAVE_LIBKVM_GETPROCS */
return (0);
} /* int ps_read */
/**
* collectd - src/rrdtool.c
- * Copyright (C) 2006,2007 Florian octo Forster
+ * Copyright (C) 2006-2008 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
enum
{
FLAG_NONE = 0x00,
- FLAG_QUEUED = 0x01
+ FLAG_QUEUED = 0x01,
+ FLAG_FLUSHQ = 0x02
} flags;
};
typedef struct rrd_cache_s rrd_cache_t;
+enum rrd_queue_dir_e
+{
+ QUEUE_INSERT_FRONT,
+ QUEUE_INSERT_BACK
+};
+typedef enum rrd_queue_dir_e rrd_queue_dir_t;
+
struct rrd_queue_s
{
char *filename;
"HeartBeat",
"RRARows",
"RRATimespan",
- "XFF"
+ "XFF",
+ "WritesPerSecond"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
static int heartbeat = 0;
static int rrarows = 1200;
static double xff = 0.1;
+static double write_rate = 0.0;
/* XXX: If you need to lock both, cache_lock and queue_lock, at the same time,
* ALWAYS lock `cache_lock' first! */
static rrd_queue_t *queue_head = NULL;
static rrd_queue_t *queue_tail = NULL;
+static rrd_queue_t *flushq_head = NULL;
+static rrd_queue_t *flushq_tail = NULL;
static pthread_t queue_thread = 0;
static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER;
if (rra_num >= rra_max)
break;
- if (snprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
+ if (ssnprintf (buffer, sizeof (buffer), "RRA:%s:%3.1f:%u:%u",
rra_types[j], xff,
cdp_len, cdp_num) >= sizeof (buffer))
{
sstrncpy (min, "U", sizeof (min));
}
else
- {
- snprintf (min, sizeof (min), "%lf", d->min);
- min[sizeof (min) - 1] = '\0';
- }
+ ssnprintf (min, sizeof (min), "%lf", d->min);
if (isnan (d->max))
{
sstrncpy (max, "U", sizeof (max));
}
else
- {
- snprintf (max, sizeof (max), "%lf", d->max);
- max[sizeof (max) - 1] = '\0';
- }
+ ssnprintf (max, sizeof (max), "%lf", d->max);
- status = snprintf (buffer, sizeof (buffer),
+ status = ssnprintf (buffer, sizeof (buffer),
"DS:%s:%s:%i:%s:%s",
d->name, type,
(heartbeat > 0) ? heartbeat : (2 * vl->interval),
#if HAVE_THREADSAFE_LIBRRD
static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
- int argc, char **argv)
+ int argc, const char **argv)
{
int status;
return (status);
} /* int srrd_create */
-static int srrd_update (char *filename, char *template, int argc, char **argv)
+static int srrd_update (char *filename, char *template,
+ int argc, const char **argv)
{
int status;
#else /* !HAVE_THREADSAFE_LIBRRD */
static int srrd_create (char *filename, unsigned long pdp_step, time_t last_up,
- int argc, char **argv)
+ int argc, const char **argv)
{
int status;
if (last_up == 0)
last_up = time (NULL) - 10;
- snprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
- pdp_step_str[sizeof (pdp_step_str) - 1] = '\0';
- snprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
- last_up_str[sizeof (last_up_str) - 1] = '\0';
+ ssnprintf (pdp_step_str, sizeof (pdp_step_str), "%lu", pdp_step);
+ ssnprintf (last_up_str, sizeof (last_up_str), "%u", (unsigned int) last_up);
new_argv[0] = "create";
new_argv[1] = filename;
return (status);
} /* int srrd_create */
-static int srrd_update (char *filename, char *template, int argc, char **argv)
+static int srrd_update (char *filename, char *template,
+ int argc, const char **argv)
{
int status;
status = srrd_create (filename,
(stepsize > 0) ? stepsize : vl->interval,
vl->time - 10,
- argc, argv);
+ argc, (const char **)argv);
free (argv);
ds_free (ds_num, ds_def);
memset (buffer, '\0', buffer_len);
- status = snprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
+ status = ssnprintf (buffer, buffer_len, "%u", (unsigned int) vl->time);
if ((status < 1) || (status >= buffer_len))
return (-1);
offset = status;
return (-1);
if (ds->ds[i].type == DS_TYPE_COUNTER)
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
":%llu", vl->values[i].counter);
else
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
":%lf", vl->values[i].gauge);
if ((status < 1) || (status >= (buffer_len - offset)))
if (datadir != NULL)
{
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s/", datadir);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
}
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s/", vl->host);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
if (strlen (vl->plugin_instance) > 0)
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s-%s/", vl->plugin, vl->plugin_instance);
else
- status = snprintf (buffer + offset, buffer_len - offset,
+ status = ssnprintf (buffer + offset, buffer_len - offset,
"%s/", vl->plugin);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
if (strlen (vl->type_instance) > 0)
- status = snprintf (buffer + offset, buffer_len - offset,
- "%s-%s.rrd", ds->type, vl->type_instance);
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s-%s.rrd", vl->type, vl->type_instance);
else
- status = snprintf (buffer + offset, buffer_len - offset,
- "%s.rrd", ds->type);
+ status = ssnprintf (buffer + offset, buffer_len - offset,
+ "%s.rrd", vl->type);
if ((status < 1) || (status >= buffer_len - offset))
return (-1);
offset += status;
static void *rrd_queue_thread (void *data)
{
+ struct timeval tv_next_update;
+ struct timeval tv_now;
+
+ gettimeofday (&tv_next_update, /* timezone = */ NULL);
+
while (42)
{
rrd_queue_t *queue_entry;
int values_num;
int i;
- /* XXX: If you need to lock both, cache_lock and queue_lock, at
- * the same time, ALWAYS lock `cache_lock' first! */
-
- /* wait until an entry is available */
- pthread_mutex_lock (&queue_lock);
- while ((queue_head == NULL) && (do_shutdown == 0))
- pthread_cond_wait (&queue_cond, &queue_lock);
-
- /* We're in the shutdown phase */
- if (queue_head == NULL)
- {
- pthread_mutex_unlock (&queue_lock);
- break;
- }
-
- /* Dequeue the first entry */
- queue_entry = queue_head;
- if (queue_head == queue_tail)
- queue_head = queue_tail = NULL;
- else
- queue_head = queue_head->next;
+ pthread_mutex_lock (&queue_lock);
+ /* Wait for values to arrive */
+ while (true)
+ {
+ struct timespec ts_wait;
+ int status;
+
+ while ((flushq_head == NULL) && (queue_head == NULL)
+ && (do_shutdown == 0))
+ pthread_cond_wait (&queue_cond, &queue_lock);
+
+ if ((flushq_head == NULL) && (queue_head == NULL))
+ break;
+
+ /* Don't delay if there's something to flush */
+ if (flushq_head != NULL)
+ break;
+
+ /* Don't delay if we're shutting down */
+ if (do_shutdown != 0)
+ break;
+
+ /* Don't delay if no delay was configured. */
+ if (write_rate <= 0.0)
+ break;
+
+ gettimeofday (&tv_now, /* timezone = */ NULL);
+ status = timeval_sub_timespec (&tv_next_update, &tv_now,
+ &ts_wait);
+ /* We're good to go */
+ if (status != 0)
+ break;
+
+ /* We're supposed to wait a bit with this update, so we'll
+ * wait for the next addition to the queue or to the end of
+ * the wait period - whichever comes first. */
+ ts_wait.tv_sec = tv_next_update.tv_sec;
+ ts_wait.tv_nsec = 1000 * tv_next_update.tv_usec;
+
+ status = pthread_cond_timedwait (&queue_cond, &queue_lock,
+ &ts_wait);
+ if (status == ETIMEDOUT)
+ break;
+ } /* while (true) */
+
+ /* XXX: If you need to lock both, cache_lock and queue_lock, at
+ * the same time, ALWAYS lock `cache_lock' first! */
+
+ /* We're in the shutdown phase */
+ if ((flushq_head == NULL) && (queue_head == NULL))
+ {
+ pthread_mutex_unlock (&queue_lock);
+ break;
+ }
+
+ if (flushq_head != NULL)
+ {
+ /* Dequeue the first flush entry */
+ queue_entry = flushq_head;
+ if (flushq_head == flushq_tail)
+ flushq_head = flushq_tail = NULL;
+ else
+ flushq_head = flushq_head->next;
+ }
+ else /* if (queue_head != NULL) */
+ {
+ /* Dequeue the first regular entry */
+ queue_entry = queue_head;
+ if (queue_head == queue_tail)
+ queue_head = queue_tail = NULL;
+ else
+ queue_head = queue_head->next;
+ }
/* Unlock the queue again */
pthread_mutex_unlock (&queue_lock);
pthread_mutex_unlock (&cache_lock);
+ /* Update `tv_next_update' */
+ if (write_rate > 0.0)
+ {
+ gettimeofday (&tv_now, /* timezone = */ NULL);
+ tv_next_update.tv_sec = tv_now.tv_sec;
+ tv_next_update.tv_usec = tv_now.tv_usec
+ + ((suseconds_t) (1000000 * write_rate));
+ while (tv_next_update.tv_usec > 1000000)
+ {
+ tv_next_update.tv_sec++;
+ tv_next_update.tv_usec -= 1000000;
+ }
+ }
+
/* Write the values to the RRD-file */
- srrd_update (queue_entry->filename, NULL, values_num, values);
+ srrd_update (queue_entry->filename, NULL,
+ values_num, (const char **)values);
DEBUG ("rrdtool plugin: queue thread: Wrote %i values to %s",
values_num, queue_entry->filename);
return ((void *) 0);
} /* void *rrd_queue_thread */
-static int rrd_queue_cache_entry (const char *filename)
+static int rrd_queue_enqueue (const char *filename,
+ rrd_queue_t **head, rrd_queue_t **tail)
{
- rrd_queue_t *queue_entry;
+ rrd_queue_t *queue_entry;
- queue_entry = (rrd_queue_t *) malloc (sizeof (rrd_queue_t));
- if (queue_entry == NULL)
- return (-1);
+ queue_entry = (rrd_queue_t *) malloc (sizeof (rrd_queue_t));
+ if (queue_entry == NULL)
+ return (-1);
- queue_entry->filename = strdup (filename);
- if (queue_entry->filename == NULL)
- {
- free (queue_entry);
- return (-1);
- }
+ queue_entry->filename = strdup (filename);
+ if (queue_entry->filename == NULL)
+ {
+ free (queue_entry);
+ return (-1);
+ }
- queue_entry->next = NULL;
+ queue_entry->next = NULL;
- pthread_mutex_lock (&queue_lock);
- if (queue_tail == NULL)
- queue_head = queue_entry;
- else
- queue_tail->next = queue_entry;
- queue_tail = queue_entry;
- pthread_cond_signal (&queue_cond);
- pthread_mutex_unlock (&queue_lock);
+ pthread_mutex_lock (&queue_lock);
- DEBUG ("rrdtool plugin: Put `%s' into the update queue", filename);
+ if (*tail == NULL)
+ *head = queue_entry;
+ else
+ (*tail)->next = queue_entry;
+ *tail = queue_entry;
- return (0);
-} /* int rrd_queue_cache_entry */
+ pthread_cond_signal (&queue_cond);
+ pthread_mutex_unlock (&queue_lock);
+
+ return (0);
+} /* int rrd_queue_enqueue */
+
+static int rrd_queue_dequeue (const char *filename,
+ rrd_queue_t **head, rrd_queue_t **tail)
+{
+ rrd_queue_t *this;
+ rrd_queue_t *prev;
+
+ pthread_mutex_lock (&queue_lock);
+
+ prev = NULL;
+ this = *head;
+
+ while (this != NULL)
+ {
+ if (strcmp (this->filename, filename) == 0)
+ break;
+
+ prev = this;
+ this = this->next;
+ }
+
+ if (this == NULL)
+ {
+ pthread_mutex_unlock (&queue_lock);
+ return (-1);
+ }
+
+ if (prev == NULL)
+ *head = this->next;
+ else
+ prev->next = this->next;
+
+ if (this->next == NULL)
+ *tail = prev;
+
+ pthread_mutex_unlock (&queue_lock);
+
+ sfree (this->filename);
+ sfree (this);
+
+ return (0);
+} /* int rrd_queue_dequeue */
static void rrd_cache_flush (int timeout)
{
iter = c_avl_get_iterator (cache);
while (c_avl_iterator_next (iter, (void *) &key, (void *) &rc) == 0)
{
- if (rc->flags == FLAG_QUEUED)
+ if (rc->flags != FLAG_NONE)
continue;
else if ((now - rc->first_value) < timeout)
continue;
else if (rc->values_num > 0)
{
- if (rrd_queue_cache_entry (key) == 0)
+ int status;
+
+ status = rrd_queue_enqueue (key, &queue_head, &queue_tail);
+ if (status == 0)
rc->flags = FLAG_QUEUED;
}
else /* ancient and no values -> waste of memory */
cache_flush_last = now;
} /* void rrd_cache_flush */
+static int rrd_cache_flush_identifier (int timeout, const char *identifier)
+{
+ rrd_cache_t *rc;
+ time_t now;
+ int status;
+ char key[2048];
+
+ if (identifier == NULL)
+ {
+ rrd_cache_flush (timeout);
+ return (0);
+ }
+
+ now = time (NULL);
+
+ if (datadir == NULL)
+ snprintf (key, sizeof (key), "%s.rrd",
+ identifier);
+ else
+ snprintf (key, sizeof (key), "%s/%s.rrd",
+ datadir, identifier);
+ key[sizeof (key) - 1] = 0;
+
+ status = c_avl_get (cache, key, (void *) &rc);
+ if (status != 0)
+ {
+ WARNING ("rrdtool plugin: rrd_cache_flush_identifier: "
+ "c_avl_get (%s) failed. Does that file really exist?",
+ key);
+ return (status);
+ }
+
+ if (rc->flags == FLAG_FLUSHQ)
+ {
+ status = 0;
+ }
+ else if (rc->flags == FLAG_QUEUED)
+ {
+ rrd_queue_dequeue (key, &queue_head, &queue_tail);
+ status = rrd_queue_enqueue (key, &flushq_head, &flushq_tail);
+ if (status == 0)
+ rc->flags = FLAG_FLUSHQ;
+ }
+ else if ((now - rc->first_value) < timeout)
+ {
+ status = 0;
+ }
+ else if (rc->values_num > 0)
+ {
+ status = rrd_queue_enqueue (key, &flushq_head, &flushq_tail);
+ if (status == 0)
+ rc->flags = FLAG_FLUSHQ;
+ }
+
+ return (status);
+} /* int rrd_cache_flush_identifier */
+
static int rrd_cache_insert (const char *filename,
const char *value, time_t value_time)
{
}
DEBUG ("rrdtool plugin: rrd_cache_insert: file = %s; "
- "values_num = %i; age = %u;",
+ "values_num = %i; age = %lu;",
filename, rc->values_num,
- rc->last_value - rc->first_value);
+ (unsigned long)(rc->last_value - rc->first_value));
if ((rc->last_value - rc->first_value) >= cache_timeout)
{
/* XXX: If you need to lock both, cache_lock and queue_lock, at
* the same time, ALWAYS lock `cache_lock' first! */
- if (rc->flags != FLAG_QUEUED)
+ if (rc->flags == FLAG_NONE)
{
- if (rrd_queue_cache_entry (filename) == 0)
+ int status;
+
+ status = rrd_queue_enqueue (filename, &queue_head, &queue_tail);
+ if (status == 0)
rc->flags = FLAG_QUEUED;
}
else
((time (NULL) - cache_flush_last) > cache_flush_timeout))
rrd_cache_flush (cache_flush_timeout);
-
pthread_mutex_unlock (&cache_lock);
return (0);
char values[512];
int status;
+ if (0 != strcmp (ds->type, vl->type)) {
+ ERROR ("rrdtool plugin: DS type does not match value list type");
+ return -1;
+ }
+
if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
return (-1);
return (status);
} /* int rrd_write */
-static int rrd_flush (const int timeout)
+static int rrd_flush (int timeout, const char *identifier)
{
pthread_mutex_lock (&cache_lock);
return (0);
}
- rrd_cache_flush (timeout);
+ rrd_cache_flush_identifier (timeout, identifier);
+
pthread_mutex_unlock (&cache_lock);
return (0);
} /* int rrd_flush */
}
xff = tmp;
}
+ else if (strcasecmp ("WritesPerSecond", key) == 0)
+ {
+ double wps = atof (value);
+
+ if (wps < 0.0)
+ {
+ fprintf (stderr, "rrdtool: `WritesPerSecond' must be "
+ "greater than or equal to zero.");
+ return (1);
+ }
+ else if (wps == 0.0)
+ {
+ write_rate = 0.0;
+ }
+ else
+ {
+ write_rate = 1.0 / wps;
+ }
+ }
else
{
return (-1);
if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA)
{
- status = snprintf (buf, buf_size,
+ status = ssnprintf (buf, buf_size,
"%s-isa-%04x",
chip->prefix,
chip->addr);
value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- status = snprintf (match_key, sizeof (match_key), "%s/%s-%s",
+ status = ssnprintf (match_key, sizeof (match_key), "%s/%s-%s",
plugin_instance, type, type_instance);
if (status < 1)
return;
- match_key[sizeof (match_key) - 1] = '\0';
if (sensor_list != NULL)
{
vl.values_len = 1;
vl.time = time (NULL);
- strncpy (vl.host, hostname_g, sizeof (vl.host));
- vl.host[sizeof (vl.host) - 1] = '\0';
- strncpy (vl.plugin, "sensors", sizeof (vl.plugin));
- vl.plugin[sizeof (vl.plugin) - 1] = '\0';
- strncpy (vl.plugin_instance, plugin_instance,
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "sensors", sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, plugin_instance,
sizeof (vl.plugin_instance));
- vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ 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 sensors_submit */
static int sensors_read (void)
sizeof (plugin_instance), fl->chip);
if (status < 0)
continue;
- plugin_instance[sizeof (plugin_instance) - 1] = '\0';
- strncpy (type_instance, fl->data->name,
+ sstrncpy (type_instance, fl->data->name,
sizeof (type_instance));
- type_instance[sizeof (type_instance) - 1] = '\0';
sensors_submit (plugin_instance,
sensor_type_name_map[fl->type],
sizeof (plugin_instance), fl->chip);
if (status < 0)
continue;
- plugin_instance[sizeof (plugin_instance) - 1] = '\0';
- strncpy (type_instance, fl->feature->name,
+ sstrncpy (type_instance, fl->feature->name,
sizeof (type_instance));
- type_instance[sizeof (type_instance) - 1] = '\0';
if (fl->feature->type == SENSORS_FEATURE_IN)
type = "voltage";
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "serial", sizeof (vl.plugin));
- strncpy (vl.type_instance, type_instance,
+ sstrncpy (vl.type, "serial_octets", sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance,
sizeof (vl.type_instance));
- plugin_dispatch_values ("serial_octets", &vl);
+ plugin_dispatch_values (&vl);
}
static int serial_read (void)
else
{
/* Instance is a simple string */
- strncpy (dd->instance.string, ci->values[0].value.string, DATA_MAX_NAME_LEN - 1);
+ sstrncpy (dd->instance.string, ci->values[0].value.string,
+ sizeof (dd->instance.string));
}
return (0);
temp += (uint32_t) vl->val.counter64->low;
DEBUG ("snmp plugin: Parsed int64 value is %"PRIu64".", temp);
}
+ else if (vl->type == ASN_OCTET_STR)
+ {
+ /* We'll handle this later.. */
+ }
else
{
WARNING ("snmp plugin: I don't know the ASN type `%i'", (int) vl->type);
defined = 0;
}
- if (type == DS_TYPE_COUNTER)
+ if (vl->type == ASN_OCTET_STR)
+ {
+ char *endptr;
+
+ endptr = NULL;
+ if (vl->val.string != NULL)
+ {
+ char string[64];
+ size_t string_length;
+
+ string_length = sizeof (string) - 1;
+ if (vl->val_len < string_length)
+ string_length = vl->val_len;
+
+ /* The strings we get from the Net-SNMP library may not be null
+ * terminated. That is why we're using `membpy' here and not `strcpy'.
+ * `string_length' is set to `vl->val_len' which holds the length of the
+ * string. -octo */
+ memcpy (string, vl->val.string, string_length);
+ string[string_length] = 0;
+
+ if (type == DS_TYPE_COUNTER)
+ {
+ ret.counter = (counter_t) strtoll (string, &endptr, /* base = */ 0);
+ DEBUG ("snmp plugin: csnmp_value_list_to_value: String to counter: %s -> %llu",
+ string, (unsigned long long) ret.counter);
+ }
+ else if (type == DS_TYPE_GAUGE)
+ {
+ ret.gauge = (gauge_t) strtod (string, &endptr);
+ DEBUG ("snmp plugin: csnmp_value_list_to_value: String to gauge: %s -> %g",
+ string, (double) ret.gauge);
+ }
+ }
+
+ /* Check if an error occurred */
+ if ((vl->val.string == NULL) || (endptr == (char *) vl->val.string))
+ {
+ if (type == DS_TYPE_COUNTER)
+ ret.counter = 0;
+ else if (type == DS_TYPE_GAUGE)
+ ret.gauge = NAN;
+ }
+ }
+ else if (type == DS_TYPE_COUNTER)
{
ret.counter = temp;
}
char *ptr;
size_t instance_len;
+ memset (il->instance, 0, sizeof (il->instance));
instance_len = sizeof (il->instance) - 1;
if (instance_len > vb->val_len)
instance_len = vb->val_len;
- strncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
+ sstrncpy (il->instance, (char *) ((vb->type == ASN_OCTET_STR)
? vb->val.string
: vb->val.bitstring),
- instance_len);
- il->instance[instance_len] = '\0';
+ instance_len + 1);
for (ptr = il->instance; *ptr != '\0'; ptr++)
{
else
{
value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER, 1.0, 0.0);
- snprintf (il->instance, sizeof (il->instance),
+ ssnprintf (il->instance, sizeof (il->instance),
"%llu", val.counter);
}
- il->instance[sizeof (il->instance) - 1] = '\0';
/* TODO: Debugging output */
return (-1);
}
- strncpy (vl.host, host->name, sizeof (vl.host));
- vl.host[sizeof (vl.host) - 1] = '\0';
+ sstrncpy (vl.host, host->name, sizeof (vl.host));
sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
vl.interval = host->interval;
|| (instance_list_ptr->subid == value_table_ptr[0]->subid));
#endif
+ sstrncpy (vl.type, data->type, sizeof (vl.type));
+
{
char temp[DATA_MAX_NAME_LEN];
if (instance_list_ptr == NULL)
- snprintf (temp, sizeof (temp), "%u",
- (uint32_t) subid);
+ ssnprintf (temp, sizeof (temp), "%u", (uint32_t) subid);
else
- strncpy (temp, instance_list_ptr->instance,
- sizeof (temp));
- temp[sizeof (temp) - 1] = '\0';
+ sstrncpy (temp, instance_list_ptr->instance, sizeof (temp));
if (data->instance_prefix == NULL)
- strncpy (vl.type_instance, temp, sizeof (vl.type_instance));
+ sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance));
else
- snprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
data->instance_prefix, temp);
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
}
for (i = 0; i < data->values_len; i++)
vl.values[i] = value_table_ptr[i]->value;
/* If we get here `vl.type_instance' and all `vl.values' have been set */
- plugin_dispatch_values (data->type, &vl);
+ plugin_dispatch_values (&vl);
subid++;
} /* while (have_more != 0) */
vl.values[i].gauge = NAN;
}
- strncpy (vl.host, host->name, sizeof (vl.host));
- vl.host[sizeof (vl.host) - 1] = '\0';
+ sstrncpy (vl.host, host->name, sizeof (vl.host));
sstrncpy (vl.plugin, "snmp", sizeof (vl.plugin));
- strncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ sstrncpy (vl.type, data->type, sizeof (vl.type));
+ sstrncpy (vl.type_instance, data->instance.string, sizeof (vl.type_instance));
vl.interval = host->interval;
snmp_free_pdu (res);
res = NULL;
- DEBUG ("snmp plugin: -> plugin_dispatch_values (%s, &vl);", data->type);
- plugin_dispatch_values (data->type, &vl);
+ DEBUG ("snmp plugin: -> plugin_dispatch_values (&vl);");
+ plugin_dispatch_values (&vl);
sfree (vl.values);
return (0);
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "swap", sizeof (vl.plugin));
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.type, "swap", sizeof (vl.type));
+ 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)
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "tape", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, plugin_instance,
+ sstrncpy (vl.plugin_instance, plugin_instance,
sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void tape_submit */
static int tape_read (void)
* Florian octo Forster <octo at verplant.org>
**/
+/**
+ * Code within `HAVE_LIBKVM_NLIST' blocks is provided under the following
+ * license:
+ *
+ * $collectd: parts of tcpconns.c, 2008/08/08 03:48:30 Michael Stapelberg $
+ * $OpenBSD: inet.c,v 1.100 2007/06/19 05:28:30 ray Exp $
+ * $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $
+ *
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
#include "collectd.h"
#include "common.h"
#include "plugin.h"
-#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME
+#if !KERNEL_LINUX && !HAVE_SYSCTLBYNAME && !HAVE_LIBKVM_NLIST
# error "No applicable input method."
#endif
# include <netinet/tcpip.h>
# include <netinet/tcp_seq.h>
# include <netinet/tcp_var.h>
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+/* This is for OpenBSD and possibly NetBSD. */
+#elif HAVE_LIBKVM_NLIST
+# include <sys/queue.h>
+# include <sys/socket.h>
+# include <net/route.h>
+# include <netinet/in.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# include <netinet/in_pcb.h>
+# include <netinet/tcp.h>
+# include <netinet/tcp_timer.h>
+# include <netinet/tcp_var.h>
+# include <netdb.h>
+# include <arpa/inet.h>
+# include <nlist.h>
+# include <kvm.h>
+#endif /* HAVE_LIBKVM_NLIST */
#if KERNEL_LINUX
static const char *tcp_state[] =
# define TCP_STATE_LISTEN 1
# define TCP_STATE_MIN 0
# define TCP_STATE_MAX 10
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+static const char *tcp_state[] =
+{
+ "CLOSED",
+ "LISTEN",
+ "SYN_SENT",
+ "SYN_RECV",
+ "ESTABLISHED",
+ "CLOSE_WAIT",
+ "FIN_WAIT1",
+ "CLOSING",
+ "LAST_ACK",
+ "FIN_WAIT2",
+ "TIME_WAIT"
+};
+
+static kvm_t *kvmd;
+static u_long inpcbtable_off = 0;
+struct inpcbtable *inpcbtable_ptr = NULL;
+
+# define TCP_STATE_LISTEN 1
+# define TCP_STATE_MIN 1
+# define TCP_STATE_MAX 10
+#endif /* HAVE_LIBKVM_NLIST */
#define PORT_COLLECT_LOCAL 0x01
#define PORT_COLLECT_REMOTE 0x02
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "tcpconns", sizeof (vl.plugin));
+ sstrncpy (vl.type, "tcp_connections", sizeof (vl.type));
if (((port_collect_listening != 0) && (pe->flags & PORT_IS_LISTENING))
|| (pe->flags & PORT_COLLECT_LOCAL))
{
- snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
"%"PRIu16"-local", pe->port);
- vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
for (i = 1; i <= TCP_STATE_MAX; i++)
{
vl.values[0].gauge = pe->count_local[i];
- strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ sstrncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
- plugin_dispatch_values ("tcp_connections", &vl);
+ plugin_dispatch_values (&vl);
}
}
if (pe->flags & PORT_COLLECT_REMOTE)
{
- snprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
+ ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance),
"%"PRIu16"-remote", pe->port);
- vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
for (i = 1; i <= TCP_STATE_MAX; i++)
{
vl.values[0].gauge = pe->count_remote[i];
- strncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
+ sstrncpy (vl.type_instance, tcp_state[i], sizeof (vl.type_instance));
- plugin_dispatch_values ("tcp_connections", &vl);
+ plugin_dispatch_values (&vl);
}
}
} /* void conn_submit */
/* #endif KERNEL_LINUX */
#elif HAVE_SYSCTLBYNAME
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+#endif /* HAVE_LIBKVM_NLIST */
static int conn_config (const char *key, const char *value)
{
return (0);
} /* int conn_read */
-#endif /* HAVE_SYSCTLBYNAME */
+/* #endif HAVE_SYSCTLBYNAME */
+
+#elif HAVE_LIBKVM_NLIST
+static int kread (u_long addr, void *buf, int size)
+{
+ int status;
+
+ status = kvm_read (kvmd, addr, buf, size);
+ if (status != size)
+ {
+ ERROR ("tcpconns plugin: kvm_read failed (got %i, expected %i): %s\n",
+ status, size, kvm_geterr (kvmd));
+ return (-1);
+ }
+ return (0);
+} /* int kread */
+
+static int conn_init (void)
+{
+ char buf[_POSIX2_LINE_MAX];
+ struct nlist nl[] =
+ {
+#define N_TCBTABLE 0
+ { "_tcbtable" },
+ { "" }
+ };
+ int status;
+
+ kvmd = kvm_openfiles (NULL, NULL, NULL, O_RDONLY, buf);
+ if (kvmd == NULL)
+ {
+ ERROR ("tcpconns plugin: kvm_openfiles failed: %s", buf);
+ return (-1);
+ }
+
+ status = kvm_nlist (kvmd, nl);
+ if (status < 0)
+ {
+ ERROR ("tcpconns plugin: kvm_nlist failed with status %i.", status);
+ return (-1);
+ }
+
+ if (nl[N_TCBTABLE].n_type == 0)
+ {
+ ERROR ("tcpconns plugin: Error looking up kernel's namelist: "
+ "N_TCBTABLE is invalid.");
+ return (-1);
+ }
+
+ inpcbtable_off = (u_long) nl[N_TCBTABLE].n_value;
+ inpcbtable_ptr = (struct inpcbtable *) nl[N_TCBTABLE].n_value;
+
+ return (0);
+} /* int conn_init */
+
+static int conn_read (void)
+{
+ struct inpcbtable table;
+ struct inpcb *head;
+ struct inpcb *next;
+ struct inpcb inpcb;
+ struct tcpcb tcpcb;
+ int status;
+
+ conn_reset_port_entry ();
+
+ /* Read the pcbtable from the kernel */
+ status = kread (inpcbtable_off, &table, sizeof (table));
+ if (status != 0)
+ return (-1);
+
+ /* Get the `head' pcb */
+ head = (struct inpcb *) &(inpcbtable_ptr->inpt_queue);
+ /* Get the first pcb */
+ next = CIRCLEQ_FIRST (&table.inpt_queue);
+
+ while (next != head)
+ {
+ /* Read the pcb pointed to by `next' into `inpcb' */
+ kread ((u_long) next, &inpcb, sizeof (inpcb));
+
+ /* Advance `next' */
+ next = CIRCLEQ_NEXT (&inpcb, inp_queue);
+
+ /* Ignore sockets, that are not connected. */
+ if (!(inpcb.inp_flags & INP_IPV6)
+ && (inet_lnaof(inpcb.inp_laddr) == INADDR_ANY))
+ continue;
+ if ((inpcb.inp_flags & INP_IPV6)
+ && IN6_IS_ADDR_UNSPECIFIED (&inpcb.inp_laddr6))
+ continue;
+
+ kread ((u_long) inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
+ conn_handle_ports (ntohs(inpcb.inp_lport), ntohs(inpcb.inp_fport), tcpcb.t_state);
+ } /* while (next != head) */
+
+ conn_submit_all ();
+
+ return (0);
+}
+#endif /* HAVE_LIBKVM_NLIST */
void module_register (void)
{
config_keys, config_keys_num);
#if KERNEL_LINUX
plugin_register_init ("tcpconns", conn_init);
+#elif HAVE_SYSCTLBYNAME
+ /* no initialization */
+#elif HAVE_LIBKVM_NLIST
+ plugin_register_init ("tcpconns", conn_init);
#endif
plugin_register_read ("tcpconns", conn_read);
} /* void module_register */
/*
- * vim: set shiftwidth=2 softtabstop=2 tabstop=8 :
+ * vim: set shiftwidth=2 softtabstop=2 tabstop=8 fdm=marker :
*/
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 (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void tss2_submit_gauge */
static void tss2_submit_io (const char *plugin_instance, const char *type,
if (plugin_instance != NULL)
sstrncpy (vl.plugin_instance, plugin_instance,
sizeof (vl.plugin_instance));
-
- plugin_dispatch_values (type, &vl);
+
+ sstrncpy (vl.type, type, sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
} /* void tss2_submit_gauge */
static void tss2_close_socket (void)
int status;
/* Send request */
- snprintf (command, sizeof (command), "sel %i\r\n", vserver->port);
- command[sizeof (command) - 1] = 0;
+ ssnprintf (command, sizeof (command), "sel %i\r\n", vserver->port);
status = tss2_send_request (write_fh, command);
if (status != 0)
else
{
/* Request server information */
- snprintf (plugin_instance, sizeof (plugin_instance), "vserver%i",
+ ssnprintf (plugin_instance, sizeof (plugin_instance), "vserver%i",
vserver->port);
- plugin_instance[sizeof (plugin_instance) - 1] = 0;
/* Select the server */
status = tss2_select_vserver (read_fh, write_fh, vserver);
--- /dev/null
+/**
+ * collectd - src/thermal.c
+ * Copyright (C) 2008 Michał Mirosław
+ *
+ * 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:
+ * Michał Mirosław <mirq-linux at rere.qmqm.pl>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_ignorelist.h"
+
+#if !KERNEL_LINUX
+# error "This module is for Linux only."
+#endif
+
+const char *const dirname_sysfs = "/sys/class/thermal";
+const char *const dirname_procfs = "/proc/acpi/thermal_zone";
+
+static char force_procfs = 0;
+static ignorelist_t *device_list;
+static value_list_t vl_temp_template = VALUE_LIST_STATIC;
+static value_list_t vl_state_template = VALUE_LIST_STATIC;
+
+enum dev_type {
+ TEMP = 0,
+ COOLING_DEV
+};
+
+static void thermal_submit (const char *plugin_instance, enum dev_type dt,
+ gauge_t value)
+{
+ value_list_t vl = (dt == TEMP) ? vl_temp_template : vl_state_template;
+ value_t vt;
+
+ vt.gauge = value;
+
+ vl.values = &vt;
+ vl.time = time (NULL);
+ sstrncpy (vl.plugin, "thermal", sizeof(vl.plugin));
+ sstrncpy (vl.plugin_instance, plugin_instance,
+ sizeof(vl.plugin_instance));
+ sstrncpy (vl.type, (dt == TEMP) ? "temperature" : "gauge",
+ sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+}
+
+static int thermal_sysfs_device_read (const char *dir, const char *name,
+ void *user_data)
+{
+ char filename[256];
+ char data[1024];
+ int len;
+ int ok = 0;
+
+ if (device_list && ignorelist_match (device_list, name))
+ return -1;
+
+ len = snprintf (filename, sizeof (filename), "%s/%s/temp", dirname_sysfs, name);
+ if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+ return -1;
+
+ len = read_file_contents (filename, data, sizeof(data));
+ if (len > 1 && data[--len] == '\n') {
+ char *endptr = NULL;
+ double temp;
+
+ data[len] = 0;
+ errno = 0;
+ temp = strtod (data, &endptr) / 1000.0;
+
+ if (endptr == data + len && errno == 0) {
+ thermal_submit(name, TEMP, temp);
+ ++ok;
+ }
+ }
+
+ len = snprintf (filename, sizeof (filename), "%s/%s/cur_state", dirname_sysfs, name);
+ if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+ return -1;
+
+ len = read_file_contents (filename, data, sizeof(data));
+ if (len > 1 && data[--len] == '\n') {
+ char *endptr = NULL;
+ double state;
+
+ data[len] = 0;
+ errno = 0;
+ state = strtod (data, &endptr);
+
+ if (endptr == data + len && errno == 0) {
+ thermal_submit(name, COOLING_DEV, state);
+ ++ok;
+ }
+ }
+
+ return ok ? 0 : -1;
+}
+
+static int thermal_procfs_device_read (const char *dir, const char *name,
+ void *user_data)
+{
+ const char str_temp[] = "temperature:";
+ char filename[256];
+ char data[1024];
+ int len;
+
+ if (device_list && ignorelist_match (device_list, name))
+ return -1;
+
+ /**
+ * rechot ~ # cat /proc/acpi/thermal_zone/THRM/temperature
+ * temperature: 55 C
+ */
+
+ len = snprintf (filename, sizeof (filename), "%s/%s/temperature", dirname_procfs, name);
+ if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
+ return -1;
+
+ len = read_file_contents (filename, data, sizeof(data));
+ if (len > sizeof(str_temp) && data[--len] == '\n' && !strncmp(data, str_temp, sizeof(str_temp)-1)) {
+ char *endptr = NULL;
+ double temp;
+ double celsius, add;
+
+ if (data[--len] == 'C') {
+ add = 0;
+ celsius = 1;
+ } else if (data[len] == 'F') {
+ add = -32;
+ celsius = 5/9;
+ } else if (data[len] == 'K') {
+ add = -273.15;
+ celsius = 1;
+ } else
+ return -1;
+
+ while (len > 0 && data[--len] == ' ')
+ ;
+ data[len + 1] = 0;
+
+ while (len > 0 && data[--len] != ' ')
+ ;
+ ++len;
+
+ errno = 0;
+ temp = (strtod (data + len, &endptr) + add) * celsius;
+
+ if (endptr != data + len && errno == 0) {
+ thermal_submit(name, TEMP, temp);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static const char *config_keys[] = {
+ "Device",
+ "IgnoreSelected",
+ "ForceUseProcfs"
+};
+
+static int thermal_config (const char *key, const char *value)
+{
+ if (device_list == NULL)
+ device_list = ignorelist_create (1);
+
+ if (strcasecmp (key, "Device") == 0)
+ {
+ if (ignorelist_add (device_list, value))
+ {
+ ERROR ("thermal plugin: "
+ "Cannot add value to ignorelist.");
+ return 1;
+ }
+ }
+ else if (strcasecmp (key, "IgnoreSelected") == 0)
+ {
+ ignorelist_set_invert (device_list, 1);
+ if ((strcasecmp (value, "True") == 0)
+ || (strcasecmp (value, "Yes") == 0)
+ || (strcasecmp (value, "On") == 0))
+ ignorelist_set_invert (device_list, 0);
+ }
+ else if (strcasecmp (key, "ForceUseProcfs") == 0)
+ {
+ force_procfs = 0;
+ if ((strcasecmp (value, "True") == 0)
+ || (strcasecmp (value, "Yes") == 0)
+ || (strcasecmp (value, "On") == 0))
+ force_procfs = 1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int thermal_sysfs_read (void)
+{
+ return walk_directory (dirname_sysfs, thermal_sysfs_device_read,
+ /* user_data = */ NULL);
+}
+
+static int thermal_procfs_read (void)
+{
+ return walk_directory (dirname_procfs, thermal_procfs_device_read,
+ /* user_data = */ NULL);
+}
+
+static int thermal_init (void)
+{
+ int ret = -1;
+
+ if (!force_procfs && access (dirname_sysfs, R_OK | X_OK) == 0) {
+ ret = plugin_register_read ("thermal", thermal_sysfs_read);
+ } else if (access (dirname_procfs, R_OK | X_OK) == 0) {
+ ret = plugin_register_read ("thermal", thermal_procfs_read);
+ }
+
+ if (!ret) {
+ vl_temp_template.values_len = 1;
+ vl_temp_template.interval = interval_g;
+ sstrncpy (vl_temp_template.host, hostname_g,
+ sizeof(vl_temp_template.host));
+ sstrncpy (vl_temp_template.plugin, "thermal",
+ sizeof(vl_temp_template.plugin));
+ sstrncpy (vl_temp_template.type_instance, "temperature",
+ sizeof(vl_temp_template.type_instance));
+
+ vl_state_template = vl_temp_template;
+ sstrncpy (vl_state_template.type_instance, "cooling_state",
+ sizeof(vl_state_template.type_instance));
+ }
+
+ return ret;
+}
+
+static int thermal_shutdown (void)
+{
+ ignorelist_free (device_list);
+
+ return 0;
+}
+
+void module_register (void)
+{
+ plugin_register_config ("thermal", thermal_config,
+ config_keys, STATIC_ARRAY_SIZE(config_keys));
+ plugin_register_init ("thermal", thermal_init);
+ plugin_register_shutdown ("thermal", thermal_shutdown);
+}
+
apache_requests count:COUNTER:0:134217728
apache_scoreboard count:GAUGE:0:65535
bitrate value:GAUGE:0:4294967295
+bytes value:GAUGE:0:U
cache_result value:COUNTER:0:4294967295
-cache_size value:GAUGE:0:4294967295
+cache_size value:GAUGE:0:4294967295
charge value:GAUGE:0:U
connections value:COUNTER:0:U
counter value:COUNTER:U:U
email_size value:GAUGE:0:U
entropy entropy:GAUGE:0:4294967295
fanspeed value:GAUGE:0:U
+files value:GAUGE:0:U
frequency frequency:GAUGE:0:U
frequency_offset ppm:GAUGE:-1000000:1000000
gauge value:GAUGE:U:U
nginx_connections value:GAUGE:0:U
nginx_requests value:COUNTER:0:134217728
percent percent:GAUGE:0:100.1
+pg_blks value:COUNTER:0:U
+pg_db_size value:GAUGE:0:U
+pg_n_tup_c value:COUNTER:0:U
+pg_n_tup_g value:GAUGE:0:U
+pg_numbackends value:GAUGE:0:U
+pg_scan value:COUNTER:0:U
+pg_xact value:COUNTER:0:U
ping ping:GAUGE:0:65535
players value:GAUGE:0:1000000
power value:GAUGE:0:U
if (buf_len < 11)
{
- ERROR ("parse_ds: (buf_len = %u) < 11", buf_len);
+ ERROR ("parse_ds: (buf_len = %zu) < 11", buf_len);
return (-1);
}
return (-1);
}
- strncpy (dsrc->name, fields[0], sizeof (dsrc->name));
- dsrc->name[sizeof (dsrc->name) - 1] = '\0';
+ sstrncpy (dsrc->name, fields[0], sizeof (dsrc->name));
if (strcasecmp (fields[1], "GAUGE") == 0)
dsrc->type = DS_TYPE_GAUGE;
memset (ds, '\0', sizeof (data_set_t));
- strncpy (ds->type, fields[0], sizeof (ds->type));
- ds->type[sizeof (ds->type) - 1] = '\0';
+ sstrncpy (ds->type, fields[0], sizeof (ds->type));
ds->ds_num = fields_num - 1;
ds->ds = (data_source_t *) calloc (ds->ds_num, sizeof (data_source_t));
memset (&sa, '\0', sizeof (sa));
sa.sun_family = AF_UNIX;
- strncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
- sizeof (sa.sun_path) - 1);
+ sstrncpy (sa.sun_path, (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
+ sizeof (sa.sun_path));
/* unlink (sa.sun_path); */
DEBUG ("unixsock plugin: socket path = %s", sa.sun_path);
{
int fd;
FILE *fhin, *fhout;
- char buffer[1024];
- char *fields[128];
- int fields_num;
fd = *((int *) arg);
free (arg);
arg = NULL;
- DEBUG ("Reading from fd #%i", fd);
+ DEBUG ("unixsock plugin: us_handle_client: Reading from fd #%i", fd);
fhin = fdopen (fd, "r");
if (fhin == NULL)
while (42)
{
- int len;
+ char buffer[1024];
+ char buffer_copy[1024];
+ char *fields[128];
+ int fields_num;
+ int len;
errno = 0;
if (fgets (buffer, sizeof (buffer), fhin) == NULL)
if (len == 0)
continue;
- DEBUG ("fgets -> buffer = %s; len = %i;", buffer, len);
+ sstrncpy (buffer_copy, buffer, sizeof (buffer_copy));
- fields_num = strsplit (buffer, fields,
+ fields_num = strsplit (buffer_copy, fields,
sizeof (fields) / sizeof (fields[0]));
if (fields_num < 1)
if (strcasecmp (fields[0], "getval") == 0)
{
- handle_getval (fhout, fields, fields_num);
+ handle_getval (fhout, buffer);
}
else if (strcasecmp (fields[0], "putval") == 0)
{
- handle_putval (fhout, fields, fields_num);
+ handle_putval (fhout, buffer);
}
else if (strcasecmp (fields[0], "listval") == 0)
{
- handle_listval (fhout, fields, fields_num);
+ handle_listval (fhout, buffer);
}
else if (strcasecmp (fields[0], "putnotif") == 0)
{
- handle_putnotif (fhout, fields, fields_num);
+ handle_putnotif (fhout, buffer);
}
else if (strcasecmp (fields[0], "flush") == 0)
{
- handle_flush (fhout, fields, fields_num);
+ handle_flush (fhout, buffer);
}
else
{
}
} /* while (fgets) */
- DEBUG ("Exiting..");
+ DEBUG ("unixsock plugin: us_handle_client: Exiting..");
fclose (fhin);
fclose (fhout);
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "users", sizeof (vl.plugin));
+ sstrncpy (vl.type, "users", sizeof (vl.plugin));
- plugin_dispatch_values ("users", &vl);
+ plugin_dispatch_values (&vl);
} /* void users_submit */
static int users_read (void)
return (-1);
}
- snprintf (n.message, sizeof (n.message),
+ ssnprintf (n.message, sizeof (n.message),
"%s has not been updated for %i seconds.", name,
(int) (n.time - ce->last_update));
pthread_mutex_unlock (&cache_lock);
- n.message[sizeof (n.message) - 1] = '\0';
plugin_dispatch_notification (&n);
return (0);
}
else
{
- WARNING ("uc_check_timeout: ut_check_interesting (%s) returned ",
+ WARNING ("uc_check_timeout: ut_check_interesting (%s) returned "
"invalid status %i.",
keys[i], status);
}
n.severity = NOTIF_OKAY;
n.time = vl->time;
- snprintf (n.message, sizeof (n.message),
+ ssnprintf (n.message, sizeof (n.message),
"Received a value for %s. It was missing for %u seconds.",
name, (unsigned int) update_delay);
- n.message[sizeof (n.message) - 1] = '\0';
plugin_dispatch_notification (&n);
if (ret_num != ds->ds_num)
{
ERROR ("utils_cache: uc_get_rate: ds[%s] has %i values, "
- "but uc_get_rate_by_name returned %i.",
+ "but uc_get_rate_by_name returned %zu.",
ds->type, ds->ds_num, ret_num);
sfree (ret);
return (NULL);
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include "utils_parse_option.h"
#define print_to_socket(fh, ...) \
if (fprintf (fh, __VA_ARGS__) < 0) { \
return -1; \
}
-int handle_flush (FILE *fh, char **fields, int fields_num)
+static int add_to_array (char ***array, int *array_num, char *value)
+{
+ char **temp;
+
+ temp = (char **) realloc (*array, sizeof (char *) * (*array_num + 1));
+ if (temp == NULL)
+ return (-1);
+
+ *array = temp;
+ (*array)[*array_num] = value;
+ (*array_num)++;
+
+ return (0);
+} /* int add_to_array */
+
+int handle_flush (FILE *fh, char *buffer)
{
int success = 0;
int error = 0;
int timeout = -1;
+ char **plugins = NULL;
+ int plugins_num = 0;
+ char **identifiers = NULL;
+ int identifiers_num = 0;
int i;
- for (i = 1; i < fields_num; i++)
+ if ((fh == NULL) || (buffer == NULL))
+ return (-1);
+
+ DEBUG ("utils_cmd_flush: handle_flush (fh = %p, buffer = %s);",
+ (void *) fh, buffer);
+
+ if (strncasecmp ("FLUSH", buffer, strlen ("FLUSH")) != 0)
{
- char *option = fields[i];
- int status = 0;
+ print_to_socket (fh, "-1 Cannot parse command.\n");
+ return (-1);
+ }
+ buffer += strlen ("FLUSH");
+
+ while (*buffer != 0)
+ {
+ char *opt_key;
+ char *opt_value;
+ int status;
- if (strncasecmp ("plugin=", option, strlen ("plugin=")) == 0)
+ opt_key = NULL;
+ opt_value = NULL;
+ status = parse_option (&buffer, &opt_key, &opt_value);
+ if (status != 0)
{
- char *plugin = option + strlen ("plugin=");
+ print_to_socket (fh, "-1 Parsing options failed.\n");
+ sfree (plugins);
+ sfree (identifiers);
+ return (-1);
+ }
- if (0 == plugin_flush_one (timeout, plugin))
- ++success;
- else
- ++error;
+ if (strcasecmp ("plugin", opt_key) == 0)
+ {
+ add_to_array (&plugins, &plugins_num, opt_value);
}
- else if (strncasecmp ("timeout=", option, strlen ("timeout=")) == 0)
+ else if (strcasecmp ("identifier", opt_key) == 0)
{
- char *endptr = NULL;
- char *value = option + strlen ("timeout=");
-
+ add_to_array (&identifiers, &identifiers_num, opt_value);
+ }
+ else if (strcasecmp ("timeout", opt_key) == 0)
+ {
+ char *endptr;
+
errno = 0;
- timeout = strtol (value, &endptr, 0);
+ endptr = NULL;
+ timeout = strtol (opt_value, &endptr, 0);
- if ((endptr == value) || (0 != errno))
- status = -1;
- else if (0 >= timeout)
+ if ((endptr == opt_value) || (errno != 0))
+ {
+ print_to_socket (fh, "-1 Invalid value for option `timeout': "
+ "%s\n", opt_value);
+ sfree (plugins);
+ sfree (identifiers);
+ return (-1);
+ }
+ else if (timeout <= 0)
timeout = -1;
}
else
- status = -1;
-
- if (status != 0)
{
- print_to_socket (fh, "-1 Cannot parse option %s\n", option);
+ print_to_socket (fh, "-1 Cannot parse option %s\n", opt_key);
+ sfree (plugins);
+ sfree (identifiers);
return (-1);
}
+ } /* while (*buffer != 0) */
+
+ /* Add NULL entries for `any plugin' and/or `any value' if nothing was
+ * specified. */
+ if (plugins_num == 0)
+ add_to_array (&plugins, &plugins_num, NULL);
+
+ if (identifiers_num == 0)
+ add_to_array (&identifiers, &identifiers_num, NULL);
+
+ for (i = 0; i < plugins_num; i++)
+ {
+ char *plugin;
+ int j;
+
+ plugin = plugins[i];
+
+ for (j = 0; j < identifiers_num; j++)
+ {
+ char *identifier;
+ int status;
+
+ identifier = identifiers[j];
+ status = plugin_flush (plugin, timeout, identifier);
+ if (status == 0)
+ success++;
+ else
+ error++;
+ }
}
if ((success + error) > 0)
}
else
{
- plugin_flush_all (timeout);
+ plugin_flush (NULL, timeout, NULL);
print_to_socket (fh, "0 Done\n");
}
+ sfree (plugins);
+ sfree (identifiers);
return (0);
} /* int handle_flush */
#ifndef UTILS_CMD_FLUSH_H
#define UTILS_CMD_FLUSH_H 1
-int handle_flush (FILE *fh, char **fields, int fields_num);
+int handle_flush (FILE *fh, char *buffer);
#endif /* UTILS_CMD_FLUSH_H */
#include "plugin.h"
#include "utils_cache.h"
+#include "utils_parse_option.h"
#define print_to_socket(fh, ...) \
if (fprintf (fh, __VA_ARGS__) < 0) { \
return -1; \
}
-int handle_getval (FILE *fh, char **fields, int fields_num)
+int handle_getval (FILE *fh, char *buffer)
{
+ char *command;
+ char *identifier;
+ char *identifier_copy;
+
char *hostname;
char *plugin;
char *plugin_instance;
gauge_t *values;
size_t values_num;
- char *identifier_copy;
-
const data_set_t *ds;
int status;
int i;
- if (fields_num != 2)
+ if ((fh == NULL) || (buffer == NULL))
+ return (-1);
+
+ DEBUG ("utils_cmd_getval: handle_getval (fh = %p, buffer = %s);",
+ (void *) fh, buffer);
+
+ command = NULL;
+ status = parse_string (&buffer, &command);
+ if (status != 0)
{
- DEBUG ("unixsock plugin: Wrong number of fields: %i", fields_num);
- print_to_socket (fh, "-1 Wrong number of fields: Got %i, expected 2.\n",
- fields_num);
+ print_to_socket (fh, "-1 Cannot parse command.\n");
return (-1);
}
- DEBUG ("unixsock plugin: Got query for `%s'", fields[1]);
+ assert (command != NULL);
- if (strlen (fields[1]) < strlen ("h/p/t"))
+ if (strcasecmp ("GETVAL", command) != 0)
{
- print_to_socket (fh, "-1 Invalied identifier, %s\n", fields[1]);
+ print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
+ return (-1);
+ }
+
+ identifier = NULL;
+ status = parse_string (&buffer, &identifier);
+ if (status != 0)
+ {
+ print_to_socket (fh, "-1 Cannot parse identifier.\n");
+ return (-1);
+ }
+ assert (identifier != NULL);
+
+ if (*buffer != 0)
+ {
+ print_to_socket (fh, "-1 Garbage after end of command: %s\n", buffer);
return (-1);
}
/* parse_identifier() modifies its first argument,
* returning pointers into it */
- identifier_copy = sstrdup (fields[1]);
+ identifier_copy = sstrdup (identifier);
status = parse_identifier (identifier_copy, &hostname,
&plugin, &plugin_instance,
&type, &type_instance);
if (status != 0)
{
- DEBUG ("unixsock plugin: Cannot parse `%s'", fields[1]);
- print_to_socket (fh, "-1 Cannot parse identifier.\n");
+ DEBUG ("handle_getval: Cannot parse identifier `%s'.", identifier);
+ print_to_socket (fh, "-1 Cannot parse identifier `%s'.\n", identifier);
sfree (identifier_copy);
return (-1);
}
ds = plugin_get_ds (type);
if (ds == NULL)
{
- DEBUG ("unixsock plugin: plugin_get_ds (%s) == NULL;", type);
+ DEBUG ("handle_getval: plugin_get_ds (%s) == NULL;", type);
print_to_socket (fh, "-1 Type `%s' is unknown.\n", type);
sfree (identifier_copy);
return (-1);
values = NULL;
values_num = 0;
- status = uc_get_rate_by_name (fields[1], &values, &values_num);
+ status = uc_get_rate_by_name (identifier, &values, &values_num);
if (status != 0)
{
print_to_socket (fh, "-1 No such value\n");
#ifndef UTILS_CMD_GETVAL_H
#define UTILS_CMD_GETVAL_H 1
-int handle_getval (FILE *fh, char **fields, int fields_num);
+int handle_getval (FILE *fh, char *buffer);
#endif /* UTILS_CMD_GETVAL_H */
#include "utils_cmd_listval.h"
#include "utils_cache.h"
+#include "utils_parse_option.h"
#define print_to_socket(fh, ...) \
if (fprintf (fh, __VA_ARGS__) < 0) { \
return -1; \
}
-int handle_listval (FILE *fh, char **fields, int fields_num)
+int handle_listval (FILE *fh, char *buffer)
{
+ char *command;
char **names = NULL;
time_t *times = NULL;
size_t number = 0;
size_t i;
int status;
- if (fields_num != 1)
+ DEBUG ("utils_cmd_listval: handle_listval (fh = %p, buffer = %s);",
+ (void *) fh, buffer);
+
+ command = NULL;
+ status = parse_string (&buffer, &command);
+ if (status != 0)
+ {
+ print_to_socket (fh, "-1 Cannot parse command.\n");
+ return (-1);
+ }
+ assert (command != NULL);
+
+ if (strcasecmp ("LISTVAL", command) != 0)
+ {
+ print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
+ return (-1);
+ }
+
+ if (*buffer != 0)
{
- DEBUG ("command listval: us_handle_listval: Wrong number of fields: %i",
- fields_num);
- print_to_socket (fh, "-1 Wrong number of fields: Got %i, expected 1.\n",
- fields_num);
+ print_to_socket (fh, "-1 Garbage after end of command: %s\n", buffer);
return (-1);
}
#ifndef UTILS_CMD_LISTVAL_H
#define UTILS_CMD_LISTVAL_H 1
-int handle_listval (FILE *fh, char **fields, int fields_num);
+int handle_listval (FILE *fh, char *buffer);
#endif /* UTILS_CMD_LISTVAL_H */
#include "common.h"
#include "plugin.h"
+#include "utils_parse_option.h"
+
#define print_to_socket(fh, ...) \
if (fprintf (fh, __VA_ARGS__) < 0) { \
char errbuf[1024]; \
return -1; \
}
-static int parse_option_severity (notification_t *n, char *value)
+static int set_option_severity (notification_t *n, const char *value)
{
if (strcasecmp (value, "Failure") == 0)
n->severity = NOTIF_FAILURE;
return (-1);
return (0);
-} /* int parse_option_severity */
+} /* int set_option_severity */
-static int parse_option_time (notification_t *n, char *value)
+static int set_option_time (notification_t *n, const char *value)
{
time_t tmp;
n->time = tmp;
return (0);
-} /* int parse_option_time */
+} /* int set_option_time */
-static int parse_option (notification_t *n, char *buffer)
+static int set_option (notification_t *n, const char *option, const char *value)
{
- char *option = buffer;
- char *value;
-
- if ((n == NULL) || (option == NULL))
+ if ((n == NULL) || (option == NULL) || (value == NULL))
return (-1);
- value = strchr (option, '=');
- if (value == NULL)
- return (-1);
- *value = '\0'; value++;
+ DEBUG ("utils_cmd_putnotif: set_option (option = %s, value = %s);",
+ option, value);
if (strcasecmp ("severity", option) == 0)
- return (parse_option_severity (n, value));
+ return (set_option_severity (n, value));
else if (strcasecmp ("time", option) == 0)
- return (parse_option_time (n, value));
+ return (set_option_time (n, value));
+ else if (strcasecmp ("message", option) == 0)
+ sstrncpy (n->message, value, sizeof (n->message));
else if (strcasecmp ("host", option) == 0)
sstrncpy (n->host, value, sizeof (n->host));
else if (strcasecmp ("plugin", option) == 0)
return (1);
return (0);
-} /* int parse_option */
+} /* int set_option */
-static int parse_message (notification_t *n, char **fields, int fields_num)
+int handle_putnotif (FILE *fh, char *buffer)
{
+ char *command;
+ notification_t n;
int status;
- /* Strip off the leading `message=' */
- fields[0] += strlen ("message=");
-
- status = strjoin (n->message, sizeof (n->message), fields, fields_num, " ");
- if (status < 0)
+ if ((fh == NULL) || (buffer == NULL))
return (-1);
- return (0);
-} /* int parse_message */
+ DEBUG ("utils_cmd_putnotif: handle_putnotif (fh = %p, buffer = %s);",
+ (void *) fh, buffer);
-int handle_putnotif (FILE *fh, char **fields, int fields_num)
-{
- notification_t n;
- int status;
- int i;
+ command = NULL;
+ status = parse_string (&buffer, &command);
+ if (status != 0)
+ {
+ print_to_socket (fh, "-1 Cannot parse command.\n");
+ return (-1);
+ }
+ assert (command != NULL);
- /* Required fields: `PUTNOTIF', severity, time, message */
- if (fields_num < 4)
+ if (strcasecmp ("PUTNOTIF", command) != 0)
{
- DEBUG ("cmd putnotif: Wrong number of fields: %i", fields_num);
- print_to_socket (fh, "-1 Wrong number of fields: Got %i, "
- "expected at least 4.\n",
- fields_num);
+ print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
return (-1);
}
memset (&n, '\0', sizeof (n));
status = 0;
- for (i = 1; i < fields_num; i++)
+ while (*buffer != 0)
{
- if (strncasecmp (fields[i], "message=", strlen ("message=")) == 0)
+ char *key;
+ char *value;
+
+ status = parse_option (&buffer, &key, &value);
+ if (status != 0)
{
- status = parse_message (&n, fields + i, fields_num - i);
- if (status != 0)
- {
- print_to_socket (fh, "-1 Error parsing the message. Have you hit the "
- "limit of %u bytes?\n", (unsigned int) sizeof (n.message));
- }
+ print_to_socket (fh, "-1 Malformed option.\n");
break;
}
- else
+
+ status = set_option (&n, key, value);
+ if (status != 0)
{
- status = parse_option (&n, fields[i]);
- if (status != 0)
- {
- print_to_socket (fh, "-1 Error parsing option `%s'\n", fields[i]);
- break;
- }
+ print_to_socket (fh, "-1 Error parsing option `%s'\n", key);
+ break;
}
} /* for (i) */
#ifndef UTILS_CMD_PUTNOTIF_H
#define UTILS_CMD_PUTNOTIF_H 1
-int handle_putnotif (FILE *fh, char **fields, int fields_num);
+int handle_putnotif (FILE *fh, char *buffer);
/* vim: set shiftwidth=2 softtabstop=2 tabstop=8 : */
/**
* collectd - src/utils_cms_putval.c
- * Copyright (C) 2007 Florian octo Forster
+ * Copyright (C) 2007,2008 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
#include "common.h"
#include "plugin.h"
+#include "utils_parse_option.h"
+
#define print_to_socket(fh, ...) \
if (fprintf (fh, __VA_ARGS__) < 0) { \
char errbuf[1024]; \
}
static int parse_value (const data_set_t *ds, value_list_t *vl,
- const char *type,
FILE *fh, char *buffer)
{
char *dummy;
return (-1);
}
- plugin_dispatch_values (type, vl);
+ plugin_dispatch_values (vl);
return (0);
} /* int parse_value */
-static int parse_option (value_list_t *vl, char *buffer)
+static int set_option (value_list_t *vl, const char *key, const char *value)
{
- char *option = buffer;
- char *value;
-
- if ((vl == NULL) || (option == NULL))
- return (-1);
-
- value = strchr (option, '=');
- if (value == NULL)
+ if ((vl == NULL) || (key == NULL) || (value == NULL))
return (-1);
- *value = '\0'; value++;
- if (strcasecmp ("interval", option) == 0)
+ if (strcasecmp ("interval", key) == 0)
{
- vl->interval = atoi (value);
- if (vl->interval <= 0)
- vl->interval = interval_g;
+ int tmp;
+ char *endptr;
+
+ endptr = NULL;
+ errno = 0;
+ tmp = strtol (value, &endptr, 0);
+
+ if ((errno == 0) && (endptr != NULL)
+ && (endptr != value) && (tmp > 0))
+ vl->interval = tmp;
}
else
return (1);
return (0);
} /* int parse_option */
-int handle_putval (FILE *fh, char **fields, int fields_num)
+int handle_putval (FILE *fh, char *buffer)
{
+ char *command;
+ char *identifier;
char *hostname;
char *plugin;
char *plugin_instance;
char *type;
char *type_instance;
int status;
- int i;
+ int values_submitted;
char *identifier_copy;
const data_set_t *ds;
value_list_t vl = VALUE_LIST_INIT;
- if (fields_num < 3)
+ DEBUG ("utils_cmd_putval: handle_putval (fh = %p, buffer = %s);",
+ (void *) fh, buffer);
+
+ command = NULL;
+ status = parse_string (&buffer, &command);
+ if (status != 0)
{
- DEBUG ("cmd putval: Wrong number of fields: %i",
- fields_num);
- print_to_socket (fh, "-1 Wrong number of fields: Got %i, "
- "expected at least 3.\n",
- fields_num);
+ print_to_socket (fh, "-1 Cannot parse command.\n");
return (-1);
}
+ assert (command != NULL);
+
+ if (strcasecmp ("PUTVAL", command) != 0)
+ {
+ print_to_socket (fh, "-1 Unexpected command: `%s'.\n", command);
+ return (-1);
+ }
+
+ identifier = NULL;
+ status = parse_string (&buffer, &identifier);
+ if (status != 0)
+ {
+ print_to_socket (fh, "-1 Cannot parse identifier.\n");
+ return (-1);
+ }
+ assert (identifier != NULL);
/* parse_identifier() modifies its first argument,
* returning pointers into it */
- identifier_copy = sstrdup (fields[1]);
+ identifier_copy = sstrdup (identifier);
status = parse_identifier (identifier_copy, &hostname,
&plugin, &plugin_instance,
&type, &type_instance);
if (status != 0)
{
- DEBUG ("cmd putval: Cannot parse `%s'", fields[1]);
- print_to_socket (fh, "-1 Cannot parse identifier.\n");
+ DEBUG ("handle_putval: Cannot parse identifier `%s'.",
+ identifier);
+ print_to_socket (fh, "-1 Cannot parse identifier `%s'.\n",
+ identifier);
sfree (identifier_copy);
return (-1);
}
sstrncpy (vl.host, hostname, sizeof (vl.host));
sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (plugin_instance != NULL)
sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
if (type_instance != NULL)
ds = plugin_get_ds (type);
if (ds == NULL) {
+ print_to_socket (fh, "-1 Type `%s' isn't defined.\n", type);
sfree (identifier_copy);
return (-1);
}
+ /* Free identifier_copy */
+ hostname = NULL;
+ plugin = NULL; plugin_instance = NULL;
+ type = NULL; type_instance = NULL;
+ sfree (identifier_copy);
+
vl.values_len = ds->ds_num;
vl.values = (value_t *) malloc (vl.values_len * sizeof (value_t));
if (vl.values == NULL)
{
print_to_socket (fh, "-1 malloc failed.\n");
- sfree (identifier_copy);
return (-1);
}
/* All the remaining fields are part of the optionlist. */
- for (i = 2; i < fields_num; i++)
+ values_submitted = 0;
+ while (*buffer != 0)
{
- if (strchr (fields[i], ':') != NULL)
+ char *string = NULL;
+ char *value = NULL;
+
+ status = parse_option (&buffer, &string, &value);
+ if (status < 0)
{
- /* It's parse_value's job to write an error to `fh'.
- * This is not the case with `parse_option below.
- * Neither will write an success message. */
- if (parse_value (ds, &vl, type, fh, fields[i]) != 0)
- break;
+ /* parse_option failed, buffer has been modified.
+ * => we need to abort */
+ print_to_socket (fh, "-1 Misformatted option.\n");
+ return (-1);
}
- else if (strchr (fields[i], '=') != NULL)
+ else if (status == 0)
{
- if (parse_option (&vl, fields[i]) != 0)
- {
- print_to_socket (fh, "-1 Error parsing option `%s'\n",
- fields[i]);
- break;
- }
+ assert (string != NULL);
+ assert (value != NULL);
+ set_option (&vl, string, value);
+ continue;
}
- else
+ /* else: parse_option but buffer has not been modified. This is
+ * the default if no `=' is found.. */
+
+ status = parse_string (&buffer, &string);
+ if (status != 0)
{
- WARNING ("cmd putval: handle_putval: "
- "Cannot parse field #%i `%s'; "
- "Ignoring it.\n",
- i, fields[i]);
+ print_to_socket (fh, "-1 Misformatted value.\n");
+ return (-1);
}
- }
+ assert (string != NULL);
+
+ status = parse_value (ds, &vl, fh, string);
+ if (status != 0)
+ {
+ /* An error has already been printed. */
+ return (-1);
+ }
+ values_submitted++;
+ } /* while (*buffer != 0) */
/* Done parsing the options. */
- if (i == fields_num)
- print_to_socket (fh, "0 Success\n");
+ print_to_socket (fh, "0 Success: %i %s been dispatched.\n",
+ values_submitted,
+ (values_submitted == 1) ? "value has" : "values have");
sfree (vl.values);
- sfree (identifier_copy);
return (0);
} /* int handle_putval */
#ifndef UTILS_CMD_PUTVAL_H
#define UTILS_CMD_PUTVAL_H 1
-int handle_putval (FILE *fh, char **fields, int fields_num);
+int handle_putval (FILE *fh, char *buffer);
#endif /* UTILS_CMD_PUTVAL_H */
--- /dev/null
+/**
+ * collectd - src/utils_complain.c
+ * Copyright (C) 2006-2007 Florian octo Forster
+ * Copyright (C) 2008 Sebastian tokkee 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:
+ * Florian octo Forster <octo at verplant.org>
+ * Sebastian tokkee Harl <sh at tokkee.org>
+ **/
+
+#include "collectd.h"
+#include "utils_complain.h"
+#include "plugin.h"
+
+/* vcomplain returns 0 if it did not report, 1 else */
+static int vcomplain (int level, c_complain_t *c,
+ const char *format, va_list ap)
+{
+ time_t now;
+ char message[512];
+
+ now = time (NULL);
+
+ if (c->last + c->interval > now)
+ return 0;
+
+ c->last = now;
+
+ if (c->interval < interval_g)
+ c->interval = interval_g;
+ else
+ c->interval *= 2;
+
+ if (c->interval > 86400)
+ c->interval = 86400;
+
+ vsnprintf (message, sizeof (message), format, ap);
+ message[sizeof (message) - 1] = '\0';
+
+ plugin_log (level, "%s", message);
+ return 1;
+} /* vcomplain */
+
+void c_complain (int level, c_complain_t *c, const char *format, ...)
+{
+ va_list ap;
+
+ /* reset the old interval */
+ if (c->interval < 0)
+ c->interval *= -1;
+
+ va_start (ap, format);
+ vcomplain (level, c, format, ap);
+ va_end (ap);
+} /* c_complain */
+
+void c_complain_once (int level, c_complain_t *c, const char *format, ...)
+{
+ va_list ap;
+
+ if (c->interval < 0)
+ return;
+
+ va_start (ap, format);
+ if (vcomplain (level, c, format, ap))
+ c->interval *= -1;
+ va_end (ap);
+} /* c_complain_once */
+
+void c_do_release (int level, c_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, sizeof (message), format, ap);
+ message[sizeof (message) - 1] = '\0';
+ va_end (ap);
+
+ plugin_log (level, "%s", message);
+} /* c_release */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
--- /dev/null
+/**
+ * collectd - src/utils_complain.h
+ * Copyright (C) 2006-2007 Florian octo Forster
+ * Copyright (C) 2008 Sebastian tokkee 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:
+ * Florian octo Forster <octo at verplant.org>
+ * Sebastian tokkee Harl <sh at tokkee.org>
+ **/
+
+#ifndef UTILS_COMPLAIN_H
+#define UTILS_COMPLAIN_H 1
+
+#include <time.h>
+
+typedef struct
+{
+ /* time of the last report */
+ time_t last;
+
+ /* how long to wait until reporting again
+ * 0 indicates that the complaint is no longer valid
+ * < 0 indicates that the complaint has been reported once
+ * => c_complain_once will not report again
+ * => c_complain uses the absolute value to reset the old value */
+ int interval;
+} c_complain_t;
+
+#define C_COMPLAIN_INIT { 0, 0 }
+
+/*
+ * NAME
+ * c_complain
+ *
+ * DESCRIPTION
+ * Complain about something. This function will report a message (usually
+ * indicating some error condition) using the collectd logging mechanism.
+ * When this function is called again, reporting the message again will be
+ * deferred by an increasing interval (up to one day) to prevent flooding
+ * the logs. A call to `c_release' resets the counter.
+ *
+ * PARAMETERS
+ * `level' The log level passed to `plugin_log'.
+ * `c' Identifier for the complaint.
+ * `format' Message format - see the documentation of printf(3).
+ */
+void c_complain (int level, c_complain_t *c, const char *format, ...);
+
+/*
+ * NAME
+ * c_complain_once
+ *
+ * DESCRIPTION
+ * Complain about something once. This function will not report anything
+ * again, unless `c_release' has been called in between. If used after some
+ * calls to `c_complain', it will report again on the next interval and stop
+ * after that.
+ *
+ * See `c_complain' for further details and a description of the parameters.
+ */
+void c_complain_once (int level, c_complain_t *c, const char *format, ...);
+
+/*
+ * NAME
+ * c_release
+ *
+ * DESCRIPTION
+ * Release a complaint. This will report a message once, marking the
+ * complaint as released.
+ *
+ * See `c_complain' for a description of the parameters.
+ */
+void c_do_release (int level, c_complain_t *c, const char *format, ...);
+#define c_release(level, c, ...) \
+ do { \
+ if ((c)->interval != 0) \
+ c_do_release(level, c, __VA_ARGS__); \
+ } while (0)
+
+#endif /* UTILS_COMPLAIN_H */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
+
#include "collectd.h"
#include "plugin.h"
+#include "common.h"
#if HAVE_NETINET_IN_SYSTM_H
# include <netinet/in_systm.h>
if (0 != x)
return 0;
if ('\0' == qh.qname[0])
- strncpy (qh.qname, ".", sizeof (qh.qname));
+ sstrncpy (qh.qname, ".", sizeof (qh.qname));
while ((t = strchr(qh.qname, '\n')))
*t = ' ';
while ((t = strchr(qh.qname, '\r')))
case T_ANY: return ("ANY"); /* ... 255 */
#endif /* __BIND >= 19950621 */
default:
- snprintf (buf, 32, "#%i", t);
- buf[31] = '\0';
+ ssnprintf (buf, sizeof (buf), "#%i", t);
return (buf);
}; /* switch (t) */
/* NOTREACHED */
return "Update";
break;
default:
- snprintf(buf, 30, "Opcode%d", o);
+ ssnprintf(buf, sizeof (buf), "Opcode%d", o);
return buf;
}
/* NOTREACHED */
#endif /* RFC2136 rcodes */
#endif /* __BIND >= 19950621 */
default:
- snprintf (buf, 32, "RCode%i", rcode);
- buf[31] = '\0';
+ ssnprintf (buf, sizeof (buf), "RCode%i", rcode);
return (buf);
}
/* Never reached */
/* We need to copy `entry' since it's const */
entry_copy_size = entry_len - 1;
entry_copy = smalloc (entry_copy_size);
- strncpy (entry_copy, entry + 1, entry_copy_size);
- entry_copy[entry_copy_size - 1] = 0;
+ sstrncpy (entry_copy, entry + 1, entry_copy_size);
DEBUG("I'm about to add regex entry: %s", entry_copy);
ret = ignorelist_append_regex(il, entry_copy);
* (This is useful, if the cdrom on /dev/hdc must not
* be accessed.)
*/
- snprintf(device, sizeof(device), "%s/%s",
+ ssnprintf(device, sizeof(device), "%s/%s",
DEVLABELDIR, ptname);
if(!get_label_uuid(device, &label, uuid)) {
uuidcache_addentry(sstrdup(device),
return r;
} /* char *cu_mount_getoptionvalue(char *line, char *keyword) */
-
-
int
cu_mount_type(const char *type)
{
return CUMT_UNKNOWN;
} /* int cu_mount_type(const char *type) */
-
-
--- /dev/null
+/**
+ * collectd - src/utils_parse_option.c
+ * Copyright (C) 2008 Florian 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_parse_option.h"
+
+int parse_string (char **ret_buffer, char **ret_string)
+{
+ char *buffer;
+ char *string;
+
+ buffer = *ret_buffer;
+
+ /* Eat up leading spaces. */
+ string = buffer;
+ while (isspace ((int) *string))
+ string++;
+ if (*string == 0)
+ return (1);
+
+ /* A quoted string */
+ if (*string == '"')
+ {
+ char *dst;
+
+ string++;
+ if (*string == 0)
+ return (1);
+
+ dst = string;
+ buffer = string;
+ while ((*buffer != '"') && (*buffer != 0))
+ {
+ /* Un-escape backslashes */
+ if (*buffer == '\\')
+ {
+ buffer++;
+ /* Catch a backslash at the end of buffer */
+ if (*buffer == 0)
+ return (-1);
+ }
+ *dst = *buffer;
+ buffer++;
+ dst++;
+ }
+ /* No quote sign has been found */
+ if (*buffer == 0)
+ return (-1);
+
+ *dst = 0;
+ dst++;
+ *buffer = 0;
+ buffer++;
+
+ /* Check for trailing spaces. */
+ if ((*buffer != 0) && !isspace ((int) *buffer))
+ return (-1);
+ }
+ else /* an unquoted string */
+ {
+ buffer = string;
+ while ((*buffer != 0) && !isspace ((int) *buffer))
+ buffer++;
+ if (*buffer != 0)
+ {
+ *buffer = 0;
+ buffer++;
+ }
+ }
+
+ /* Eat up trailing spaces */
+ while (isspace ((int) *buffer))
+ buffer++;
+
+ *ret_buffer = buffer;
+ *ret_string = string;
+
+ return (0);
+} /* int parse_string */
+
+/*
+ * parse_option
+ * ------------
+ * Parses an ``option'' as used with the unixsock and exec commands. An
+ * option is of the form:
+ * name0="value"
+ * name1="value with \"quotes\""
+ * name2="value \\ backslash"
+ * However, if the value does *not* contain a space character, you can skip
+ * the quotes.
+ */
+int parse_option (char **ret_buffer, char **ret_key, char **ret_value)
+{
+ char *buffer;
+ char *key;
+ char *value;
+ int status;
+
+ buffer = *ret_buffer;
+
+ /* Eat up leading spaces */
+ key = buffer;
+ while (isspace ((int) *key))
+ key++;
+ if (*key == 0)
+ return (1);
+
+ /* Look for the equal sign */
+ buffer = key;
+ while (isalnum ((int) *buffer))
+ buffer++;
+ if ((*buffer != '=') || (buffer == key))
+ return (1);
+ *buffer = 0;
+ buffer++;
+ /* Empty values must be written as "" */
+ if (isspace ((int) *buffer) || (*buffer == 0))
+ return (-1);
+
+ status = parse_string (&buffer, &value);
+ if (status != 0)
+ return (-1);
+
+ /* NB: parse_string will have eaten up all trailing spaces. */
+
+ *ret_buffer = buffer;
+ *ret_key = key;
+ *ret_value = value;
+
+ return (0);
+} /* int parse_option */
+
+/* vim: set sw=2 ts=8 tw=78 et : */
--- /dev/null
+/**
+ * collectd - src/utils_parse_option.h
+ * Copyright (C) 2008 Florian 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Florian octo Forster <octo at verplant.org>
+ **/
+
+#ifndef UTILS_PARSE_OPTION
+#define UTILS_PARSE_OPTION 1
+
+int parse_string (char **ret_buffer, char **ret_string);
+int parse_option (char **ret_buffer, char **ret_key, char **ret_value);
+
+#endif /* UTILS_PARSE_OPTION */
+
+/* vim: set sw=2 ts=8 tw=78 et : */
sstrncpy (vl.plugin, data->plugin, sizeof (vl.plugin));
sstrncpy (vl.plugin_instance, data->plugin_instance,
sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, data->type, sizeof (vl.type));
sstrncpy (vl.type_instance, data->type_instance,
sizeof (vl.type_instance));
- plugin_dispatch_values (data->type, &vl);
+ plugin_dispatch_values (&vl);
if (match_value->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
{
return (-1);
}
- strncpy (th->type_instance, ci->values[0].value.string,
+ sstrncpy (th->type_instance, ci->values[0].value.string,
sizeof (th->type_instance));
- th->type_instance[sizeof (th->type_instance) - 1] = '\0';
return (0);
} /* int ut_config_type_instance */
}
memcpy (&th, th_orig, sizeof (th));
- strncpy (th.type, ci->values[0].value.string, sizeof (th.type));
- th.type[sizeof (th.type) - 1] = '\0';
+ sstrncpy (th.type, ci->values[0].value.string, sizeof (th.type));
th.warning_min = NAN;
th.warning_max = NAN;
return (-1);
}
- strncpy (th->plugin_instance, ci->values[0].value.string,
+ sstrncpy (th->plugin_instance, ci->values[0].value.string,
sizeof (th->plugin_instance));
- th->plugin_instance[sizeof (th->plugin_instance) - 1] = '\0';
return (0);
} /* int ut_config_plugin_instance */
}
memcpy (&th, th_orig, sizeof (th));
- strncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
- th.plugin[sizeof (th.plugin) - 1] = '\0';
+ sstrncpy (th.plugin, ci->values[0].value.string, sizeof (th.plugin));
for (i = 0; i < ci->children_num; i++)
{
}
memcpy (&th, th_orig, sizeof (th));
- strncpy (th.host, ci->values[0].value.string, sizeof (th.host));
- th.host[sizeof (th.host) - 1] = '\0';
+ sstrncpy (th.host, ci->values[0].value.string, sizeof (th.host));
for (i = 0; i < ci->children_num; i++)
{
*/
/* }}} */
-static threshold_t *threshold_search (const data_set_t *ds,
- const value_list_t *vl)
+static threshold_t *threshold_search (const value_list_t *vl)
{
threshold_t *th;
if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
- ds->type, vl->type_instance)) != NULL)
+ vl->type, vl->type_instance)) != NULL)
return (th);
else if ((th = threshold_get (vl->host, vl->plugin, vl->plugin_instance,
- ds->type, NULL)) != NULL)
+ vl->type, NULL)) != NULL)
return (th);
else if ((th = threshold_get (vl->host, vl->plugin, NULL,
- ds->type, vl->type_instance)) != NULL)
+ vl->type, vl->type_instance)) != NULL)
return (th);
else if ((th = threshold_get (vl->host, vl->plugin, NULL,
- ds->type, NULL)) != NULL)
+ vl->type, NULL)) != NULL)
return (th);
else if ((th = threshold_get (vl->host, "", NULL,
- ds->type, vl->type_instance)) != NULL)
+ vl->type, vl->type_instance)) != NULL)
return (th);
else if ((th = threshold_get (vl->host, "", NULL,
- ds->type, NULL)) != NULL)
+ vl->type, NULL)) != NULL)
return (th);
else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
- ds->type, vl->type_instance)) != NULL)
+ vl->type, vl->type_instance)) != NULL)
return (th);
else if ((th = threshold_get ("", vl->plugin, vl->plugin_instance,
- ds->type, NULL)) != NULL)
+ vl->type, NULL)) != NULL)
return (th);
else if ((th = threshold_get ("", vl->plugin, NULL,
- ds->type, vl->type_instance)) != NULL)
+ vl->type, vl->type_instance)) != NULL)
return (th);
else if ((th = threshold_get ("", vl->plugin, NULL,
- ds->type, NULL)) != NULL)
+ vl->type, NULL)) != NULL)
return (th);
else if ((th = threshold_get ("", "", NULL,
- ds->type, vl->type_instance)) != NULL)
+ vl->type, vl->type_instance)) != NULL)
return (th);
else if ((th = threshold_get ("", "", NULL,
- ds->type, NULL)) != NULL)
+ vl->type, NULL)) != NULL)
return (th);
return (NULL);
n.time = vl->time;
- status = snprintf (buf, bufsize, "Host %s, plugin %s",
+ status = ssnprintf (buf, bufsize, "Host %s, plugin %s",
vl->host, vl->plugin);
buf += status;
bufsize -= status;
if (vl->plugin_instance[0] != '\0')
{
- status = snprintf (buf, bufsize, " (instance %s)",
+ status = ssnprintf (buf, bufsize, " (instance %s)",
vl->plugin_instance);
buf += status;
bufsize -= status;
}
- status = snprintf (buf, bufsize, " type %s", ds->type);
+ status = ssnprintf (buf, bufsize, " type %s", vl->type);
buf += status;
bufsize -= status;
if (vl->type_instance[0] != '\0')
{
- status = snprintf (buf, bufsize, " (instance %s)",
+ status = ssnprintf (buf, bufsize, " (instance %s)",
vl->type_instance);
buf += status;
bufsize -= status;
}
+ plugin_notification_meta_add_string (&n, "DataSource",
+ ds->ds[ds_index].name);
+ plugin_notification_meta_add_double (&n, "CurrentValue", values[ds_index]);
+ plugin_notification_meta_add_double (&n, "WarningMin", th->warning_min);
+ plugin_notification_meta_add_double (&n, "WarningMax", th->warning_max);
+ plugin_notification_meta_add_double (&n, "FailureMin", th->failure_min);
+ plugin_notification_meta_add_double (&n, "FailureMax", th->failure_max);
+
/* Send an okay notification */
if (state == STATE_OKAY)
{
- status = snprintf (buf, bufsize, ": All data sources are within range again.");
+ status = ssnprintf (buf, bufsize, ": All data sources are within range again.");
buf += status;
bufsize -= status;
}
{
if (!isnan (min) && !isnan (max))
{
- status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
+ status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
"%f. That is within the %s region of %f and %f.",
ds->ds[ds_index].name, values[ds_index],
(state == STATE_ERROR) ? "failure" : "warning",
}
else
{
- status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
+ status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
"%f. That is %s the %s threshold of %f.",
ds->ds[ds_index].name, values[ds_index],
isnan (min) ? "below" : "above",
}
else /* is not inverted */
{
- status = snprintf (buf, bufsize, ": Data source \"%s\" is currently "
+ status = ssnprintf (buf, bufsize, ": Data source \"%s\" is currently "
"%f. That is %s the %s threshold of %f.",
ds->ds[ds_index].name, values[ds_index],
(values[ds_index] < min) ? "below" : "above",
plugin_dispatch_notification (&n);
+ plugin_notification_meta_free (&n);
return (0);
} /* }}} int ut_report_state */
/* Is this lock really necessary? So far, thresholds are only inserted at
* startup. -octo */
pthread_mutex_lock (&threshold_lock);
- th = threshold_search (ds, vl);
+ th = threshold_search (vl);
pthread_mutex_unlock (&threshold_lock);
if (th == NULL)
return (0);
memset (&ds, '\0', sizeof (ds));
memset (&vl, '\0', sizeof (vl));
- strncpy (vl.host, host, sizeof (vl.host));
- vl.host[sizeof (vl.host) - 1] = '\0';
- strncpy (vl.plugin, plugin, sizeof (vl.plugin));
- vl.plugin[sizeof (vl.plugin) - 1] = '\0';
+ sstrncpy (vl.host, host, sizeof (vl.host));
+ sstrncpy (vl.plugin, plugin, sizeof (vl.plugin));
if (plugin_instance != NULL)
- {
- strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
- vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0';
- }
- strncpy (ds.type, type, sizeof (ds.type));
- ds.type[sizeof (ds.type) - 1] = '\0';
+ sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+ sstrncpy (ds.type, type, sizeof (ds.type));
+ sstrncpy (vl.type, type, sizeof (vl.type));
if (type_instance != NULL)
- {
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- vl.type_instance[sizeof (vl.type_instance) - 1] = '\0';
- }
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
sfree (name_copy);
host = plugin = plugin_instance = type = type_instance = NULL;
- th = threshold_search (&ds, &vl);
+ th = threshold_search (&vl);
if (th == NULL)
return (0);
if ((th->flags & UT_FLAG_PERSIST) == 0)
char *uuid = uuid_get_local ();
if (uuid) {
- strncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
- hostname_g[DATA_MAX_NAME_LEN-1] = '\0';
+ sstrncpy (hostname_g, uuid, DATA_MAX_NAME_LEN);
sfree (uuid);
return 0;
}
sstrncpy (vl.plugin, "vmem", 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 (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void vmem_submit */
static void submit_two (const char *plugin_instance, const char *type,
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "if_octets", sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
- plugin_dispatch_values ("if_octets", &vl);
+ plugin_dispatch_values (&vl);
} /* void traffic_submit */
static void load_submit (const char *plugin_instance,
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, "load", sizeof (vl.type));
- plugin_dispatch_values ("load", &vl);
+ plugin_dispatch_values (&vl);
}
static void submit_gauge (const char *plugin_instance, const char *type,
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "vserver", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
- strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_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 submit_gauge */
static inline long long __get_sock_bytes(const char *s)
continue;
/* socket message accounting */
- len = snprintf (file, BUFSIZE, PROCDIR "/%s/cacct", dent->d_name);
- if ((len < 0) || (len >= BUFSIZE))
+ len = ssnprintf (file, sizeof (file),
+ PROCDIR "/%s/cacct", dent->d_name);
+ if ((len < 0) || (len >= sizeof (file)))
continue;
if (NULL == (fh = fopen (file, "r")))
}
/* thread information and load */
- len = snprintf (file, BUFSIZE, PROCDIR "/%s/cvirt", dent->d_name);
- if ((len < 0) || (len >= BUFSIZE))
+ len = ssnprintf (file, sizeof (file),
+ PROCDIR "/%s/cvirt", dent->d_name);
+ if ((len < 0) || (len >= sizeof (file)))
continue;
if (NULL == (fh = fopen (file, "r")))
}
/* processes and memory usage */
- len = snprintf (file, BUFSIZE, PROCDIR "/%s/limit", dent->d_name);
- if ((len < 0) || (len >= BUFSIZE))
+ len = ssnprintf (file, sizeof (file),
+ PROCDIR "/%s/limit", dent->d_name);
+ if ((len < 0) || (len >= sizeof (file)))
continue;
if (NULL == (fh = fopen (file, "r")))
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "wireless", sizeof (vl.plugin));
- strncpy (vl.plugin_instance, plugin_instance,
+ sstrncpy (vl.plugin_instance, plugin_instance,
sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void wireless_submit */
#define POWER_MIN -90.0
vl.time = time (NULL);
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "xmms", sizeof (vl.plugin));
+ sstrncpy (vl.type, type, sizeof (vl.type));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void cxmms_submit */
int cxmms_read (void)
#!/bin/sh
-DEFAULT_VERSION="4.4.4.git"
+DEFAULT_VERSION="4.5.1.git"
VERSION="$( git describe 2> /dev/null | sed -e 's/^collectd-//' )"