author | Florian Forster <octo@collectd.org> | |
Sun, 11 Nov 2012 07:58:18 +0000 (08:58 +0100) | ||
committer | Florian Forster <octo@collectd.org> | |
Sun, 11 Nov 2012 07:58:18 +0000 (08:58 +0100) |
Conflicts:
src/Makefile.am
src/Makefile.am
60 files changed:
index 90560e347acef55d1dc50bac405725b65a6e41fa..78dbad146745dc81edeb800909297eebd3735028 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
- netapp plugin.
- python plugin.
+Thomas Meson <zllak at hycik.org>
+ - Graphite support for the AMQP plugin.
+
Tomasz Pala <gotar at pld-linux.org>
- conntrack plugin.
diff --git a/bindings/Makefile.am b/bindings/Makefile.am
index f39e9bbb2778b60a47c138a4ea3ee8f02563126d..3876cc2c06d3f6ae70b08243cd18343b1c3f5a6f 100644 (file)
--- a/bindings/Makefile.am
+++ b/bindings/Makefile.am
perl/lib/Collectd/Plugins/Monitorus.pm \
perl/lib/Collectd/Plugins/OpenVZ.pm
+CLEANFILES = \
+ buildperl/Collectd.pm \
+ buildperl/Collectd/Plugins/OpenVZ.pm \
+ buildperl/Collectd/Unixsock.pm \
+ buildperl/Makefile.PL \
+ .perl-directory-stamp
+
+DISTCLEANFILES = \
+ buildperl/Collectd.pm \
+ buildperl/Collectd/Plugins/OpenVZ.pm \
+ buildperl/Collectd/Unixsock.pm \
+ buildperl/Makefile.PL \
+ .perl-directory-stamp
+
all-local: @PERL_BINDINGS@
+
install-exec-local:
- [ ! -f perl/Makefile ] || ( cd perl && $(MAKE) install )
+ [ ! -f buildperl/Makefile ] || ( cd buildperl && $(MAKE) install )
+
+# Perl 'make uninstall' does not work as well as wanted.
+# So we do the work here.
+uninstall-local:
+ rm -f $(DESTDIR)$(mandir)/man3/Collectd::Unixsock.3pm
+ rm -f $(DESTDIR)$(datarootdir)/perl5/Collectd.pm
+ rm -f $(DESTDIR)$(datarootdir)/perl5/Collectd/Plugins/OpenVZ.pm
+ rm -f $(DESTDIR)$(datarootdir)/perl5/Collectd/Unixsock.pm
+ rm -f $(DESTDIR)$(prefix)/lib64/perl5/perllocal.pod
+ rm -f $(DESTDIR)$(prefix)/lib64/perl5/auto/Collectd/.packlist
clean-local:
- [ ! -f perl/Makefile ] || ( cd perl && $(MAKE) realclean )
+ rm -rf buildperl
-perl: perl/Makefile
- cd perl && $(MAKE)
+perl: buildperl/Makefile
+ cd buildperl && $(MAKE)
-perl/Makefile: .perl-directory-stamp perl/Makefile.PL \
+buildperl/Makefile: .perl-directory-stamp buildperl/Makefile.PL \
$(top_builddir)/config.status
- cd perl && @PERL@ Makefile.PL PREFIX=$(prefix) @PERL_BINDINGS_OPTIONS@
+ cd buildperl && @PERL@ Makefile.PL INSTALL_BASE=$(prefix) @PERL_BINDINGS_OPTIONS@
+
+buildperl/Makefile.PL: .perl-directory-stamp $(top_builddir)/config.status
.perl-directory-stamp:
- if test ! -d perl; then \
- mkdir -p perl/Collectd/Plugins; \
- cp $(srcdir)/perl/Collectd.pm perl/; \
- cp $(srcdir)/perl/Makefile.PL perl/; \
- cp $(srcdir)/perl/Collectd/Unixsock.pm perl/Collectd/; \
- cp $(srcdir)/perl/Collectd/Plugins/OpenVZ.pm perl/Collectd/Plugins/; \
+ if test ! -d buildperl; then \
+ mkdir -p buildperl/Collectd/Plugins; \
+ cp $(srcdir)/perl/lib/Collectd.pm buildperl/; \
+ cp $(srcdir)/perl/Makefile.PL buildperl/; \
+ cp $(srcdir)/perl/lib/Collectd/Unixsock.pm buildperl/Collectd/; \
+ cp $(srcdir)/perl/lib/Collectd/Plugins/OpenVZ.pm buildperl/Collectd/Plugins/; \
fi
touch $@
diff --git a/configure.in b/configure.in
index cc3d4c4ed09ba5a841c1d3c7ef60644b316f28d6..83551076038882f3ee067d569dbd072f8b95a3d3 100644 (file)
--- a/configure.in
+++ b/configure.in
if test "x$ac_system" = "xSolaris"
then
AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Define to enforce POSIX thread semantics under Solaris.])
+ AC_DEFINE(_REENTRANT, 1, [Define to enable reentrancy interfaces.])
fi
if test "x$ac_system" = "xAIX"
then
#endif
])
+AC_CHECK_HEADERS(netinet/ip_compat.h)
+
# For the multimeter plugin
have_termios_h="no"
AC_CHECK_HEADERS(termios.h, [have_termios_h="yes"])
@@ -1225,6 +1228,7 @@ AC_CHECK_MEMBERS([struct kinfo_proc.ki_pid, struct kinfo_proc.ki_rssize, struct
have_struct_kinfo_proc_freebsd="no"
],
[
+AC_INCLUDES_DEFAULT
#include <kvm.h>
#include <sys/param.h>
#include <sys/sysctl.h>
have_struct_kinfo_proc_openbsd="no"
],
[
+AC_INCLUDES_DEFAULT
#include <sys/param.h>
#include <sys/sysctl.h>
#include <kvm.h>
# This could be in iptc or ip4tc
if test "x$with_libiptc" = "xpkgconfig"
then
+ SAVE_LIBS="$LIBS"
AC_SEARCH_LIBS(iptc_init, [iptc ip4tc],
[with_libiptc="pkgconfig"],
[with_libiptc="no"],
[$with_libiptc_libs])
+ LIBS="$SAVE_LIBS"
fi
if test "x$with_libiptc" = "xpkgconfig"
then
fi
if test "x$with_libnetlink" = "xyes"
then
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $with_libnetlink_cflags"
+
+ AC_CACHE_CHECK(
+ [if function 'rtnl_dump_filter' expects five arguments],
+ [c_cv_rtnl_dump_filter_five_args],
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+ [
+AC_INCLUDES_DEFAULT
+#include <asm/types.h>
+#include <sys/socket.h>
+#if HAVE_LIBNETLINK_H
+# include <libnetlink.h>
+#elif HAVE_IPROUTE_LIBNETLINK_H
+# include <iproute/libnetlink.h>
+#elif HAVE_LINUX_LIBNETLINK_H
+# include <linux/libnetlink.h>
+#endif
+ ],
+ [
+if (rtnl_dump_filter(NULL, NULL, NULL, NULL, NULL))
+ return 1;
+return 0;
+ ]
+ )],
+ [c_cv_rtnl_dump_filter_five_args="yes"],
+ [c_cv_rtnl_dump_filter_five_args="no"]
+ )
+ )
+
+ AC_CACHE_CHECK(
+ [if function 'rtnl_dump_filter' expects three arguments],
+ [c_cv_rtnl_dump_filter_three_args],
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
+ [
+AC_INCLUDES_DEFAULT
+#include <asm/types.h>
+#include <sys/socket.h>
+#if HAVE_LIBNETLINK_H
+# include <libnetlink.h>
+#elif HAVE_IPROUTE_LIBNETLINK_H
+# include <iproute/libnetlink.h>
+#elif HAVE_LINUX_LIBNETLINK_H
+# include <linux/libnetlink.h>
+#endif
+ ],
+ [
+if (rtnl_dump_filter(NULL, NULL, NULL))
+ return 1;
+return 0;
+ ]
+ )],
+ [c_cv_rtnl_dump_filter_three_args="yes"],
+ [c_cv_rtnl_dump_filter_three_args="no"]
+ )
+ )
+
+ CFLAGS="$SAVE_CFLAGS"
+
+ if test "x$c_cv_rtnl_dump_filter_five_args" = "xyes"
+ then
+ AC_DEFINE(RTNL_DUMP_FILTER_FIVE_ARGS, 1,
+ [Define to 1 if function 'rtnl_dump_filter' expects five arguments.])
+ fi
+ if test "x$c_cv_rtnl_dump_filter_three_args" = "xyes"
+ then
+ AC_DEFINE(RTNL_DUMP_FILTER_THREE_ARGS, 1,
+ [Define to 1 if function 'rtnl_dump_filter' expects three arguments.])
+ fi
+
BUILD_WITH_LIBNETLINK_CFLAGS="$with_libnetlink_cflags"
BUILD_WITH_LIBNETLINK_LIBS="$with_libnetlink_libs"
AC_SUBST(BUILD_WITH_LIBNETLINK_CFLAGS)
perl_interpreter="perl"
AC_ARG_WITH(libperl, [AS_HELP_STRING([--with-libperl@<:@=PREFIX@:>@], [Path to libperl.])],
[
- if test -x "$withval"
+ if test -f "$withval" && test -x "$withval"
then
perl_interpreter="$withval"
with_libperl="yes"
@@ -4057,7 +4134,7 @@ AC_ARG_WITH(libvarnish, [AS_HELP_STRING([--with-libvarnish@<:@=PREFIX@:>@], [Pat
then
AC_MSG_NOTICE([Not checking for libvarnish: Manually configured])
with_libvarnish_cflags="-I$withval/include"
- with_libvarnish_libs="-L$withval/lib -lvarnish -lvarnishcompat -lvarnishapi"
+ with_libvarnish_libs="-L$withval/lib -lvarnishapi"
with_libvarnish="yes"
fi; fi; fi
],
if test "x$with_perfstat" = "xyes"
then
plugin_cpu="yes"
+ plugin_contextswitch="yes"
plugin_disk="yes"
plugin_memory="yes"
plugin_swap="yes"
plugin_interface="yes"
plugin_load="yes"
+ plugin_uptime="yes"
fi
if test "x$with_procinfo" = "xyes"
diff --git a/contrib/README b/contrib/README
index bc1fe9ff10d384d16bc212f01cb20a4e2b0903cd..1ebf1f146e6332ce88f90b894ec233bbbc196946 100644 (file)
--- a/contrib/README
+++ b/contrib/README
-----------
Manifest file for the Solaris SMF system and detailed information on how to
register collectd as a service with this system.
+
+collectd.service
+----------------
+ Service file for systemd. Please ship this file as
+ /lib/systemd/system/collectd.service in any linux package of collectd.
diff --git a/contrib/collectd.service b/contrib/collectd.service
--- /dev/null
+++ b/contrib/collectd.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=statistics collection daemon
+Documentation=man:collectd(1)
+After=local-fs.target network.target
+Requires=local-fs.target network.target
+
+[Service]
+ExecStart=/usr/sbin/collectd -C /etc/collectd/collectd.conf -f
+Restart=always
+RestartSec=10
+StandardOutput=syslog
+StandardError=syslog
+
+[Install]
+WantedBy=multi-user.target
index 445b1838d0256dce0ce425daa2aadd8e0cdf5696..9af0fb008a72790e48562e7e6440c3bec8c6dd2a 100644 (file)
#
# Copyright © 2009 Adrian Perez <aperez@igalia.com>
#
-# Distributed under terms of the GPLv2 license.
+# Distributed under terms of the GPLv2 license or newer.
+#
+# Frank Marien (frank@apsu.be) 6 Sep 2012
+# - quick fixes for 5.1 binary protocol
+# - updated to python 3
+# - fixed for larger packet sizes (possible on lo interface)
+# - fixed comment typo (decode_network_string decodes a string)
"""
Collectd network protocol implementation.
"""
-import socket
-import struct
-
+import socket,struct,sys
try:
- from cStringIO import StringIO
+ from io import StringIO
except ImportError:
- from StringIO import StringIO
+ from cStringIO import StringIO
from datetime import datetime
from copy import deepcopy
DEFAULT_IPv6_GROUP = "ff18::efc0:4a42"
"""Default IPv6 multicast group"""
-
+HR_TIME_DIV = (2.0**30)
# Message kinds
TYPE_HOST = 0x0000
TYPE_TIME = 0x0001
+TYPE_TIME_HR = 0x0008
TYPE_PLUGIN = 0x0002
TYPE_PLUGIN_INSTANCE = 0x0003
TYPE_TYPE = 0x0004
TYPE_TYPE_INSTANCE = 0x0005
TYPE_VALUES = 0x0006
TYPE_INTERVAL = 0x0007
+TYPE_INTERVAL_HR = 0x0009
# For notifications
TYPE_MESSAGE = 0x0100
# DS kinds
DS_TYPE_COUNTER = 0
DS_TYPE_GAUGE = 1
-
+DS_TYPE_DERIVE = 2
+DS_TYPE_ABSOLUTE = 3
header = struct.Struct("!2H")
number = struct.Struct("!Q")
short = struct.Struct("!H")
double = struct.Struct("<d")
-
def decode_network_values(ptype, plen, buf):
"""Decodes a list of DS values in collectd network format
"""
assert double.size == number.size
result = []
- for dstype in map(ord, buf[header.size+short.size:off]):
+ for dstype in buf[header.size+short.size:off]:
if dstype == DS_TYPE_COUNTER:
result.append((dstype, number.unpack_from(buf, off)[0]))
off += valskip
elif dstype == DS_TYPE_GAUGE:
result.append((dstype, double.unpack_from(buf, off)[0]))
off += valskip
+ elif dstype == DS_TYPE_DERIVE:
+ result.append((dstype, number.unpack_from(buf, off)[0]))
+ off += valskip
+ elif dstype == DS_TYPE_ABSOLUTE:
+ result.append((dstype, number.unpack_from(buf, off)[0]))
+ off += valskip
else:
raise ValueError("DS type %i unsupported" % dstype)
def decode_network_number(ptype, plen, buf):
- """Decodes a number (64-bit unsigned) in collectd network format.
+ """Decodes a number (64-bit unsigned) from collectd network format.
"""
return number.unpack_from(buf, header.size)[0]
def decode_network_string(msgtype, plen, buf):
- """Decodes a floating point number (64-bit) in collectd network format.
+ """Decodes a string from collectd network format.
"""
return buf[header.size:plen-1]
_decoders = {
TYPE_VALUES : decode_network_values,
TYPE_TIME : decode_network_number,
+ TYPE_TIME_HR : decode_network_number,
TYPE_INTERVAL : decode_network_number,
+ TYPE_INTERVAL_HR : decode_network_number,
TYPE_HOST : decode_network_string,
TYPE_PLUGIN : decode_network_string,
TYPE_PLUGIN_INSTANCE: decode_network_string,
"""
off = 0
blen = len(buf)
+
while off < blen:
ptype, plen = header.unpack_from(buf, off)
off += plen
-
-
-
class Data(object):
time = 0
host = None
typeinstance = None
def __init__(self, **kw):
- [setattr(self, k, v) for k, v in kw.iteritems()]
+ [setattr(self, k, v) for k, v in kw.items()]
@property
def datetime(self):
def source(self):
buf = StringIO()
if self.host:
- buf.write(self.host)
+ buf.write(str(self.host))
if self.plugin:
buf.write("/")
- buf.write(self.plugin)
+ buf.write(str(self.plugin))
if self.plugininstance:
buf.write("/")
- buf.write(self.plugininstance)
+ buf.write(str(self.plugininstance))
if self.type:
buf.write("/")
- buf.write(self.type)
+ buf.write(str(self.type))
if self.typeinstance:
buf.write("/")
- buf.write(self.typeinstance)
+ buf.write(str(self.typeinstance))
return buf.getvalue()
def __str__(self):
for kind, data in iterable:
if kind == TYPE_TIME:
vl.time = nt.time = data
+ elif kind == TYPE_TIME_HR:
+ vl.time = nt.time = data / HR_TIME_DIV
elif kind == TYPE_INTERVAL:
vl.interval = data
+ elif kind == TYPE_INTERVAL_HR:
+ vl.interval = data / HR_TIME_DIV
elif kind == TYPE_HOST:
vl.host = nt.host = data
elif kind == TYPE_PLUGIN:
host = None
port = DEFAULT_PORT
- BUFFER_SIZE = 1024
+ BUFFER_SIZE = 16384
def __init__(self, host=None, port=DEFAULT_PORT, multicast=False):
"""
if iterable is None:
iterable = self.decode()
- if isinstance(iterable, basestring):
+ if isinstance(iterable, str):
iterable = self.decode(iterable)
return interpret_opcodes(iterable)
-
-
index 027961fa43ac73de432e0e7435768852c423f37b..a85027176c426dfd0f4e59c8fb109953d7237d42 100755 (executable)
$html_started = 0;
}
+sub contains_invalid_chars
+{
+ my $str = shift;
+
+ for (split (m//, $str))
+ {
+ my $n = ord ($_);
+
+ # Whitespace is allowed.
+ if (($n >= 9) && ($n <= 13))
+ {
+ next;
+ }
+ elsif ($n < 32)
+ {
+ return (1);
+ }
+ }
+
+ return;
+}
+
+sub contains_invalid_chars
+{
+ my $str = shift;
+
+ for (split (m//, $str))
+ {
+ my $n = ord ($_);
+
+ # Whitespace is allowed.
+ if (($n >= 9) && ($n <= 13))
+ {
+ next;
+ }
+ elsif ($n < 32)
+ {
+ return (1);
+ }
+ }
+
+ return;
+}
+
sub show_selector
{
my $timespan_selection = get_timespan_selection ();
HTML
for (sort (keys %$host_selection))
{
+ next if contains_invalid_chars ($_);
my $host = encode_entities ($_);
my $selected = $host_selection->{$_}
? ' selected="selected"'
HTML
for (sort (keys %$plugin_selection))
{
+ next if contains_invalid_chars ($_);
my $plugin = encode_entities ($_);
my $selected = $plugin_selection->{$_}
? ' selected="selected"'
HTML
for (sort { $TimeSpans->{$a} <=> $TimeSpans->{$b} } (keys (%$TimeSpans)))
{
+ next if contains_invalid_chars ($_);
my $name = encode_entities ($_);
my $value = $TimeSpans->{$_};
my $selected = ($value == $timespan_selection)
for (sort @hosts)
{
my $url = encode_entities (script_name () . "?action=show_selection;hostname=$_");
+ next if contains_invalid_chars ($_);
my $name = encode_entities ($_);
print qq# <li><a href="$url">$name</a></li>\n#;
}
diff --git a/contrib/collection3/lib/Collectd/Graph/Type/Df.pm b/contrib/collection3/lib/Collectd/Graph/Type/Df.pm
index 0fbd0d3593333354ad3f2ac1ad41e3b37dd485dd..4a70c41abef32245152a05c030b335ac5012970b 100644 (file)
my $obj = Collectd::Graph::Type->new (@_);
$obj->{'data_sources'} = [qw(free used)];
$obj->{'rrd_opts'} = ['-v', 'Bytes'];
- $obj->{'rrd_title'} = 'Disk space ({type_instance})';
+ $obj->{'rrd_title'} = 'Disk space ({instance})';
$obj->{'rrd_format'} = '%5.1lf%sB';
$obj->{'colors'} = [qw(00b000 ff0000)];
my $faded_green = get_faded_color ('00ff00');
my $faded_red = get_faded_color ('ff0000');
- return (['-t', 'Diskspace (' . $ident->{'type_instance'} . ')', '-v', 'Bytes', '-l', '0',
+ return (['-t', $obj->getTitle ($ident), '-v', 'Bytes', '-l', '0',
"DEF:free_min=${filename}:free:MIN",
"DEF:free_avg=${filename}:free:AVERAGE",
"DEF:free_max=${filename}:free:MAX",
diff --git a/contrib/migrate-4-5.px b/contrib/migrate-4-5.px
index d3ff796d3ed7d1139edacfebd638746bb8062c5d..c2a95558b236e96477e94884c0ab703ff4fd942a 100755 (executable)
--- a/contrib/migrate-4-5.px
+++ b/contrib/migrate-4-5.px
our $InDir = '/var/lib/collectd';
our $RRDtool = 'rrdtool';
+our $RRDFilter = 'rrd_filter.px';
our %TypesCounterToDerive = # {{{
(
{
my $dir = join ('/', @path);
print "mkdir -p \"$dir/$plugin-$type_inst\"\n";
- print "mv \"$path\" \"$dir/$plugin-$type_inst/$type.rrd\"\n";
+ if (($plugin eq 'df') and ($type eq 'df'))
+ {
+ print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-free.rrd\" --map free:value\n";
+ print "$RRDFilter --infile=\"$path\" --outfile=\"$dir/$plugin-$type_inst/df_complex-used.rrd\" --map used:value\n";
+ }
+ else
+ {
+ print "mv \"$path\" \"$dir/$plugin-$type_inst/$type.rrd\"\n";
+ }
}
} # }}} sub handle_file
Valid options are:
- --indir <dir> Source directory
- Default: $InDir
- --rrdtool <path> Path to the RRDtool binary
- Default: $RRDtool
+ --indir <dir> Source directory
+ Default: $InDir
+ --rrdtool <path> Path to the RRDtool binary
+ Default: $RRDtool
+ --rrdfilter <path> Path to the rrd_filter.px script
+ Default: $RRDFilter
EOF
exit (1);
GetOptions ("indir|i=s" => \$InDir,
"rrdtool=s" => \$RRDtool,
+ "rrdfilter=s" => \$RRDFilter,
"help|h" => \&exit_usage) or exit_usage ();
+print "#!/bin/bash\n\n";
+
scan_dir ($InDir);
# vim: set sw=2 sts=2 et fdm=marker :
diff --git a/src/Makefile.am b/src/Makefile.am
index 9d528c11c2a95acfffbbaf88b9eaba6380efd622..f4c699a35b1fdeb06f9da659a6318b3f86b21895 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
collectd_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL)
collectd_CFLAGS = $(AM_CFLAGS)
collectd_LDFLAGS = -export-dynamic
-collectd_LDADD =
+collectd_LDADD = -lm
collectd_DEPENDENCIES =
# Link to these libraries..
endif
if BUILD_AIX
collectd_LDFLAGS += -Wl,-bexpall,-brtllib
-collectd_LDADD += -lm
endif
# The daemon needs to call sg_init, so we need to link it against libstatgrab,
pkglib_LTLIBRARIES += amqp.la
amqp_la_SOURCES = amqp.c \
utils_cmd_putval.c utils_cmd_putval.h \
+ utils_format_graphite.c utils_format_graphite.h \
utils_format_json.c utils_format_json.h
amqp_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
pkglib_LTLIBRARIES += contextswitch.la
contextswitch_la_SOURCES = contextswitch.c
contextswitch_la_LDFLAGS = -module -avoid-version
+contextswitch_la_LIBADD =
+if BUILD_WITH_PERFSTAT
+contextswitch_la_LIBADD += -lperfstat
+endif
collectd_LDADD += "-dlopen" contextswitch.la
collectd_DEPENDENCIES += contextswitch.la
endif
if BUILD_WITH_LIBKSTAT
uptime_la_LIBADD += -lkstat
endif
+if BUILD_WITH_PERFSTAT
+uptime_la_LIBADD += -lperfstat
+endif
collectd_LDADD += "-dlopen" uptime.la
collectd_DEPENDENCIES += uptime.la
endif
if BUILD_PLUGIN_WRITE_GRAPHITE
pkglib_LTLIBRARIES += write_graphite.la
write_graphite_la_SOURCES = write_graphite.c \
- utils_format_json.c utils_format_json.h
+ utils_format_graphite.c utils_format_graphite.h \
+ utils_format_json.c utils_format_json.h
write_graphite_la_LDFLAGS = -module -avoid-version
collectd_LDADD += "-dlopen" write_graphite.la
collectd_DEPENDENCIES += write_graphite.la
fi
pinba.pb-c.c pinba.pb-c.h: pinba.proto
- protoc-c --c_out $(builddir) pinba.proto
+ protoc-c --c_out . pinba.proto
install-exec-hook:
$(mkinstalldirs) $(DESTDIR)$(sysconfdir)
$(INSTALL) -m 0644 $(srcdir)/postgresql_default.conf \
$(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
+uninstall-hook:
+ rm -f $(DESTDIR)$(pkgdatadir)/types.db;
+ rm -f $(DESTDIR)$(sysconfdir)/collectd.conf
+ rm -f $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
+
if BUILD_FEATURE_DEBUG
bin_PROGRAMS += utils_vl_lookup_test
utils_vl_lookup_test_SOURCES = utils_vl_lookup_test.c \
diff --git a/src/amqp.c b/src/amqp.c
index 55d2a2ceff04f3772e43c21c4288ec6d97c1ddb2..c9e46c45df0cac7ef0e0cc4f3bdd2e1bda8ad96e 100644 (file)
--- a/src/amqp.c
+++ b/src/amqp.c
#include "plugin.h"
#include "utils_cmd_putval.h"
#include "utils_format_json.h"
+#include "utils_format_graphite.h"
#include <pthread.h>
#define CAMQP_DM_VOLATILE 1
#define CAMQP_DM_PERSISTENT 2
-#define CAMQP_FORMAT_COMMAND 1
-#define CAMQP_FORMAT_JSON 2
+#define CAMQP_FORMAT_COMMAND 1
+#define CAMQP_FORMAT_JSON 2
+#define CAMQP_FORMAT_GRAPHITE 3
#define CAMQP_CHANNEL 1
uint8_t delivery_mode;
_Bool store_rates;
int format;
+ /* publish & graphite format only */
+ char *prefix;
+ char *postfix;
+ char escape_char;
/* subscribe only */
char *exchange_type;
sfree (conf->exchange_type);
sfree (conf->queue);
sfree (conf->routing_key);
+ sfree (conf->prefix);
+ sfree (conf->postfix);
+
sfree (conf);
} /* }}} void camqp_config_free */
camqp_config_free (conf);
pthread_exit (NULL);
+ return (NULL);
} /* }}} void *camqp_subscribe_thread */
static int camqp_subscribe_init (camqp_config_t *conf) /* {{{ */
props.content_type = amqp_cstring_bytes("text/collectd");
else if (conf->format == CAMQP_FORMAT_JSON)
props.content_type = amqp_cstring_bytes("application/json");
+ else if (conf->format == CAMQP_FORMAT_GRAPHITE)
+ props.content_type = amqp_cstring_bytes("text/graphite");
else
assert (23 == 42);
props.delivery_mode = conf->delivery_mode;
@@ -776,6 +788,18 @@ static int camqp_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
format_json_value_list (buffer, &bfill, &bfree, ds, vl, conf->store_rates);
format_json_finalize (buffer, &bfill, &bfree);
}
+ else if (conf->format == CAMQP_FORMAT_GRAPHITE)
+ {
+ status = format_graphite (buffer, sizeof (buffer), ds, vl,
+ conf->prefix, conf->postfix, conf->escape_char,
+ conf->store_rates);
+ if (status != 0)
+ {
+ ERROR ("amqp plugin: format_graphite failed with status %i.",
+ status);
+ return (status);
+ }
+ }
else
{
ERROR ("amqp plugin: Invalid format (%i).", conf->format);
conf->format = CAMQP_FORMAT_COMMAND;
else if (strcasecmp ("JSON", string) == 0)
conf->format = CAMQP_FORMAT_JSON;
+ else if (strcasecmp ("Graphite", string) == 0)
+ conf->format = CAMQP_FORMAT_GRAPHITE;
else
{
WARNING ("amqp plugin: Invalid format string: %s",
/* publish only */
conf->delivery_mode = CAMQP_DM_VOLATILE;
conf->store_rates = 0;
+ /* publish & graphite only */
+ conf->prefix = NULL;
+ conf->postfix = NULL;
+ conf->escape_char = '_';
/* subscribe only */
conf->exchange_type = NULL;
conf->queue = NULL;
status = cf_util_get_boolean (child, &conf->store_rates);
else if ((strcasecmp ("Format", child->key) == 0) && publish)
status = camqp_config_set_format (child, conf);
+ else if ((strcasecmp ("GraphitePrefix", child->key) == 0) && publish)
+ status = cf_util_get_string (child, &conf->prefix);
+ else if ((strcasecmp ("GraphitePostfix", child->key) == 0) && publish)
+ status = cf_util_get_string (child, &conf->postfix);
+ else if ((strcasecmp ("GraphiteEscapeChar", child->key) == 0) && publish)
+ {
+ char *tmp_buff = NULL;
+ status = cf_util_get_string (child, &tmp_buff);
+ if (strlen (tmp_buff) > 1)
+ WARNING ("amqp plugin: The option \"GraphiteEscapeChar\" handles "
+ "only one character. Others will be ignored.");
+ conf->escape_char = tmp_buff[0];
+ sfree (tmp_buff);
+ }
else
WARNING ("amqp plugin: Ignoring unknown "
"configuration option \"%s\".", child->key);
diff --git a/src/apcups.c b/src/apcups.c
index a0629d5f6ae0a87e13b08f1e53f6d69b0c1a85f3..4fbbde63aad113dcbefdbc2db47e545ca3b5c241 100644 (file)
--- a/src/apcups.c
+++ b/src/apcups.c
/*
* collectd - src/apcups.c
- * Copyright (C) 2006-2007 Florian octo Forster
+ * Copyright (C) 2006-2012 Florian octo Forster
* Copyright (C) 2006 Anthony Gialluca <tonyabg at charter.net>
* Copyright (C) 2000-2004 Kern Sibbald
* Copyright (C) 1996-1999 Andre M. Hedrick <andre at suse.com>
static int global_sockfd = -1;
+static int count_retries = 0;
+static int count_iterations = 0;
+static _Bool close_socket = 0;
+
static const char *config_keys[] =
{
"Host",
};
static int config_keys_num = 2;
-/* Close the network connection */
-static int apcups_shutdown (void)
+static int net_shutdown (int *fd)
{
uint16_t packet_size = 0;
- if (global_sockfd < 0)
- return (0);
+ if ((fd == NULL) || (*fd < 0))
+ return (EINVAL);
- DEBUG ("Gracefully shutting down socket %i.", global_sockfd);
+ swrite (*fd, (void *) &packet_size, sizeof (packet_size));
+ close (*fd);
+ *fd = -1;
- /* send EOF sentinel */
- swrite (global_sockfd, (void *) &packet_size, sizeof (packet_size));
+ return (0);
+} /* int net_shutdown */
- close (global_sockfd);
- global_sockfd = -1;
+/* Close the network connection */
+static int apcups_shutdown (void)
+{
+ if (global_sockfd < 0)
+ return (0);
+ net_shutdown (&global_sockfd);
return (0);
} /* int apcups_shutdown */
-/*
+/*
* Open a TCP connection to the UPS network server
* Returns -1 on error
* Returns socket file descriptor otherwise
return (sd);
} /* int net_open (char *host, char *service, int port) */
-/*
+/*
* Receive a message from the other end. Each message consists of
* two packets. The first is a header that contains the size
* of the data that follows in the second packet.
/* get data size -- in short */
if (sread (*sockfd, (void *) &packet_size, sizeof (packet_size)) != 0)
{
+ close (*sockfd);
*sockfd = -1;
return (-1);
}
packet_size = ntohs (packet_size);
if (packet_size > buflen)
{
- DEBUG ("record length too large");
+ ERROR ("apcups plugin: Received %"PRIu16" bytes of payload "
+ "but have only %i bytes of buffer available.",
+ packet_size, buflen);
+ close (*sockfd);
+ *sockfd = -1;
return (-2);
}
/* now read the actual data */
if (sread (*sockfd, (void *) buf, packet_size) != 0)
{
+ close (*sockfd);
*sockfd = -1;
return (-1);
}
if (swrite (*sockfd, (void *) &packet_size, sizeof (packet_size)) != 0)
{
+ close (*sockfd);
*sockfd = -1;
return (-1);
}
/* send data packet */
if (swrite (*sockfd, (void *) buff, len) != 0)
{
+ close (*sockfd);
*sockfd = -1;
return (-2);
}
char *toksaveptr;
char *key;
double value;
+ _Bool retry = 1;
+ int status;
#if APCMAIN
# define PRINT_VALUE(name, val) printf(" Found property: name = %s; value = %f;\n", name, val)
# define PRINT_VALUE(name, val) /**/
#endif
- if (global_sockfd < 0)
+ while (retry)
{
- global_sockfd = net_open (host, port);
if (global_sockfd < 0)
{
- ERROR ("apcups plugin: Connecting to the "
- "apcupsd failed.");
+ global_sockfd = net_open (host, port);
+ if (global_sockfd < 0)
+ {
+ ERROR ("apcups plugin: Connecting to the "
+ "apcupsd failed.");
+ return (-1);
+ }
+ }
+
+
+ status = net_send (&global_sockfd, "status", strlen ("status"));
+ if (status != 0)
+ {
+ /* net_send is closing the socket on error. */
+ assert (global_sockfd < 0);
+ if (retry)
+ {
+ retry = 0;
+ count_retries++;
+ continue;
+ }
+
+ ERROR ("apcups plugin: Writing to the socket failed.");
return (-1);
}
- }
- if (net_send (&global_sockfd, "status", 6) < 0)
+ break;
+ } /* while (retry) */
+
+ /* When collectd's collection interval is larger than apcupsd's
+ * timeout, we would have to retry / re-connect each iteration. Try to
+ * detect this situation and shut down the socket gracefully in that
+ * case. Otherwise, keep the socket open to avoid overhead. */
+ count_iterations++;
+ if ((count_iterations == 10) && (count_retries > 2))
{
- ERROR ("apcups plugin: Writing to the socket failed.");
- return (-1);
+ NOTICE ("apcups plugin: There have been %i retries in the "
+ "first %i iterations. Will close the socket "
+ "in future iterations.",
+ count_retries, count_iterations);
+ close_socket = 1;
}
while ((n = net_recv (&global_sockfd, recvline, sizeof (recvline) - 1)) > 0)
if (strcmp ("LINEV", key) == 0)
apcups_detail->linev = value;
- else if (strcmp ("BATTV", key) == 0)
+ else if (strcmp ("BATTV", key) == 0)
apcups_detail->battv = value;
else if (strcmp ("ITEMP", key) == 0)
apcups_detail->itemp = value;
tokptr = strtok_r (NULL, ":", &toksaveptr);
} /* while (tokptr != NULL) */
}
-
+ status = errno; /* save errno, net_shutdown() may re-set it. */
+
+ if (close_socket)
+ net_shutdown (&global_sockfd);
+
if (n < 0)
{
- WARNING ("apcups plugin: Error reading from socket");
+ char errbuf[1024];
+ ERROR ("apcups plugin: Reading from socket failed: %s",
+ sstrerror (status, errbuf, sizeof (errbuf)));
return (-1);
}
apcups_detail.timeleft = -1.0;
apcups_detail.itemp = -300.0;
apcups_detail.linefreq = -1.0;
-
+
status = apc_query_server (conf_host == NULL
? APCUPS_DEFAULT_HOST
: conf_host,
conf_port, &apcups_detail);
-
+
/*
* if we did not connect then do not bother submitting
* zeros. We want rrd files to have NAN.
diff --git a/src/collectd.c b/src/collectd.c
index d33d1d6685ff4755d9ab460a526313b468d6f71d..ceb184b012879d475e90f66108ac732ae2a193b3 100644 (file)
--- a/src/collectd.c
+++ b/src/collectd.c
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&thread, &attr, do_flush, NULL);
+ pthread_attr_destroy (&attr);
}
static int init_hostname (void)
static int change_basedir (const char *orig_dir)
{
- char *dir = strdup (orig_dir);
- int dirlen;
+ char *dir;
+ size_t dirlen;
int status;
+ dir = strdup (orig_dir);
if (dir == NULL)
{
char errbuf[1024];
return (-1);
status = chdir (dir);
- free (dir);
+ if (status == 0)
+ {
+ free (dir);
+ return (0);
+ }
+ else if (errno != ENOENT)
+ {
+ char errbuf[1024];
+ ERROR ("change_basedir: chdir (%s): %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ free (dir);
+ return (-1);
+ }
+ status = mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO);
if (status != 0)
{
- if (errno == ENOENT)
- {
- if (mkdir (orig_dir, 0755) == -1)
- {
- char errbuf[1024];
- ERROR ("change_basedir: mkdir (%s): %s", orig_dir,
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
- }
- else if (chdir (orig_dir) == -1)
- {
- char errbuf[1024];
- ERROR ("chdir (%s): %s", orig_dir,
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
- }
- }
- else
- {
- char errbuf[1024];
- ERROR ("chdir (%s): %s", orig_dir,
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
- }
+ char errbuf[1024];
+ ERROR ("change_basedir: mkdir (%s): %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ free (dir);
+ return (-1);
+ }
+
+ status = chdir (dir);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("change_basedir: chdir (%s): %s", dir,
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ free (dir);
+ return (-1);
}
+ free (dir);
return (0);
} /* static int change_basedir (char *dir) */
diff --git a/src/collectd.conf.in b/src/collectd.conf.in
index ebddb2b8e7d37df701ca96094ccb955a6abf41ae..9f5dedcdf0ad64d38566212bb53fdb4f48f03fea 100644 (file)
--- a/src/collectd.conf.in
+++ b/src/collectd.conf.in
#</Plugin>
#<Plugin memcached>
-# Host "127.0.0.1"
-# Port "11211"
+# <Instance "local">
+# Host "127.0.0.1"
+# Port "11211"
+# </Instance>
#</Plugin>
#<Plugin modbus>
# Host "localhost"
# Port 123
# ReverseLookups false
+# IncludeUnitID true
#</Plugin>
#<Plugin nut>
#<Plugin "swap">
# ReportByDevice false
+# ReportBytes true
#</Plugin>
#<Plugin "table">
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index 284c36c4dea93d7ff66f6167a16fd8da4d527930..f6f61c7e3da30285d516663ab9d901fbed2cb9ce 100644 (file)
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
behavior.
The syntax of this config file is similar to the config file of the famous
-B<Apache Webserver>. Each line contains either a key-value-pair or a
-section-start or -end. Empty lines and everything after the hash-symbol `#' is
-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. 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
-is a good idea to load any logging plugins first in order to catch messages
-from plugins during configuration. Also, the C<LoadPlugin> option B<must> occur
-B<before> the C<E<lt>Plugin ...E<gt>> block.
+I<Apache> webserver. Each line contains either an option (a key and a list of
+one or more values) or a section-start or -end. Empty lines and everything
+after a non-quoted hash-symbol (C<#>) is ignored. I<Keys> are unquoted
+strings, consisting only of alphanumeric characters and the underscore (C<_>)
+character. Keys are handled case insensitive by I<collectd> itself and all
+plugins included with it. I<Values> can either be an I<unquoted string>, a
+I<quoted string> (enclosed in double-quotes) a I<number> or a I<boolean>
+expression. I<Unquoted strings> consist of only alphanumeric characters and
+underscores (C<_>) and do not need to be quoted. I<Quoted strings> are
+enclosed in double quotes (C<">). You can use the backslash character (C<\>)
+to include double quotes as part of the string. I<Numbers> can be specified in
+decimal and floating point format (using a dot C<.> as decimal separator),
+hexadecimal when using the C<0x> prefix and octal with a leading zero (C<0>).
+I<Boolean> values are either B<true> or B<false>.
+
+Lines may be wrapped by using C<\> 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. from top to bottom. So
+the plugins are loaded in the order listed in this config file. It is a good
+idea to load any logging plugins first in order to catch messages from plugins
+during configuration. Also, the C<LoadPlugin> option B<must> occur B<before>
+the appropriate C<E<lt>Plugin ...E<gt>> block.
=head1 GLOBAL OPTIONS
# Persistent false
# Format "command"
# StoreRates false
+ # GraphitePrefix "collectd."
+ # GraphiteEscapeChar "_"
</Publish>
# Receive values from an AMQP broker
@@ -420,6 +432,10 @@ If set to B<JSON>, the values are encoded in the I<JavaScript Object Notation>,
an easy and straight forward exchange format. The C<Content-Type> header field
will be set to C<application/json>.
+If set to B<Graphite>, values are encoded in the I<Graphite> format, which is
+"<metric> <value> <timestamp>\n". The C<Content-Type> header field will be set to
+C<text/graphite>.
+
A subscribing client I<should> use the C<Content-Type> header field to
determine how to decode the values. Currently, the I<AMQP plugin> itself can
only decode the B<Command> format.
Please note that currently this option is only used if the B<Format> option has
been set to B<JSON>.
+=item B<GraphitePrefix> (Publish and B<Format>=I<Graphite> only)
+
+A prefix can be added in the metric name when outputting in the I<Graphite> format.
+It's added before the I<Host> name.
+Metric name will be "<prefix><host><postfix><plugin><type><name>"
+
+=item B<GraphitePostfix> (Publish and B<Format>=I<Graphite> only)
+
+A postfix can be added in the metric name when outputting in the I<Graphite> format.
+It's added after the I<Host> name.
+Metric name will be "<prefix><host><postfix><plugin><type><name>"
+
+=item B<GraphiteEscapeChar> (Publish and B<Format>=I<Graphite> only)
+
+Specify a character to replace dots (.) in the host part of the metric name.
+In I<Graphite> metric name, dots are used as separators between different
+metric parts (host, plugin, type).
+Default is "_" (I<Underscore>).
+
=back
=head2 Plugin C<apache>
@@ -2049,6 +2084,17 @@ The C<memcached plugin> connects to a memcached server and queries statistics
about cache utilization, memory and bandwidth used.
L<http://www.danga.com/memcached/>
+ <Plugin "memcached">
+ <Instance "name">
+ Host "memcache.example.com"
+ Port 11211
+ </Instance>
+ </Plugin>
+
+The plugin configuration consists of one or more B<Instance> blocks which
+specify one I<memcached> connection each. Within the B<Instance> blocks, the
+following options are allowed:
+
=over 4
=item B<Host> I<Hostname>
TCP-Port to connect to. Defaults to B<11211>.
+=item B<Socket> I<Path>
+
+Connect to I<memcached> using the UNIX domain socket at I<Path>. If this
+setting is given, the B<Host> and B<Port> settings are ignored.
+
=back
=head2 Plugin C<modbus>
lookups. The default is to do reverse lookups to preserve backwards
compatibility, though.
+=item B<IncludeUnitID> B<true>|B<false>
+
+When a peer is a refclock, include the unit ID in the I<type instance>.
+Defaults to B<false> for backward compatibility.
+
+If two refclock peers use the same driver and this is B<false>, the plugin will
+try to write simultaneous measurements from both to the same type instance.
+This will result in error messages in the log and only one set of measurements
+making it through.
+
=back
=head2 Plugin C<nut>
The name of the database of the current connection.
+=item I<instance>
+
+The name of the database plugin instance. See the B<Instance> option of the
+database specification below for details.
+
=item I<username>
The username used to connect to the database.
Specify whether to use an SSL connection when contacting the server. The
following modes are supported:
+=item B<Instance> I<name>
+
+Specify the plugin instance name that should be used instead of the database
+name (which is the default, if this option has not been specified). This
+allows to query multiple databases of the same name on the same host (e.g.
+when running multiple database server versions in parallel).
+
=over 4
=item I<disable>
connections. Either a service name of a port number may be given. Please note
that numerical port numbers must be given as a string, too.
+=item B<Password> I<Password>
+
+Use I<Password> to authenticate when connecting to I<Redis>.
+
=item B<Timeout> I<Timeout in miliseconds>
The B<Timeout> option set the socket timeout for node response. Since the Redis
locally, or B<DataDir> is set to a relative path, this will not work as
expected. Default is B<true>.
+=item B<StepSize> I<Seconds>
+
+B<Force> the stepsize of newly created RRD-files. Ideally (and per default)
+this setting is unset and the stepsize is set to the interval in which the data
+is collected. Do not use this option unless you absolutely have to for some
+reason. Setting this option may cause problems with the C<snmp plugin>, the
+C<exec plugin> or when the daemon is set up to receive data from other hosts.
+
+=item B<HeartBeat> I<Seconds>
+
+B<Force> the heartbeat of newly created RRD-files. This setting should be unset
+in which case the heartbeat is set to twice the B<StepSize> which should equal
+the interval in which data is collected. Do not set this option unless you have
+a very good reason to do so.
+
+=item B<RRARows> I<NumRows>
+
+The C<rrdtool plugin> calculates the number of PDPs per CDP based on the
+B<StepSize>, this setting and a timespan. This plugin creates RRD-files with
+three times five RRAs, i. e. five RRAs with the CFs B<MIN>, B<AVERAGE>, and
+B<MAX>. The five RRAs are optimized for graphs covering one hour, one day, one
+week, one month, and one year.
+
+So for each timespan, it calculates how many PDPs need to be consolidated into
+one CDP by calculating:
+ number of PDPs = timespan / (stepsize * rrarows)
+
+Bottom line is, set this no smaller than the width of you graphs in pixels. The
+default is 1200.
+
+=item B<RRATimespan> I<Seconds>
+
+Adds an RRA-timespan, given in seconds. Use this option multiple times to have
+more then one RRA. If this option is never used, the built-in default of (3600,
+86400, 604800, 2678400, 31622400) is used.
+
+For more information on how RRA-sizes are calculated see B<RRARows> above.
+
+=item B<XFF> I<Factor>
+
+Set the "XFiles Factor". The default is 0.1. If unsure, don't set this option.
+I<Factor> must be in the range C<[0.0-1.0)>, i.e. between zero (inclusive) and
+one (exclusive).
+
=back
=head2 Plugin C<rrdtool>
=item B<XFF> I<Factor>
Set the "XFiles Factor". The default is 0.1. If unsure, don't set this option.
+I<Factor> must be in the range C<[0.0-1.0)>, i.e. between zero (inclusive) and
+one (exclusive).
=item B<CacheFlush> I<Seconds>
This option is only available if the I<Swap plugin> can read C</proc/swaps>
(under Linux) or use the L<swapctl(2)> mechanism (under I<Solaris>).
+=item B<ReportBytes> B<false>|B<true>
+
+When enabled, the I<swap I/O> is reported in bytes. When disabled, the default,
+I<swap I/O> is reported in pages. This option is available under Linux only.
+
=back
=head2 Plugin C<syslog>
If set to B<true>, the plugin instance and type instance will be in their own
path component, for example C<host.cpu.0.cpu.idle>. If set to B<false> (the
default), the plugin and plugin instance (and likewise the type and type
-instance) are put into once component, for example C<host.cpu-0.cpu-idle>.
+instance) are put into one component, for example C<host.cpu-0.cpu-idle>.
=item B<AlwaysAppendDS> B<false>|B<true>
diff --git a/src/collectdctl.c b/src/collectdctl.c
index 3bd8f0410f846ddf21130bf93ac8059555a7c269..61b7fc55e2c24ff880730580abf2d48e0e0f571d 100644 (file)
--- a/src/collectdctl.c
+++ b/src/collectdctl.c
while (value != 0) {
char *dot, *endptr;
- tmp = strchr (argv[i], (int)':');
+ tmp = strchr (value, (int)':');
if (tmp != NULL) {
*tmp = '\0';
diff --git a/src/common.c b/src/common.c
index 9098de5908db7bbb306915b8cc0480263774d1e1..b679bf70f4ccff6a385c47b5fb4f47ccbd26a8b1 100644 (file)
--- a/src/common.c
+++ b/src/common.c
{
if (errno == ENOENT)
{
- if (mkdir (dir, 0755) == 0)
+ if (mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
break;
/* this might happen, if a different thread created
kstat_named_t *kn;
long long retval = -1LL;
-#ifdef assert
- assert (ksp != NULL);
- assert (ksp->ks_type == KSTAT_TYPE_NAMED);
-#else
if (ksp == NULL)
{
- ERROR ("ERROR: %s:%i: ksp == NULL\n", __FILE__, __LINE__);
+ ERROR ("get_kstat_value (\"%s\"): ksp is NULL.", name);
return (-1LL);
}
else if (ksp->ks_type != KSTAT_TYPE_NAMED)
{
- ERROR ("ERROR: %s:%i: ksp->ks_type != KSTAT_TYPE_NAMED\n", __FILE__, __LINE__);
+ ERROR ("get_kstat_value (\"%s\"): ksp->ks_type (%#x) "
+ "is not KSTAT_TYPE_NAMED (%#x).",
+ name,
+ (unsigned int) ksp->ks_type,
+ (unsigned int) KSTAT_TYPE_NAMED);
return (-1LL);
}
-#endif
if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL)
- return (retval);
+ return (-1LL);
if (kn->data_type == KSTAT_DATA_INT32)
retval = (long long) kn->value.i32;
diff --git a/src/contextswitch.c b/src/contextswitch.c
index c207318f9d62425fbfb18e7e86727bce62b65bcb..344f76e76f0c29242ac20821d8efb25f83f12871 100644 (file)
--- a/src/contextswitch.c
+++ b/src/contextswitch.c
/* no global variables */
/* #endif KERNEL_LINUX */
+#elif HAVE_PERFSTAT
+# include <sys/protosw.h>
+# include <libperfstat.h>
+/* #endif HAVE_PERFSTAT */
+
#else
# error "No applicable input method."
#endif
if (status == -2)
ERROR ("contextswitch plugin: Unable to find context switch value.");
-#endif /* KERNEL_LINUX */
+/* #endif KERNEL_LINUX */
+
+#elif HAVE_PERFSTAT
+ int status = 0;
+ perfstat_cpu_total_t perfcputotal;
+
+ status = perfstat_cpu_total(NULL, &perfcputotal, sizeof(perfstat_cpu_total_t), 1);
+ if (status < 0)
+ {
+ char errbuf[1024];
+ ERROR ("contextswitch plugin: perfstat_cpu_total: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ cs_submit(perfcputotal.pswitch);
+ status = 0;
+#endif /* defined(HAVE_PERFSTAT) */
return status;
}
diff --git a/src/curl_xml.c b/src/curl_xml.c
index 052ea1e61244d92d509501ea0daf800f19f454f3..46e0d490967456156863413912fe234deeb5abda 100644 (file)
--- a/src/curl_xml.c
+++ b/src/curl_xml.c
return (0);
} /* }}} int cx_handle_instance_xpath */
-static int cx_handle_base_xpath (char *plugin_instance, /* {{{ */
+static int cx_handle_base_xpath (char const *plugin_instance, /* {{{ */
+ char const *host,
xmlXPathContextPtr xpath_ctx, const data_set_t *ds,
char *base_xpath, cx_xpath_t *xpath)
{
vl.values_len = ds->ds_num;
sstrncpy (vl.type, xpath->type, sizeof (vl.type));
sstrncpy (vl.plugin, "curl_xml", sizeof (vl.plugin));
- sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.host, (host != NULL) ? host : hostname_g, sizeof (vl.host));
if (plugin_instance != NULL)
sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance));
ds = plugin_get_ds (xpath->type);
if ( (cx_check_type(ds, xpath) == 0) &&
- (cx_handle_base_xpath(db->instance, xpath_ctx, ds, le->key, xpath) == 0) )
+ (cx_handle_base_xpath(db->instance, db->host,
+ xpath_ctx, ds, le->key, xpath) == 0) )
status = 0; /* we got atleast one success */
le = le->next;
diff --git a/src/df.c b/src/df.c
index 41a03cbf6280067815419d8802c5d431c0fd239f..ded374b942e5d08d804dd027292eef2ef9f50fcb 100644 (file)
--- a/src/df.c
+++ b/src/df.c
{
if (strcmp (mnt_ptr->dir, "/") == 0)
{
+ if (strcmp (mnt_ptr->type, "rootfs") == 0)
+ continue;
sstrncpy (disk_name, "root", sizeof (disk_name));
}
else
diff --git a/src/disk.c b/src/disk.c
index fde0dcde9abd5112c48633a6dcd588ef8bb0f69b..7411c22588abd4e409f25027d784bd83b62af62a 100644 (file)
--- a/src/disk.c
+++ b/src/disk.c
plugin_dispatch_values (&vl);
} /* void disk_submit */
+#if KERNEL_LINUX
+static counter_t disk_calc_time_incr (counter_t delta_time, counter_t delta_ops)
+{
+ double avg_time = ((double) delta_time) / ((double) delta_ops);
+ double avg_time_incr = CDTIME_T_TO_DOUBLE (interval_g) * avg_time;
+
+ return ((counter_t) (avg_time_incr + .5));
+}
+#endif
+
#if HAVE_IOKIT_IOKITLIB_H
static signed long long dict_get_value (CFDictionaryRef dict, const char *key)
{
diff_write_time = write_time - ds->write_time;
if (diff_read_ops != 0)
- ds->avg_read_time += (diff_read_time
- + (diff_read_ops / 2))
- / diff_read_ops;
+ ds->avg_read_time += disk_calc_time_incr (
+ diff_read_time, diff_read_ops);
if (diff_write_ops != 0)
- ds->avg_write_time += (diff_write_time
- + (diff_write_ops / 2))
- / diff_write_ops;
+ ds->avg_write_time += disk_calc_time_incr (
+ diff_write_time, diff_write_ops);
ds->read_ops = read_ops;
ds->read_time = read_time;
diff --git a/src/email.c b/src/email.c
index 8fc5509f3e7e5ece33a15015b0ffa40fde6d6ede..5870ab1de1498593d4636973a65444d4e918d558 100644 (file)
--- a/src/email.c
+++ b/src/email.c
} /* while (1) */
pthread_exit ((void *)0);
+ return ((void *) 0);
} /* static void *collect (void *) */
static void *open_connection (void __attribute__((unused)) *arg)
pthread_cond_signal (&conn_available);
}
- pthread_exit ((void *)0);
+
+ pthread_exit ((void *) 0);
+ return ((void *) 0);
} /* static void *open_connection (void *) */
static int email_init (void)
diff --git a/src/ethstat.c b/src/ethstat.c
index ae1b68931d898830cca2a67e9aa2cc8034371803..08381a821087e275fb03922a32bc54c35ca7c3cd 100644 (file)
--- a/src/ethstat.c
+++ b/src/ethstat.c
if (tmp == NULL)
return (-1);
interfaces = tmp;
+ interfaces[interfaces_num] = NULL;
status = cf_util_get_string (ci, interfaces + interfaces_num);
if (status != 0)
memset (map, 0, sizeof (*map));
sstrncpy (map->type, ci->values[1].value.string, sizeof (map->type));
- if (ci->values_num == 2)
+ if (ci->values_num == 3)
sstrncpy (map->type_instance, ci->values[2].value.string,
sizeof (map->type_instance));
diff --git a/src/exec.c b/src/exec.c
index c5ea155ebc53f10e4d191bc84dca0828476a953a..0e807c75bc18e7dc59547471b3c35c57915979ac 100644 (file)
--- a/src/exec.c
+++ b/src/exec.c
if (len < 0)
{
- if (errno == EAGAIN || errno == EINTR) continue;
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
break;
}
else if (len == 0)
{
/* We've reached EOF */
- NOTICE ("exec plugin: Program `%s' has closed STDERR.",
- pl->exec);
- close (fd_err);
+ NOTICE ("exec plugin: Program `%s' has closed STDERR.", pl->exec);
+
+ /* Remove file descriptor form select() set. */
FD_CLR (fd_err, &fdset);
+ copy = fdset;
highest_fd = fd;
+
+ /* Clean up file descriptor */
+ close (fd_err);
fd_err = -1;
continue;
}
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&t, &attr, exec_read_one, (void *) pl);
+ pthread_attr_destroy (&attr);
} /* for (pl) */
return (0);
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&t, &attr, exec_notification_one, (void *) pln);
+ pthread_attr_destroy (&attr);
} /* for (pl) */
return (0);
index 5b7aa94a9e4deec315c5175f8503a4900536e3c1..19f58b2b75c4f19b9b196f5d15b85f8f78dd21ac 100644 (file)
--- a/src/liboconfig/parser.y
+++ b/src/liboconfig/parser.y
$$.children = $2.statement;
$$.children_num = $2.statement_num;
}
+ | block_begin block_end
+ {
+ if (strcmp ($1.key, $2) != 0)
+ {
+ printf ("block_begin = %s; block_end = %s;\n", $1.key, $2);
+ yyerror ("Block not closed..\n");
+ exit (1);
+ }
+ free ($2); $2 = NULL;
+ $$ = $1;
+ $$.children = NULL;
+ $$.children_num = 0;
+ }
;
statement:
ci_root->children = $1.statement;
ci_root->children_num = $1.statement_num;
}
+ | /* epsilon */
+ {
+ ci_root = malloc (sizeof (oconfig_item_t));
+ memset (ci_root, '\0', sizeof (oconfig_item_t));
+ ci_root->children = NULL;
+ ci_root->children_num = 0;
+ }
;
%%
diff --git a/src/memcachec.c b/src/memcachec.c
index 8f51e22f01dd3c2d728d0cbc0a8e2cc61fba99e1..c57a831226d4da64691922a7a43983c5b37eeee1 100644 (file)
--- a/src/memcachec.c
+++ b/src/memcachec.c
if (strcasecmp ("Server", child->key) == 0)
status = cmc_config_add_string ("Server", &page->server, child);
- if (strcasecmp ("Key", child->key) == 0)
+ else if (strcasecmp ("Key", child->key) == 0)
status = cmc_config_add_string ("Key", &page->key, child);
else if (strcasecmp ("Match", child->key) == 0)
/* Be liberal with failing matches => don't set `status'. */
diff --git a/src/memcached.c b/src/memcached.c
index 48fa713b8dbbe3aebf83f7130cf3988d18717dd3..a09f45ec6dae1a2e537fe986af7677f4130bd662 100644 (file)
--- a/src/memcached.c
+++ b/src/memcached.c
/**
* collectd - src/memcached.c, based on src/hddtemp.c
* Copyright (C) 2007 Antony Dovgal
- * Copyright (C) 2007-2010 Florian Forster
+ * Copyright (C) 2007-2012 Florian Forster
* Copyright (C) 2009 Doug MacEachern
* Copyright (C) 2009 Franck Lombardi
+ * Copyright (C) 2012 Nicolas Szalay
*
* 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
* Florian octo Forster <octo at collectd.org>
* Doug MacEachern <dougm at hyperic.com>
* Franck Lombardi
+ * Nicolas Szalay
**/
#include "collectd.h"
#include "plugin.h"
#include "configfile.h"
-# include <poll.h>
-# include <netdb.h>
-# include <sys/socket.h>
-# include <sys/un.h>
-# include <netinet/in.h>
-# include <netinet/tcp.h>
-
-/* Hack to work around the missing define in AIX */
-#ifndef MSG_DONTWAIT
-# define MSG_DONTWAIT MSG_NONBLOCK
-#endif
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#define MEMCACHED_DEF_HOST "127.0.0.1"
#define MEMCACHED_DEF_PORT "11211"
-#define MEMCACHED_RETRY_COUNT 100
-
-static const char *config_keys[] =
+struct memcached_s
{
- "Socket",
- "Host",
- "Port"
+ char *name;
+ char *socket;
+ char *host;
+ char *port;
};
-static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+typedef struct memcached_s memcached_t;
-static char *memcached_socket = NULL;
-static char *memcached_host = NULL;
-static char memcached_port[16];
+static _Bool memcached_have_instances = 0;
-static int memcached_query_daemon (char *buffer, int buffer_size) /* {{{ */
+static void memcached_free (memcached_t *st)
{
- int fd;
- ssize_t status;
- int buffer_fill;
- int i = 0;
-
- if (memcached_socket != NULL) {
- struct sockaddr_un serv_addr;
-
- memset (&serv_addr, 0, sizeof (serv_addr));
- serv_addr.sun_family = AF_UNIX;
- sstrncpy (serv_addr.sun_path, memcached_socket,
- sizeof (serv_addr.sun_path));
-
- /* create our socket descriptor */
- fd = socket (AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0) {
- char errbuf[1024];
- ERROR ("memcached: unix socket: %s", sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return -1;
- }
-
- /* connect to the memcached daemon */
- status = (ssize_t) connect (fd, (struct sockaddr *) &serv_addr,
- sizeof (serv_addr));
- if (status != 0) {
- shutdown (fd, SHUT_RDWR);
- close (fd);
- fd = -1;
- }
- }
- else { /* if (memcached_socket == NULL) */
- const char *host;
- const char *port;
-
- struct addrinfo ai_hints;
- struct addrinfo *ai_list, *ai_ptr;
- int ai_return = 0;
-
- memset (&ai_hints, '\0', sizeof (ai_hints));
- ai_hints.ai_flags = 0;
+ if (st == NULL)
+ return;
+
+ sfree (st->name);
+ sfree (st->socket);
+ sfree (st->host);
+ sfree (st->port);
+}
+
+static int memcached_connect_unix (memcached_t *st)
+{
+ struct sockaddr_un serv_addr;
+ int fd;
+
+ memset (&serv_addr, 0, sizeof (serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ sstrncpy (serv_addr.sun_path, st->socket,
+ sizeof (serv_addr.sun_path));
+
+ /* create our socket descriptor */
+ fd = socket (AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ char errbuf[1024];
+ ERROR ("memcached plugin: memcached_connect_unix: socket(2) failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ return (fd);
+} /* int memcached_connect_unix */
+
+static int memcached_connect_inet (memcached_t *st)
+{
+ char *host;
+ char *port;
+
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_list, *ai_ptr;
+ int status;
+ int fd = -1;
+
+ memset (&ai_hints, 0, sizeof (ai_hints));
+ ai_hints.ai_flags = 0;
#ifdef AI_ADDRCONFIG
- /* ai_hints.ai_flags |= AI_ADDRCONFIG; */
+ ai_hints.ai_flags |= AI_ADDRCONFIG;
#endif
- ai_hints.ai_family = AF_INET;
- ai_hints.ai_socktype = SOCK_STREAM;
- ai_hints.ai_protocol = 0;
-
- host = memcached_host;
- if (host == NULL) {
- host = MEMCACHED_DEF_HOST;
- }
-
- port = memcached_port;
- if (strlen (port) == 0) {
- port = MEMCACHED_DEF_PORT;
- }
-
- if ((ai_return = getaddrinfo (host, port, &ai_hints, &ai_list)) != 0) {
- char errbuf[1024];
- ERROR ("memcached: getaddrinfo (%s, %s): %s",
- host, port,
- (ai_return == EAI_SYSTEM)
- ? sstrerror (errno, errbuf, sizeof (errbuf))
- : gai_strerror (ai_return));
- return -1;
- }
-
- fd = -1;
- for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
- /* create our socket descriptor */
- fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
- if (fd < 0) {
- char errbuf[1024];
- ERROR ("memcached: socket: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
- continue;
- }
-
- /* connect to the memcached daemon */
- status = (ssize_t) connect (fd, (struct sockaddr *) ai_ptr->ai_addr, ai_ptr->ai_addrlen);
- if (status != 0) {
- shutdown (fd, SHUT_RDWR);
- close (fd);
- fd = -1;
- continue;
- }
-
- /* A socket could be opened and connecting succeeded. We're
- * done. */
- break;
- }
-
- freeaddrinfo (ai_list);
- }
-
- if (fd < 0) {
- ERROR ("memcached: Could not connect to daemon.");
- return -1;
- }
-
- if (send(fd, "stats\r\n", sizeof("stats\r\n") - 1, MSG_DONTWAIT) != (sizeof("stats\r\n") - 1)) {
- ERROR ("memcached: Could not send command to the memcached daemon.");
- return -1;
- }
-
- {
- struct pollfd p;
- int status;
-
- memset (&p, 0, sizeof (p));
- p.fd = fd;
- p.events = POLLIN | POLLERR | POLLHUP;
- p.revents = 0;
-
- status = poll (&p, /* nfds = */ 1,
- /* timeout = */ CDTIME_T_TO_MS (interval_g));
- if (status <= 0)
- {
- if (status == 0)
- {
- ERROR ("memcached: poll(2) timed out after %.3f seconds.",
- CDTIME_T_TO_DOUBLE (interval_g));
- }
- else
- {
- char errbuf[1024];
- ERROR ("memcached: poll(2) failed: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- }
- shutdown (fd, SHUT_RDWR);
- close (fd);
- return (-1);
- }
- }
-
- /* receive data from the memcached daemon */
- memset (buffer, '\0', buffer_size);
-
- buffer_fill = 0;
- while ((status = recv (fd, buffer + buffer_fill, buffer_size - buffer_fill, MSG_DONTWAIT)) != 0) {
- if (i > MEMCACHED_RETRY_COUNT) {
- ERROR("recv() timed out");
- break;
- }
- i++;
-
- if (status == -1) {
- char errbuf[1024];
-
- if (errno == EAGAIN) {
- continue;
- }
-
- ERROR ("memcached: Error reading from socket: %s",
- sstrerror (errno, errbuf, sizeof (errbuf)));
- shutdown(fd, SHUT_RDWR);
- close (fd);
- return -1;
- }
- buffer_fill += status;
-
- if (buffer_fill > 3 && buffer[buffer_fill-5] == 'E' && buffer[buffer_fill-4] == 'N' && buffer[buffer_fill-3] == 'D') {
- /* we got all the data */
- break;
- }
- }
-
- if (buffer_fill >= buffer_size) {
- buffer[buffer_size - 1] = '\0';
- WARNING ("memcached: Message from memcached has been truncated.");
- } else if (buffer_fill == 0) {
- WARNING ("memcached: Peer has unexpectedly shut down the socket. "
- "Buffer: `%s'", buffer);
- shutdown(fd, SHUT_RDWR);
- close(fd);
- return -1;
- }
-
- shutdown(fd, SHUT_RDWR);
- close(fd);
- return 0;
+ ai_hints.ai_family = AF_UNSPEC;
+ ai_hints.ai_socktype = SOCK_STREAM;
+ ai_hints.ai_protocol = 0;
+
+ host = (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST;
+ port = (st->port != NULL) ? st->port : MEMCACHED_DEF_PORT;
+
+ ai_list = NULL;
+ status = getaddrinfo (host, port, &ai_hints, &ai_list);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("memcached plugin: memcached_connect_inet: "
+ "getaddrinfo(%s,%s) failed: %s",
+ host, port,
+ (status == EAI_SYSTEM)
+ ? sstrerror (errno, errbuf, sizeof (errbuf))
+ : gai_strerror (status));
+ return (-1);
+ }
+
+ for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
+ {
+ /* create our socket descriptor */
+ fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+ if (fd < 0)
+ {
+ char errbuf[1024];
+ WARNING ("memcached plugin: memcached_connect_inet: "
+ "socket(2) failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ continue;
+ }
+
+ /* connect to the memcached daemon */
+ status = (int) connect (fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ if (status != 0)
+ {
+ shutdown (fd, SHUT_RDWR);
+ close (fd);
+ fd = -1;
+ continue;
+ }
+
+ /* A socket could be opened and connecting succeeded. We're done. */
+ break;
+ }
+
+ freeaddrinfo (ai_list);
+ return (fd);
+} /* int memcached_connect_inet */
+
+static int memcached_connect (memcached_t *st)
+{
+ if (st->socket != NULL)
+ return (memcached_connect_unix (st));
+ else
+ return (memcached_connect_inet (st));
}
-/* }}} */
-static int memcached_config (const char *key, const char *value) /* {{{ */
+static int memcached_query_daemon (char *buffer, size_t buffer_size, memcached_t *st)
{
- if (strcasecmp (key, "Socket") == 0) {
- if (memcached_socket != NULL) {
- free (memcached_socket);
- }
- memcached_socket = strdup (value);
- } else if (strcasecmp (key, "Host") == 0) {
- if (memcached_host != NULL) {
- free (memcached_host);
- }
- memcached_host = strdup (value);
- } else if (strcasecmp (key, "Port") == 0) {
- int port = (int) (atof (value));
- if ((port > 0) && (port <= 65535)) {
- ssnprintf (memcached_port, sizeof (memcached_port), "%i", port);
- } else {
- sstrncpy (memcached_port, value, sizeof (memcached_port));
- }
- } else {
- return -1;
- }
-
- return 0;
+ int fd = -1;
+ int status;
+ size_t buffer_fill;
+
+ fd = memcached_connect (st);
+ if (fd < 0) {
+ ERROR ("memcached plugin: Instance \"%s\" could not connect to daemon.",
+ st->name);
+ return -1;
+ }
+
+ status = (int) swrite (fd, "stats\r\n", strlen ("stats\r\n"));
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("memcached plugin: write(2) failed: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ shutdown(fd, SHUT_RDWR);
+ close (fd);
+ return (-1);
+ }
+
+ /* receive data from the memcached daemon */
+ memset (buffer, 0, buffer_size);
+
+ buffer_fill = 0;
+ while ((status = (int) recv (fd, buffer + buffer_fill,
+ buffer_size - buffer_fill, /* flags = */ 0)) != 0)
+ {
+ char const end_token[5] = {'E', 'N', 'D', '\r', '\n'};
+ if (status < 0)
+ {
+ char errbuf[1024];
+
+ if ((errno == EAGAIN) || (errno == EINTR))
+ continue;
+
+ ERROR ("memcached: Error reading from socket: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ shutdown(fd, SHUT_RDWR);
+ close (fd);
+ return (-1);
+ }
+
+ buffer_fill += (size_t) status;
+ if (buffer_fill > buffer_size)
+ {
+ buffer_fill = buffer_size;
+ WARNING ("memcached plugin: Message was truncated.");
+ break;
+ }
+
+ /* If buffer ends in end_token, we have all the data. */
+ if (memcmp (buffer + buffer_fill - sizeof (end_token),
+ end_token, sizeof (end_token)) == 0)
+ break;
+ } /* while (recv) */
+
+ status = 0;
+ if (buffer_fill == 0)
+ {
+ WARNING ("memcached plugin: No data returned by memcached.");
+ status = -1;
+ }
+
+ shutdown(fd, SHUT_RDWR);
+ close(fd);
+ return (status);
+} /* int memcached_query_daemon */
+
+static void memcached_init_vl (value_list_t *vl, memcached_t const *st)
+{
+ sstrncpy (vl->plugin, "memcached", sizeof (vl->plugin));
+ if (strcmp (st->name, "__legacy__") == 0) /* legacy mode */
+ {
+ sstrncpy (vl->host, hostname_g, sizeof (vl->host));
+ }
+ else
+ {
+ if (st->socket != NULL)
+ sstrncpy (vl->host, hostname_g, sizeof (vl->host));
+ else
+ sstrncpy (vl->host,
+ (st->host != NULL) ? st->host : MEMCACHED_DEF_HOST,
+ sizeof (vl->host));
+ sstrncpy (vl->plugin_instance, st->name, sizeof (vl->plugin_instance));
+ }
}
-/* }}} */
static void submit_derive (const char *type, const char *type_inst,
- derive_t value) /* {{{ */
+ derive_t value, memcached_t *st)
{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+ memcached_init_vl (&vl, st);
- values[0].derive = value;
+ values[0].derive = value;
- vl.values = values;
- vl.values_len = 1;
- 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)
- sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_inst != NULL)
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (&vl);
-} /* void memcached_submit_cmd */
-/* }}} */
+ plugin_dispatch_values (&vl);
+}
static void submit_derive2 (const char *type, const char *type_inst,
- derive_t value0, derive_t value1) /* {{{ */
+ derive_t value0, derive_t value1, memcached_t *st)
{
- value_t values[2];
- value_list_t vl = VALUE_LIST_INIT;
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
+ memcached_init_vl (&vl, st);
- values[0].derive = value0;
- values[1].derive = value1;
+ values[0].derive = value0;
+ values[1].derive = value1;
- vl.values = values;
- vl.values_len = 2;
- 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)
- sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+ vl.values = values;
+ vl.values_len = 2;
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_inst != NULL)
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (&vl);
-} /* void memcached_submit_cmd */
-/* }}} */
+ plugin_dispatch_values (&vl);
+}
static void submit_gauge (const char *type, const char *type_inst,
- gauge_t value) /* {{{ */
+ gauge_t value, memcached_t *st)
{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+ memcached_init_vl (&vl, st);
- values[0].gauge = value;
+ values[0].gauge = value;
- vl.values = values;
- vl.values_len = 1;
- 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)
- sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_inst != NULL)
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (&vl);
+ plugin_dispatch_values (&vl);
}
-/* }}} */
static void submit_gauge2 (const char *type, const char *type_inst,
- gauge_t value0, gauge_t value1) /* {{{ */
+ gauge_t value0, gauge_t value1, memcached_t *st)
{
- value_t values[2];
- value_list_t vl = VALUE_LIST_INIT;
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
+ memcached_init_vl (&vl, st);
- values[0].gauge = value0;
- values[1].gauge = value1;
+ values[0].gauge = value0;
+ values[1].gauge = value1;
- vl.values = values;
- vl.values_len = 2;
- 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)
- sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
+ vl.values = values;
+ vl.values_len = 2;
+ sstrncpy (vl.type, type, sizeof (vl.type));
+ if (type_inst != NULL)
+ sstrncpy (vl.type_instance, type_inst, sizeof (vl.type_instance));
- plugin_dispatch_values (&vl);
+ plugin_dispatch_values (&vl);
}
-/* }}} */
-static int memcached_read (void) /* {{{ */
+static int memcached_read (user_data_t *user_data)
{
- char buf[4096];
- char *fields[3];
- char *ptr;
- char *line;
- char *saveptr;
- int fields_num;
-
- gauge_t bytes_used = NAN;
- gauge_t bytes_total = NAN;
- gauge_t hits = NAN;
- gauge_t gets = NAN;
- derive_t rusage_user = 0;
- derive_t rusage_syst = 0;
- derive_t octets_rx = 0;
- derive_t octets_tx = 0;
-
- /* get data from daemon */
- if (memcached_query_daemon (buf, sizeof (buf)) < 0) {
- return -1;
- }
+ char buf[4096];
+ char *fields[3];
+ char *ptr;
+ char *line;
+ char *saveptr;
+ int fields_num;
+
+ gauge_t bytes_used = NAN;
+ gauge_t bytes_total = NAN;
+ gauge_t hits = NAN;
+ gauge_t gets = NAN;
+ derive_t rusage_user = 0;
+ derive_t rusage_syst = 0;
+ derive_t octets_rx = 0;
+ derive_t octets_tx = 0;
+
+ memcached_t *st;
+ st = user_data->data;
+
+ /* get data from daemon */
+ if (memcached_query_daemon (buf, sizeof (buf), st) < 0) {
+ return -1;
+ }
#define FIELD_IS(cnst) \
- (((sizeof(cnst) - 1) == name_len) && (strcmp (cnst, fields[1]) == 0))
-
- ptr = buf;
- saveptr = NULL;
- while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
- {
- int name_len;
-
- ptr = NULL;
-
- fields_num = strsplit(line, fields, 3);
- if (fields_num != 3)
- continue;
-
- name_len = strlen(fields[1]);
- if (name_len == 0)
- continue;
-
- /*
- * For an explanation on these fields please refer to
- * <http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt>
- */
-
- /*
- * CPU time consumed by the memcached process
- */
- if (FIELD_IS ("rusage_user"))
- {
- rusage_user = atoll (fields[2]);
- }
- else if (FIELD_IS ("rusage_system"))
- {
- rusage_syst = atoll(fields[2]);
- }
-
- /*
- * Number of threads of this instance
- */
- else if (FIELD_IS ("threads"))
- {
- submit_gauge2 ("ps_count", NULL, NAN, atof (fields[2]));
- }
-
- /*
- * Number of items stored
- */
- else if (FIELD_IS ("curr_items"))
- {
- submit_gauge ("memcached_items", "current", atof (fields[2]));
- }
-
- /*
- * Number of bytes used and available (total - used)
- */
- else if (FIELD_IS ("bytes"))
- {
- bytes_used = atof (fields[2]);
- }
- else if (FIELD_IS ("limit_maxbytes"))
- {
- bytes_total = atof(fields[2]);
- }
-
- /*
- * Connections
- */
- else if (FIELD_IS ("curr_connections"))
- {
- submit_gauge ("memcached_connections", "current", atof (fields[2]));
- }
-
- /*
- * Commands
- */
- else if ((name_len > 4) && (strncmp (fields[1], "cmd_", 4) == 0))
- {
- const char *name = fields[1] + 4;
- submit_derive ("memcached_command", name, atoll (fields[2]));
- if (strcmp (name, "get") == 0)
- gets = atof (fields[2]);
- }
-
- /*
- * Operations on the cache, i. e. cache hits, cache misses and evictions of items
- */
- else if (FIELD_IS ("get_hits"))
- {
- submit_derive ("memcached_ops", "hits", atoll (fields[2]));
- hits = atof (fields[2]);
- }
- else if (FIELD_IS ("get_misses"))
- {
- submit_derive ("memcached_ops", "misses", atoll (fields[2]));
- }
- else if (FIELD_IS ("evictions"))
- {
- submit_derive ("memcached_ops", "evictions", atoll (fields[2]));
- }
-
- /*
- * Network traffic
- */
- else if (FIELD_IS ("bytes_read"))
- {
- octets_rx = atoll (fields[2]);
- }
- else if (FIELD_IS ("bytes_written"))
- {
- octets_tx = atoll (fields[2]);
- }
- } /* while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL) */
-
- if (!isnan (bytes_used) && !isnan (bytes_total) && (bytes_used <= bytes_total))
- submit_gauge2 ("df", "cache", bytes_used, bytes_total - bytes_used);
-
- if ((rusage_user != 0) || (rusage_syst != 0))
- submit_derive2 ("ps_cputime", NULL, rusage_user, rusage_syst);
-
- if ((octets_rx != 0) || (octets_tx != 0))
- submit_derive2 ("memcached_octets", NULL, octets_rx, octets_tx);
-
- if (!isnan (gets) && !isnan (hits))
- {
- gauge_t rate = NAN;
-
- if (gets != 0.0)
- rate = 100.0 * hits / gets;
-
- submit_gauge ("percent", "hitratio", rate);
- }
-
- return 0;
+ (((sizeof(cnst) - 1) == name_len) && (strcmp (cnst, fields[1]) == 0))
+
+ ptr = buf;
+ saveptr = NULL;
+ while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL)
+ {
+ int name_len;
+
+ ptr = NULL;
+
+ fields_num = strsplit(line, fields, 3);
+ if (fields_num != 3)
+ continue;
+
+ name_len = strlen(fields[1]);
+ if (name_len == 0)
+ continue;
+
+ /*
+ * For an explanation on these fields please refer to
+ * <http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt>
+ */
+
+ /*
+ * CPU time consumed by the memcached process
+ */
+ if (FIELD_IS ("rusage_user"))
+ {
+ rusage_user = atoll (fields[2]);
+ }
+ else if (FIELD_IS ("rusage_system"))
+ {
+ rusage_syst = atoll(fields[2]);
+ }
+
+ /*
+ * Number of threads of this instance
+ */
+ else if (FIELD_IS ("threads"))
+ {
+ submit_gauge2 ("ps_count", NULL, NAN, atof (fields[2]), st);
+ }
+
+ /*
+ * Number of items stored
+ */
+ else if (FIELD_IS ("curr_items"))
+ {
+ submit_gauge ("memcached_items", "current", atof (fields[2]), st);
+ }
+
+ /*
+ * Number of bytes used and available (total - used)
+ */
+ else if (FIELD_IS ("bytes"))
+ {
+ bytes_used = atof (fields[2]);
+ }
+ else if (FIELD_IS ("limit_maxbytes"))
+ {
+ bytes_total = atof(fields[2]);
+ }
+
+ /*
+ * Connections
+ */
+ else if (FIELD_IS ("curr_connections"))
+ {
+ submit_gauge ("memcached_connections", "current", atof (fields[2]), st);
+ }
+
+ /*
+ * Commands
+ */
+ else if ((name_len > 4) && (strncmp (fields[1], "cmd_", 4) == 0))
+ {
+ const char *name = fields[1] + 4;
+ submit_derive ("memcached_command", name, atoll (fields[2]), st);
+ if (strcmp (name, "get") == 0)
+ gets = atof (fields[2]);
+ }
+
+ /*
+ * Operations on the cache, i. e. cache hits, cache misses and evictions of items
+ */
+ else if (FIELD_IS ("get_hits"))
+ {
+ submit_derive ("memcached_ops", "hits", atoll (fields[2]), st);
+ hits = atof (fields[2]);
+ }
+ else if (FIELD_IS ("get_misses"))
+ {
+ submit_derive ("memcached_ops", "misses", atoll (fields[2]), st);
+ }
+ else if (FIELD_IS ("evictions"))
+ {
+ submit_derive ("memcached_ops", "evictions", atoll (fields[2]), st);
+ }
+
+ /*
+ * Network traffic
+ */
+ else if (FIELD_IS ("bytes_read"))
+ {
+ octets_rx = atoll (fields[2]);
+ }
+ else if (FIELD_IS ("bytes_written"))
+ {
+ octets_tx = atoll (fields[2]);
+ }
+ } /* while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL) */
+
+ if (!isnan (bytes_used) && !isnan (bytes_total) && (bytes_used <= bytes_total))
+ submit_gauge2 ("df", "cache", bytes_used, bytes_total - bytes_used, st);
+
+ if ((rusage_user != 0) || (rusage_syst != 0))
+ submit_derive2 ("ps_cputime", NULL, rusage_user, rusage_syst, st);
+
+ if ((octets_rx != 0) || (octets_tx != 0))
+ submit_derive2 ("memcached_octets", NULL, octets_rx, octets_tx, st);
+
+ if (!isnan (gets) && !isnan (hits))
+ {
+ gauge_t rate = NAN;
+
+ if (gets != 0.0)
+ rate = 100.0 * hits / gets;
+
+ submit_gauge ("percent", "hitratio", rate, st);
+ }
+
+ return 0;
+} /* int memcached_read */
+
+static int memcached_add_read_callback (memcached_t *st)
+{
+ user_data_t ud;
+ char callback_name[3*DATA_MAX_NAME_LEN];
+ int status;
+
+ memset (&ud, 0, sizeof (ud));
+ ud.data = st;
+ ud.free_func = (void *) memcached_free;
+
+ assert (st->name != NULL);
+ ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
+
+ status = plugin_register_complex_read (/* group = */ "memcached",
+ /* name = */ callback_name,
+ /* callback = */ memcached_read,
+ /* interval = */ NULL,
+ /* user_data = */ &ud);
+ return (status);
+} /* int memcached_add_read_callback */
+
+/* Configuration handling functiions
+ * <Plugin memcached>
+ * <Instance "instance_name">
+ * Host foo.zomg.com
+ * Port "1234"
+ * </Instance>
+ * </Plugin>
+ */
+static int config_add_instance(oconfig_item_t *ci)
+{
+ memcached_t *st;
+ int i;
+ int status = 0;
+
+ /* Disable automatic generation of default instance in the init callback. */
+ memcached_have_instances = 1;
+
+ st = malloc (sizeof (*st));
+ if (st == NULL)
+ {
+ ERROR ("memcached plugin: malloc failed.");
+ return (-1);
+ }
+
+ memset (st, 0, sizeof (*st));
+ st->name = NULL;
+ st->socket = NULL;
+ st->host = NULL;
+ st->port = NULL;
+
+ if (strcasecmp (ci->key, "Plugin") == 0) /* default instance */
+ st->name = sstrdup ("__legacy__");
+ else /* <Instance /> block */
+ status = cf_util_get_string (ci, &st->name);
+ if (status != 0)
+ {
+ sfree (st);
+ return (status);
+ }
+ assert (st->name != NULL);
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Socket", child->key) == 0)
+ status = cf_util_get_string (child, &st->socket);
+ else if (strcasecmp ("Host", child->key) == 0)
+ status = cf_util_get_string (child, &st->host);
+ else if (strcasecmp ("Port", child->key) == 0)
+ status = cf_util_get_service (child, &st->port);
+ else
+ {
+ WARNING ("memcached plugin: Option `%s' not allowed here.",
+ child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ if (status == 0)
+ status = memcached_add_read_callback (st);
+
+ if (status != 0)
+ {
+ memcached_free(st);
+ return (-1);
+ }
+
+ return (0);
}
-/* }}} */
-void module_register (void) /* {{{ */
+static int memcached_config (oconfig_item_t *ci)
{
- plugin_register_config ("memcached", memcached_config, config_keys, config_keys_num);
- plugin_register_read ("memcached", memcached_read);
+ int status = 0;
+ _Bool have_instance_block = 0;
+ int i;
+
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Instance", child->key) == 0)
+ {
+ config_add_instance (child);
+ have_instance_block = 1;
+ }
+ else if (!have_instance_block)
+ {
+ /* Non-instance option: Assume legacy configuration (without <Instance />
+ * blocks) and call config_add_instance() with the <Plugin /> block. */
+ return (config_add_instance (ci));
+ }
+ else
+ WARNING ("memcached plugin: The configuration option "
+ "\"%s\" is not allowed here. Did you "
+ "forget to add an <Instance /> block "
+ "around the configuration?",
+ child->key);
+ } /* for (ci->children) */
+
+ return (status);
}
-/* }}} */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker noexpandtab
- * vim<600: sw=4 ts=4 noexpandtab
- */
+static int memcached_init (void)
+{
+ memcached_t *st;
+ int status;
+
+ if (memcached_have_instances)
+ return (0);
+
+ /* No instances were configured, lets start a default instance. */
+ st = malloc (sizeof (*st));
+ if (st == NULL)
+ return (ENOMEM);
+ memset (st, 0, sizeof (*st));
+ st->name = sstrdup ("__legacy__");
+ st->socket = NULL;
+ st->host = NULL;
+ st->port = NULL;
+
+ status = memcached_add_read_callback (st);
+ if (status == 0)
+ memcached_have_instances = 1;
+ else
+ memcached_free (st);
+
+ return (status);
+} /* int memcached_init */
+
+void module_register (void)
+{
+ plugin_register_complex_config ("memcached", memcached_config);
+ plugin_register_init ("memcached", memcached_init);
+}
diff --git a/src/meta_data.c b/src/meta_data.c
index b502b377295141a8a095ba248d7e6de0ab285072..ea98ba94abf44670583ab47601e39ce6a0f68394 100644 (file)
--- a/src/meta_data.c
+++ b/src/meta_data.c
if (md == NULL)
return;
+ pthread_mutex_destroy(&md->lock);
md_entry_free (md->head);
pthread_mutex_destroy (&md->lock);
free (md);
diff --git a/src/mysql.c b/src/mysql.c
index 6b636787555b7e177a09abf20b71cd7cbbb7f9a7..32b352bbdd15919631a60ba78ef6233230dd407f 100644 (file)
--- a/src/mysql.c
+++ b/src/mysql.c
ud.data = (void *) db;
ud.free_func = mysql_database_free;
- if (db->database != NULL)
+ if (db->instance != NULL)
ssnprintf (cb_name, sizeof (cb_name), "mysql-%s",
- db->database);
+ db->instance);
else
sstrncpy (cb_name, "mysql", sizeof (cb_name));
diff --git a/src/netapp.c b/src/netapp.c
index d9bd1ae520597697fc96cb1f1a540d664c571ff2..f7bc04d3b1db35c54ab5a607316c9f1fc146209d 100644 (file)
--- a/src/netapp.c
+++ b/src/netapp.c
/**
* collectd - src/netapp.c
- * Copyright (C) 2009 Sven Trenkel
+ * Copyright (C) 2009,2010 Sven Trenkel
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
na_server_adminuser(host->srv, host->username, host->password);
na_server_set_timeout(host->srv, 5 /* seconds */);
- return 0;
+ return (0);
} /* }}} int cna_init_host */
static int cna_init (void) /* {{{ */
return (0);
} /* }}} cna_init */
+static int cna_read_internal (host_config_t *host) { /* {{{ */
+ int status;
+
+ status = cna_query_wafl (host);
+ if (status != 0)
+ return (status);
+
+ status = cna_query_disk (host);
+ if (status != 0)
+ return (status);
+
+ status = cna_query_volume_perf (host);
+ if (status != 0)
+ return (status);
+
+ status = cna_query_volume_usage (host);
+ if (status != 0)
+ return (status);
+
+ status = cna_query_system (host);
+ if (status != 0)
+ return (status);
+
+ return 0;
+} /* }}} int cna_read_internal */
+
static int cna_read (user_data_t *ud) { /* {{{ */
host_config_t *host;
int status;
status = cna_init_host (host);
if (status != 0)
return (status);
-
- cna_query_wafl (host);
- cna_query_disk (host);
- cna_query_volume_perf (host);
- cna_query_volume_usage (host);
- cna_query_system (host);
+
+ status = cna_read_internal (host);
+ if (status != 0)
+ {
+ if (host->srv != NULL)
+ na_server_close (host->srv);
+ host->srv = NULL;
+ }
return 0;
} /* }}} int cna_read */
diff --git a/src/netlink.c b/src/netlink.c
index ef851d354937a0069969b7822b5ce6de0879a739..7c4bef5a83f79f41796a473b6f6956e17a84e9fb 100644 (file)
--- a/src/netlink.c
+++ b/src/netlink.c
return (-1);
}
+#ifdef RTNL_DUMP_FILTER_FIVE_ARGS
if (rtnl_dump_filter (&rth, link_filter, /* arg1 = */ NULL,
NULL, NULL) != 0)
+#elif defined(RTNL_DUMP_FILTER_THREE_ARGS)
+ if (rtnl_dump_filter (&rth, link_filter, /* arg = */ NULL) != 0)
+#else
+#error "Failed to determine the number of arguments to 'rtnl_dump_filter'!"
+#endif
{
ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
return (-1);
continue;
}
+#ifdef RTNL_DUMP_FILTER_FIVE_ARGS
if (rtnl_dump_filter (&rth, qos_filter, (void *) &ifindex,
NULL, NULL) != 0)
+#elif defined(RTNL_DUMP_FILTER_THREE_ARGS)
+ if (rtnl_dump_filter (&rth, qos_filter, /* arg = */ &ifindex) != 0)
+#else
+#error "Failed to determine the number of arguments to 'rtnl_dump_filter'!"
+#endif
{
ERROR ("netlink plugin: ir_read: rtnl_dump_filter failed.");
continue;
diff --git a/src/network.c b/src/network.c
index 5fed1b196933a5bb00d39d8e9f3c9d828930bd84..3cf222744262796d4ce964cf3c76d4c690202d49 100644 (file)
--- a/src/network.c
+++ b/src/network.c
#endif
#if HAVE_LIBGCRYPT
+# include <pthread.h>
+# if defined __APPLE__
+/* default xcode compiler throws warnings even when deprecated functionality
+ * is not used. -Werror breaks the build because of erroneous warnings.
+ * http://stackoverflow.com/questions/10556299/compiler-warnings-with-libgcrypt-v1-5-0/12830209#12830209
+ */
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+# endif
# include <gcrypt.h>
+# if defined __APPLE__
+/* Re enable deprecation warnings */
+# pragma GCC diagnostic warning "-Wdeprecated-declarations"
+# endif
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
part_header_t pkg_head;
uint64_t pkg_value;
-
+
int offset;
packet_len = sizeof (pkg_head) + sizeof (pkg_value);
sizeof (network_config_ttl)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv4-ttl): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
sizeof (network_config_ttl)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt(ipv6-ttl): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
@@ -1733,7 +1745,7 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
&mreq, sizeof (mreq)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv4-multicast-if): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
@@ -1752,7 +1764,7 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
sizeof (se->interface)) != 0)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv6-multicast-if): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
@@ -1778,7 +1790,7 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
sizeof(interface_name)) == -1 )
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (bind-if): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
@@ -1802,14 +1814,18 @@ static int network_set_interface (const sockent_t *se, const struct addrinfo *ai
static int network_bind_socket (int fd, const struct addrinfo *ai, const int interface_idx)
{
+#if KERNEL_SOLARIS
+ char loop = 0;
+#else
int loop = 0;
+#endif
int yes = 1;
/* allow multiple sockets to use the same PORT number */
if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
&yes, sizeof(yes)) == -1) {
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (reuseaddr): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
@@ -1852,7 +1868,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
&loop, sizeof (loop)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (multicast-loop): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
@@ -1862,7 +1878,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
&mreq, sizeof (mreq)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (add-membership): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
@@ -1900,7 +1916,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
&loop, sizeof (loop)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv6-multicast-loop): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
@@ -1910,7 +1926,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
&mreq, sizeof (mreq)) == -1)
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (ipv6-add-membership): %s",
sstrerror (errno, errbuf,
sizeof (errbuf)));
return (-1);
@@ -1938,7 +1954,7 @@ static int network_bind_socket (int fd, const struct addrinfo *ai, const int int
sizeof(interface_name)) == -1 )
{
char errbuf[1024];
- ERROR ("setsockopt: %s",
+ ERROR ("network plugin: setsockopt (bind-if): %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
return (-1);
sstrncpy (vl_def->type_instance, vl->type_instance, sizeof (vl_def->type_instance));
}
-
+
if (write_part_values (&buffer, &buffer_size, ds, vl) != 0)
return (-1);
return (0);
} /* int network_init */
-/*
+/*
* 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
diff --git a/src/nfs.c b/src/nfs.c
index 58f2e0d23b37316ae1e48be719aa37ac82fc692c..461e806f90ab76d0ed97747043ca1a1430a6f12c 100644 (file)
--- a/src/nfs.c
+++ b/src/nfs.c
kstat_read(kc, ksp, NULL);
for (i = 0; i < proc_names_num; i++)
- values[i].counter = (derive_t) get_kstat_value (ksp, proc_names[i]);
+ values[i].counter = (derive_t) get_kstat_value (ksp,
+ (char *)proc_names[i]);
nfs_procedures_submit (plugin_instance, proc_names, values,
proc_names_num);
+ return (0);
}
#endif
diff --git a/src/ntpd.c b/src/ntpd.c
index 8bbf74d7d965b94ac0d21939fc3a4776116a7539..bbc455f6dd0603a1f6135c52ae1b199ff57f24f2 100644 (file)
--- a/src/ntpd.c
+++ b/src/ntpd.c
/**
* collectd - src/ntpd.c
- * Copyright (C) 2006-2007 Florian octo Forster
+ * Copyright (C) 2006-2012 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
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
**/
#define _BSD_SOURCE /* For NI_MAXHOST */
{
"Host",
"Port",
- "ReverseLookups"
+ "ReverseLookups",
+ "IncludeUnitID"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-static int do_reverse_lookups = 1;
+static _Bool do_reverse_lookups = 1;
+
+/* This option only exists for backward compatibility. If it is false and two
+ * ntpd peers use the same refclock driver, the plugin will try to write
+ * simultaneous measurements from both to the same type instance. */
+static _Bool include_unit_id = 0;
# define NTPD_DEFAULT_HOST "localhost"
# define NTPD_DEFAULT_PORT "123"
else
do_reverse_lookups = 0;
}
+ else if (strcasecmp (key, "IncludeUnitID") == 0)
+ {
+ if (IS_TRUE (value))
+ include_unit_id = 1;
+ else
+ include_unit_id = 0;
+ }
else
{
return (-1);
plugin_dispatch_values (&vl);
}
+/* Each time a peer is polled, ntpd shifts the reach register to the left and
+ * sets the LSB based on whether the peer was reachable. If the LSB is zero,
+ * the values are out of date. */
+static void ntpd_submit_reach (char *type, char *type_inst, uint8_t reach,
+ double value)
+{
+ if (!(reach & 1))
+ value = NAN;
+
+ ntpd_submit (type, type_inst, value);
+}
+
static int ntpd_connect (void)
{
char *host;
return (val_double);
}
+static uint32_t ntpd_get_refclock_id (struct info_peer_summary const *peer_info)
+{
+ uint32_t addr = ntohl (peer_info->srcadr);
+ uint32_t refclock_id = (addr >> 8) & 0x00FF;
+
+ return (refclock_id);
+}
+
+static int ntpd_get_name_from_address (char *buffer, size_t buffer_size,
+ struct info_peer_summary const *peer_info, _Bool do_reverse_lookup)
+{
+ struct sockaddr_storage sa;
+ socklen_t sa_len;
+ int flags = 0;
+ int status;
+
+ memset (&sa, 0, sizeof (sa));
+
+ if (peer_info->v6_flag)
+ {
+ struct sockaddr_in6 sa6;
+
+ assert (sizeof (sa) >= sizeof (sa6));
+
+ memset (&sa6, 0, sizeof (sa6));
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_port = htons (123);
+ memcpy (&sa6.sin6_addr, &peer_info->srcadr6,
+ sizeof (struct in6_addr));
+ sa_len = sizeof (sa6);
+
+ memcpy (&sa, &sa6, sizeof (sa6));
+ }
+ else
+ {
+ struct sockaddr_in sa4;
+
+ assert (sizeof (sa) >= sizeof (sa4));
+
+ memset (&sa4, 0, sizeof (sa4));
+ sa4.sin_family = AF_INET;
+ sa4.sin_port = htons (123);
+ memcpy (&sa4.sin_addr, &peer_info->srcadr,
+ sizeof (struct in_addr));
+ sa_len = sizeof (sa4);
+
+ memcpy (&sa, &sa4, sizeof (sa4));
+ }
+
+ if (!do_reverse_lookup)
+ flags |= NI_NUMERICHOST;
+
+ status = getnameinfo ((struct sockaddr const *) &sa, sa_len,
+ buffer, buffer_size,
+ NULL, 0, /* No port name */
+ flags);
+ if (status != 0)
+ {
+ char errbuf[1024];
+ ERROR ("ntpd plugin: getnameinfo failed: %s",
+ (status == EAI_SYSTEM)
+ ? sstrerror (errno, errbuf, sizeof (errbuf))
+ : gai_strerror (status));
+ return (-1);
+ }
+
+ return (0);
+} /* ntpd_get_name_from_address */
+
+static int ntpd_get_name_refclock (char *buffer, size_t buffer_size,
+ struct info_peer_summary const *peer_info)
+{
+ uint32_t refclock_id = ntpd_get_refclock_id (peer_info);
+ uint32_t unit_id = ntohl (peer_info->srcadr) & 0x00FF;
+
+ if (refclock_id >= refclock_names_num)
+ return (ntpd_get_name_from_address (buffer, buffer_size,
+ peer_info,
+ /* do_reverse_lookup = */ 0));
+
+ if (include_unit_id)
+ ssnprintf (buffer, buffer_size, "%s-%"PRIu32,
+ refclock_names[refclock_id], unit_id);
+ else
+ sstrncpy (buffer, refclock_names[refclock_id], buffer_size);
+
+ return (0);
+} /* int ntpd_get_name_refclock */
+
+static int ntpd_get_name (char *buffer, size_t buffer_size,
+ struct info_peer_summary const *peer_info)
+{
+ uint32_t addr = ntohl (peer_info->srcadr);
+
+ if (!peer_info->v6_flag && ((addr & REFCLOCK_MASK) == REFCLOCK_ADDR))
+ return (ntpd_get_name_refclock (buffer, buffer_size,
+ peer_info));
+ else
+ return (ntpd_get_name_from_address (buffer, buffer_size,
+ peer_info, do_reverse_lookups));
+} /* int ntpd_addr_to_name */
+
static int ntpd_read (void)
{
struct info_kernel *ik;
double offset;
char peername[NI_MAXHOST];
- int refclock_id;
-
- ptr = ps + i;
- refclock_id = 0;
+ uint32_t refclock_id;
- /* Convert the `long floating point' offset value to double */
- M_LFPTOD (ntohl (ptr->offset_int), ntohl (ptr->offset_frc), offset);
+ ptr = ps + i;
- /* Special IP addresses for hardware clocks and stuff.. */
- if (!ptr->v6_flag
- && ((ntohl (ptr->srcadr) & REFCLOCK_MASK)
- == REFCLOCK_ADDR))
+ status = ntpd_get_name (peername, sizeof (peername), ptr);
+ if (status != 0)
{
- struct in_addr addr_obj;
- char *addr_str;
-
- refclock_id = (ntohl (ptr->srcadr) >> 8) & 0x000000FF;
-
- if (refclock_id < refclock_names_num)
- {
- sstrncpy (peername, refclock_names[refclock_id],
- sizeof (peername));
- }
- else
- {
- memset ((void *) &addr_obj, '\0', sizeof (addr_obj));
- addr_obj.s_addr = ptr->srcadr;
- addr_str = inet_ntoa (addr_obj);
-
- sstrncpy (peername, addr_str, sizeof (peername));
- }
+ ERROR ("ntpd plugin: Determining name of peer failed.");
+ continue;
}
- else /* Normal network host. */
- {
- struct sockaddr_storage sa;
- socklen_t sa_len;
- int flags = 0;
-
- memset (&sa, '\0', sizeof (sa));
-
- if (ptr->v6_flag)
- {
- struct sockaddr_in6 sa6;
-
- assert (sizeof (sa) >= sizeof (sa6));
-
- memset (&sa6, 0, sizeof (sa6));
- sa6.sin6_family = AF_INET6;
- sa6.sin6_port = htons (123);
- memcpy (&sa6.sin6_addr, &ptr->srcadr6,
- sizeof (struct in6_addr));
- sa_len = sizeof (sa6);
-
- memcpy (&sa, &sa6, sizeof (sa6));
- }
- else
- {
- struct sockaddr_in sa4;
-
- assert (sizeof (sa) >= sizeof (sa4));
- memset (&sa4, 0, sizeof (sa4));
- sa4.sin_family = AF_INET;
- sa4.sin_port = htons (123);
- memcpy (&sa4.sin_addr, &ptr->srcadr,
- sizeof (struct in_addr));
- sa_len = sizeof (sa4);
+ refclock_id = ntpd_get_refclock_id (ptr);
- memcpy (&sa, &sa4, sizeof (sa4));
- }
-
- if (do_reverse_lookups == 0)
- flags |= NI_NUMERICHOST;
-
- status = getnameinfo ((const struct sockaddr *) &sa,
- sa_len,
- peername, sizeof (peername),
- NULL, 0, /* No port name */
- flags);
- if (status != 0)
- {
- char errbuf[1024];
- ERROR ("ntpd plugin: getnameinfo failed: %s",
- (status == EAI_SYSTEM)
- ? sstrerror (errno, errbuf, sizeof (errbuf))
- : gai_strerror (status));
- continue;
- }
- }
+ /* Convert the `long floating point' offset value to double */
+ M_LFPTOD (ntohl (ptr->offset_int), ntohl (ptr->offset_frc), offset);
DEBUG ("peer %i:\n"
" peername = %s\n"
" srcadr = 0x%08x\n"
+ " reach = 0%03o\n"
" delay = %f\n"
" offset_int = %i\n"
" offset_frc = %i\n"
i,
peername,
ntohl (ptr->srcadr),
+ ptr->reach,
ntpd_read_fp (ptr->delay),
ntohl (ptr->offset_int),
ntohl (ptr->offset_frc),
ntpd_read_fp (ptr->dispersion));
if (refclock_id != 1) /* not the system clock (offset will always be zero.. */
- ntpd_submit ("time_offset", peername, offset);
- ntpd_submit ("time_dispersion", peername, ntpd_read_fp (ptr->dispersion));
+ ntpd_submit_reach ("time_offset", peername, ptr->reach,
+ offset);
+ ntpd_submit_reach ("time_dispersion", peername, ptr->reach,
+ ntpd_read_fp (ptr->dispersion));
if (refclock_id == 0) /* not a reference clock */
- ntpd_submit ("delay", peername, ntpd_read_fp (ptr->delay));
+ ntpd_submit_reach ("delay", peername, ptr->reach,
+ ntpd_read_fp (ptr->delay));
}
free (ps);
diff --git a/src/oracle.c b/src/oracle.c
index 86643ca3b09d608ca9272eec0b9d462c063d8f1f..ab0812b703ec441c745d4afbe2bcdaf2ca79025f 100644 (file)
--- a/src/oracle.c
+++ b/src/oracle.c
* Functions
*/
static void o_report_error (const char *where, /* {{{ */
+ const char *db_name, const char *query_name,
const char *what, OCIError *eh)
{
char buffer[2048];
int status;
unsigned int record_number;
+ if (db_name == NULL)
+ db_name = "(none)";
+ if (query_name == NULL)
+ query_name = "(none)";
+
/* An operation may cause / return multiple errors. Loop until we have
* handled all errors available (with a fail-save limit of 16). */
for (record_number = 1; record_number <= 16; record_number++)
buffer[buffer_length] = 0;
}
- ERROR ("oracle plugin: %s: %s failed: %s", where, what, buffer);
+ ERROR ("oracle plugin: %s (db = %s, query = %s): %s failed: %s",
+ where, db_name, query_name, what, buffer);
}
else
{
- ERROR ("oracle plugin: %s: %s failed. Additionally, OCIErrorGet failed with status %i.",
- where, what, status);
+ ERROR ("oracle plugin: %s (db = %s, query = %s): %s failed. "
+ "Additionally, OCIErrorGet failed with status %i.",
+ where, db_name, query_name, what, status);
return;
}
}
OCI_HTYPE_STMT, /* user_data_size = */ 0, /* user_data = */ NULL);
if (status != OCI_SUCCESS)
{
- o_report_error ("o_read_database_query", "OCIHandleAlloc", oci_error);
+ o_report_error ("o_read_database_query", db->name,
+ udb_query_get_name (q), "OCIHandleAlloc", oci_error);
oci_statement = NULL;
return (-1);
}
/* mode = */ OCI_DEFAULT);
if (status != OCI_SUCCESS)
{
- o_report_error ("o_read_database_query", "OCIStmtPrepare", oci_error);
+ o_report_error ("o_read_database_query", db->name,
+ udb_query_get_name (q), "OCIStmtPrepare", oci_error);
OCIHandleFree (oci_statement, OCI_HTYPE_STMT);
oci_statement = NULL;
return (-1);
/* mode = */ OCI_DEFAULT);
if (status != OCI_SUCCESS)
{
- DEBUG ("oracle plugin: o_read_database_query: status = %i (%#x)", status, status);
- o_report_error ("o_read_database_query", "OCIStmtExecute", oci_error);
- ERROR ("oracle plugin: o_read_database_query: "
- "Failing statement was: %s", udb_query_get_statement (q));
+ o_report_error ("o_read_database_query", db->name, udb_query_get_name (q),
+ "OCIStmtExecute", oci_error);
return (-1);
} /* }}} */
OCI_ATTR_PARAM_COUNT, oci_error);
if (status != OCI_SUCCESS)
{
- o_report_error ("o_read_database_query", "OCIAttrGet", oci_error);
+ o_report_error ("o_read_database_query", db->name,
+ udb_query_get_name (q), "OCIAttrGet", oci_error);
return (-1);
} /* }}} */
if (status != OCI_SUCCESS)
{
/* This is probably alright */
- DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);", status, status);
- o_report_error ("o_read_database_query", "OCIParamGet", oci_error);
+ DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);",
+ status, status);
+ o_report_error ("o_read_database_query", db->name,
+ udb_query_get_name (q), "OCIParamGet", oci_error);
status = OCI_SUCCESS;
break;
}
if (status != OCI_SUCCESS)
{
OCIDescriptorFree (oci_param, OCI_DTYPE_PARAM);
- o_report_error ("o_read_database_query", "OCIAttrGet (OCI_ATTR_NAME)",
- oci_error);
+ o_report_error ("o_read_database_query", db->name,
+ udb_query_get_name (q), "OCIAttrGet (OCI_ATTR_NAME)", oci_error);
continue;
}
NULL, NULL, NULL, OCI_DEFAULT);
if (status != OCI_SUCCESS)
{
- o_report_error ("o_read_database_query", "OCIDefineByPos", oci_error);
+ o_report_error ("o_read_database_query", db->name,
+ udb_query_get_name (q), "OCIDefineByPos", oci_error);
continue;
}
} /* for (j = 1; j <= param_counter; j++) */
}
else if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
{
- o_report_error ("o_read_database_query", "OCIStmtFetch2", oci_error);
+ o_report_error ("o_read_database_query", db->name,
+ udb_query_get_name (q), "OCIStmtFetch2", oci_error);
break;
}
OCI_ATTR_SERVER, oci_error);
if (status != OCI_SUCCESS)
{
- o_report_error ("o_read_database", "OCIAttrGet", oci_error);
+ o_report_error ("o_read_database", db->name, NULL, "OCIAttrGet",
+ oci_error);
return (-1);
}
OCI_ATTR_SERVER_STATUS, oci_error);
if (status != OCI_SUCCESS)
{
- o_report_error ("o_read_database", "OCIAttrGet", oci_error);
+ o_report_error ("o_read_database", db->name, NULL, "OCIAttrGet",
+ oci_error);
return (-1);
}
}
(OraText *) db->connect_id, (ub4) strlen (db->connect_id));
if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
{
- o_report_error ("o_read_database", "OCILogon", oci_error);
+ char errfunc[256];
+
+ ssnprintf (errfunc, sizeof (errfunc), "OCILogon(\"%s\")", db->connect_id);
+
+ o_report_error ("o_read_database", db->name, NULL, errfunc, oci_error);
DEBUG ("oracle plugin: OCILogon (%s): db->oci_service_context = %p;",
db->connect_id, db->oci_service_context);
db->oci_service_context = NULL;
diff --git a/src/postgresql.c b/src/postgresql.c
index 0a5e66c25d934acd4de939cd049e6070a3121ca9..675505bb3576919d741a3c31bb86fac5e6acce08 100644 (file)
--- a/src/postgresql.c
+++ b/src/postgresql.c
C_PSQL_PARAM_DB,
C_PSQL_PARAM_USER,
C_PSQL_PARAM_INTERVAL,
+ C_PSQL_PARAM_INSTANCE,
} c_psql_param_t;
/* Parameter configuration. Stored as `user data' in the query objects. */
char *user;
char *password;
+ char *instance;
+
char *sslmode;
char *krbsrvname;
db->user = NULL;
db->password = NULL;
+ db->instance = sstrdup (name);
+
db->sslmode = NULL;
db->krbsrvname = NULL;
sfree (db->user);
sfree (db->password);
+ sfree (db->instance);
+
sfree (db->sslmode);
sfree (db->krbsrvname);
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));
+ "Failed to connect to database %s (%s): %s",
+ db->database, db->instance,
+ PQerrorMessage (db->conn));
return -1;
}
? CDTIME_T_TO_DOUBLE (db->interval) : interval_g);
params[i] = interval;
break;
+ case C_PSQL_PARAM_INSTANCE:
+ params[i] = db->instance;
+ break;
default:
assert (0);
}
else if ((NULL == data) || (0 == data->params_num))
res = c_psql_exec_query_noparams (db, q);
else {
- log_err ("Connection to database \"%s\" does not support parameters "
- "(protocol version %d) - cannot execute query \"%s\".",
- db->database, db->proto_version,
+ log_err ("Connection to database \"%s\" (%s) does not support "
+ "parameters (protocol version %d) - "
+ "cannot execute query \"%s\".",
+ db->database, db->instance, db->proto_version,
udb_query_get_name (q));
return -1;
}
host = db->host;
status = udb_query_prepare_result (q, prep_area, host, "postgresql",
- db->database, column_names, (size_t) column_num, db->interval);
+ db->instance, column_names, (size_t) column_num, db->interval);
if (0 != status) {
log_err ("udb_query_prepare_result failed with status %i.",
status);
db = ud->data;
assert (NULL != db->database);
+ assert (NULL != db->instance);
if (0 != c_psql_check_connection (db))
return -1;
data->params[data->params_num] = C_PSQL_PARAM_USER;
else if (0 == strcasecmp (param_str, "interval"))
data->params[data->params_num] = C_PSQL_PARAM_INTERVAL;
+ else if (0 == strcasecmp (param_str, "instance"))
+ data->params[data->params_num] = C_PSQL_PARAM_INSTANCE;
else {
log_err ("Invalid parameter \"%s\".", param_str);
return 1;
cf_util_get_string (c, &db->user);
else if (0 == strcasecmp (c->key, "Password"))
cf_util_get_string (c, &db->password);
+ else if (0 == strcasecmp (c->key, "Instance"))
+ cf_util_get_string (c, &db->instance);
else if (0 == strcasecmp (c->key, "SSLMode"))
cf_util_get_string (c, &db->sslmode);
else if (0 == strcasecmp (c->key, "KRBSrvName"))
ud.data = db;
ud.free_func = c_psql_database_delete;
- ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->database);
+ ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->instance);
CDTIME_T_TO_TIMESPEC (db->interval, &cb_interval);
diff --git a/src/processes.c b/src/processes.c
index 66237dc376be56414b29d62000d8a39c6fd70e1b..c77859d9e7d9f6953abe3fb87c3e16aebdd44357 100644 (file)
--- a/src/processes.c
+++ b/src/processes.c
* Copyright (C) 2009 Andrés J. DÃaz
* Copyright (C) 2009 Manuel Sanmartin
* Copyright (C) 2010 Clément Stenac
+ * Copyright (C) 2012 Cosmin Ioiart
*
* 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
* Andrés J. DÃaz <ajdiaz at connectical.com>
* Manuel Sanmartin
* Clément Stenac <clement.stenac at diwi.org>
+ * Cosmin Ioiart <cioiart at gmail.com>
**/
#include "collectd.h"
#define MAXARGLN 1024
/* #endif HAVE_PROCINFO_H */
+#elif KERNEL_SOLARIS
+# include <procfs.h>
+# include <dirent.h>
+/* #endif KERNEL_SOLARIS */
+
#else
# error "No applicable input method."
#endif
# include <regex.h>
#endif
+#if HAVE_KSTAT_H
+# include <kstat.h>
+#endif
+
#ifndef ARG_MAX
# define ARG_MAX 4096
#endif
@@ -216,8 +227,8 @@ int getargs (struct procentry64 *processBuffer, int bufferLen, char *argsBuffer,
#endif /* HAVE_PROCINFO_H */
/* 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 */
+ * 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;
}
DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; "
- "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
+ "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
"vmem_code = %lu; "
"vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
"cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw);
} /* void ps_submit_proc_list */
+#if KERNEL_LINUX || KERNEL_SOLARIS
+static void ps_submit_fork_rate (derive_t value)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].derive = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy(vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy(vl.plugin, "processes", sizeof (vl.plugin));
+ sstrncpy(vl.plugin_instance, "", sizeof (vl.plugin_instance));
+ sstrncpy(vl.type, "fork_rate", sizeof (vl.type));
+ sstrncpy(vl.type_instance, "", sizeof (vl.type_instance));
+
+ plugin_dispatch_values(&vl);
+}
+#endif /* KERNEL_LINUX || KERNEL_SOLARIS*/
+
/* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
#if KERNEL_LINUX
static int ps_read_tasks (int pid)
continue;
numfields = strsplit (buffer, fields,
- STATIC_ARRAY_SIZE (fields));
+ STATIC_ARRAY_SIZE (fields));
if (numfields < 2)
continue;
@@ -1117,70 +1148,226 @@ static char *ps_get_cmdline (pid_t pid, char *name, char *buf, size_t buf_len)
return buf;
} /* char *ps_get_cmdline (...) */
-static unsigned long read_fork_rate ()
+static int read_fork_rate ()
{
FILE *proc_stat;
- char buf[1024];
- unsigned long result = 0;
- int numfields;
- char *fields[3];
+ char buffer[1024];
+ value_t value;
+ _Bool value_valid = 0;
- proc_stat = fopen("/proc/stat", "r");
- if (proc_stat == NULL) {
+ proc_stat = fopen ("/proc/stat", "r");
+ if (proc_stat == NULL)
+ {
char errbuf[1024];
ERROR ("processes plugin: fopen (/proc/stat) failed: %s",
sstrerror (errno, errbuf, sizeof (errbuf)));
- return ULONG_MAX;
+ return (-1);
}
- while (fgets (buf, sizeof(buf), proc_stat) != NULL)
+ while (fgets (buffer, sizeof (buffer), proc_stat) != NULL)
{
- char *endptr;
+ int status;
+ char *fields[3];
+ int fields_num;
- numfields = strsplit(buf, fields, STATIC_ARRAY_SIZE (fields));
- if (numfields != 2)
+ fields_num = strsplit (buffer, fields,
+ STATIC_ARRAY_SIZE (fields));
+ if (fields_num != 2)
continue;
if (strcmp ("processes", fields[0]) != 0)
continue;
- errno = 0;
- endptr = NULL;
- result = strtoul(fields[1], &endptr, /* base = */ 10);
- if ((endptr == fields[1]) || (errno != 0)) {
- ERROR ("processes plugin: Cannot parse fork rate: %s",
- fields[1]);
- result = ULONG_MAX;
- break;
- }
+ status = parse_value (fields[1], &value, DS_TYPE_DERIVE);
+ if (status == 0)
+ value_valid = 1;
break;
}
-
fclose(proc_stat);
- return result;
+ if (!value_valid)
+ return (-1);
+
+ ps_submit_fork_rate (value.derive);
+ return (0);
}
+#endif /*KERNEL_LINUX */
-static void ps_submit_fork_rate (unsigned long value)
+#if KERNEL_SOLARIS
+static const char *ps_get_cmdline (pid_t pid, /* {{{ */
+ char *buffer, size_t buffer_size)
{
- value_t values[1];
- value_list_t vl = VALUE_LIST_INIT;
+ char path[PATH_MAX];
+ psinfo_t info;
+ int status;
- values[0].derive = (derive_t) value;
+ snprintf(path, sizeof (path), "/proc/%i/psinfo", pid);
- vl.values = values;
- vl.values_len = 1;
- sstrncpy (vl.host, hostname_g, sizeof (vl.host));
- sstrncpy (vl.plugin, "processes", sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, "", sizeof (vl.plugin_instance));
- sstrncpy (vl.type, "fork_rate", sizeof (vl.type));
- sstrncpy (vl.type_instance, "", sizeof (vl.type_instance));
+ status = read_file_contents (path, (void *) &info, sizeof (info));
+ if (status != ((int) buffer_size))
+ {
+ ERROR ("processes plugin: Unexpected return value "
+ "while reading \"%s\": "
+ "Returned %i but expected %zu.",
+ path, status, buffer_size);
+ return (NULL);
+ }
- plugin_dispatch_values (&vl);
+ info.pr_psargs[sizeof (info.pr_psargs) - 1] = 0;
+ sstrncpy (buffer, info.pr_psargs, buffer_size);
+
+ return (buffer);
+} /* }}} int ps_get_cmdline */
+
+/*
+ * Reads process information on the Solaris OS. The information comes mainly from
+ * /proc/PID/status, /proc/PID/psinfo and /proc/PID/usage
+ * The values for input and ouput chars are calculated "by hand"
+ * Added a few "solaris" specific process states as well
+ */
+static int ps_read_process(int pid, procstat_t *ps, char *state)
+{
+ char filename[64];
+ char f_psinfo[64], f_usage[64];
+ char *buffer;
+
+ pstatus_t *myStatus;
+ psinfo_t *myInfo;
+ prusage_t *myUsage;
+
+ snprintf(filename, sizeof (filename), "/proc/%i/status", pid);
+ snprintf(f_psinfo, sizeof (f_psinfo), "/proc/%i/psinfo", pid);
+ snprintf(f_usage, sizeof (f_usage), "/proc/%i/usage", pid);
+
+
+ buffer = malloc(sizeof (pstatus_t));
+ memset(buffer, 0, sizeof (pstatus_t));
+ read_file_contents(filename, buffer, sizeof (pstatus_t));
+ myStatus = (pstatus_t *) buffer;
+
+ buffer = malloc(sizeof (psinfo_t));
+ memset(buffer, 0, sizeof(psinfo_t));
+ read_file_contents(f_psinfo, buffer, sizeof (psinfo_t));
+ myInfo = (psinfo_t *) buffer;
+
+ buffer = malloc(sizeof (prusage_t));
+ memset(buffer, 0, sizeof(prusage_t));
+ read_file_contents(f_usage, buffer, sizeof (prusage_t));
+ myUsage = (prusage_t *) buffer;
+
+ sstrncpy(ps->name, myInfo->pr_fname, sizeof (myInfo->pr_fname));
+ ps->num_lwp = myStatus->pr_nlwp;
+ if (myInfo->pr_wstat != 0) {
+ ps->num_proc = 0;
+ ps->num_lwp = 0;
+ *state = (char) 'Z';
+ return (0);
+ } else {
+ ps->num_proc = 1;
+ ps->num_lwp = myInfo->pr_nlwp;
+ }
+
+ /*
+ * Convert system time and user time from nanoseconds to microseconds
+ * for compatibility with the linux module
+ */
+ ps->cpu_system_counter = myStatus -> pr_stime.tv_nsec / 1000;
+ ps->cpu_user_counter = myStatus -> pr_utime.tv_nsec / 1000;
+
+ /*
+ * Convert rssize from KB to bytes to be consistent w/ the linux module
+ */
+ ps->vmem_rss = myInfo->pr_rssize * 1024;
+ ps->vmem_size = myInfo->pr_size * 1024;
+ ps->vmem_minflt_counter = myUsage->pr_minf;
+ ps->vmem_majflt_counter = myUsage->pr_majf;
+
+ /*
+ * TODO: Data and code segment calculations for Solaris
+ */
+
+ ps->vmem_data = -1;
+ ps->vmem_code = -1;
+ ps->stack_size = myStatus->pr_stksize;
+
+ /*
+ * Calculating input/ouput chars
+ * Formula used is total chars / total blocks => chars/block
+ * then convert input/output blocks to chars
+ */
+ ulong_t tot_chars = myUsage->pr_ioch;
+ ulong_t tot_blocks = myUsage->pr_inblk + myUsage->pr_oublk;
+ ulong_t chars_per_block = 1;
+ if (tot_blocks != 0)
+ chars_per_block = tot_chars / tot_blocks;
+ ps->io_rchar = myUsage->pr_inblk * chars_per_block;
+ ps->io_wchar = myUsage->pr_oublk * chars_per_block;
+ ps->io_syscr = myUsage->pr_sysc;
+ ps->io_syscw = myUsage->pr_sysc;
+
+
+ /*
+ * TODO: Find way of setting BLOCKED and PAGING status
+ */
+
+ *state = (char) 'R';
+ if (myStatus->pr_flags & PR_ASLEEP)
+ *state = (char) 'S';
+ else if (myStatus->pr_flags & PR_STOPPED)
+ *state = (char) 'T';
+ else if (myStatus->pr_flags & PR_DETACH)
+ *state = (char) 'E';
+ else if (myStatus->pr_flags & PR_DAEMON)
+ *state = (char) 'A';
+ else if (myStatus->pr_flags & PR_ISSYS)
+ *state = (char) 'Y';
+ else if (myStatus->pr_flags & PR_ORPHAN)
+ *state = (char) 'O';
+
+ sfree(myStatus);
+ sfree(myInfo);
+ sfree(myUsage);
+
+ return (0);
}
-#endif /* KERNEL_LINUX */
+/*
+ * Reads the number of threads created since the last reboot. On Solaris these
+ * are retrieved from kstat (module cpu, name sys, class misc, stat nthreads).
+ * The result is the sum for all the threads created on each cpu
+ */
+static int read_fork_rate()
+{
+ extern kstat_ctl_t *kc;
+ kstat_t *ksp_chain = NULL;
+ derive_t result = 0;
+
+ if (kc == NULL)
+ return (-1);
+
+ for (ksp_chain = kc->kc_chain;
+ ksp_chain != NULL;
+ ksp_chain = ksp_chain->ks_next)
+ {
+ if ((strcmp (ksp_chain->ks_module, "cpu") == 0)
+ && (strcmp (ksp_chain->ks_name, "sys") == 0)
+ && (strcmp (ksp_chain->ks_class, "misc") == 0))
+ {
+ long long tmp;
+
+ kstat_read (kc, ksp_chain, NULL);
+
+ tmp = get_kstat_value(ksp_chain, "nthreads");
+ if (tmp != -1LL)
+ result += tmp;
+ }
+ }
+
+ ps_submit_fork_rate (result);
+ return (0);
+}
+#endif /* KERNEL_SOLARIS */
#if HAVE_THREAD_INFO
static int mach_get_task_name (task_t t, int *pid, char *name, size_t name_max_len)
procstat_entry_t pse;
char state;
- unsigned long fork_rate;
-
procstat_t *ps_ptr;
running = sleeping = zombies = stopped = paging = blocked = 0;
for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
ps_submit_proc_list (ps_ptr);
- fork_rate = read_fork_rate();
- if (fork_rate != ULONG_MAX)
- ps_submit_fork_rate(fork_rate);
+ read_fork_rate();
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
kvm_t *kd;
char errbuf[1024];
- struct kinfo_proc *procs; /* array of processes */
+ struct kinfo_proc *procs; /* array of processes */
struct kinfo_proc *proc_ptr = NULL;
- int count; /* returns number of processes */
+ int count; /* returns number of processes */
int i;
procstat_t *ps_ptr;
if (procentry[i].pi_pid == 0)
cmdline = "swapper";
cargs = cmdline;
- }
+ }
else
{
if (getargs(&procentry[i], sizeof(struct procentry64), arglist, MAXARGLN) >= 0)
for (ps = list_head_g; ps != NULL; ps = ps->next)
ps_submit_proc_list (ps);
-#endif /* HAVE_PROCINFO_H */
+/* #endif HAVE_PROCINFO_H */
+
+#elif KERNEL_SOLARIS
+ /*
+ * The Solaris section adds a few more process states and removes some
+ * process states compared to linux. Most notably there is no "PAGING"
+ * and "BLOCKED" state for a process. The rest is similar to the linux
+ * code.
+ */
+ int running = 0;
+ int sleeping = 0;
+ int zombies = 0;
+ int stopped = 0;
+ int detached = 0;
+ int daemon = 0;
+ int system = 0;
+ int orphan = 0;
+
+ struct dirent *ent;
+ DIR *proc;
+
+ int status;
+ procstat_t *ps_ptr;
+ char state;
+
+ char cmdline[PRARGSZ];
+
+ ps_list_reset ();
+
+ proc = opendir ("/proc");
+ if (proc == NULL)
+ return (-1);
+
+ while ((ent = readdir(proc)) != NULL)
+ {
+ int pid;
+ struct procstat ps;
+ procstat_entry_t pse;
+
+ if (!isdigit ((int) ent->d_name[0]))
+ continue;
+
+ if ((pid = atoi (ent->d_name)) < 1)
+ continue;
+
+ status = ps_read_process (pid, &ps, &state);
+ if (status != 0)
+ {
+ DEBUG("ps_read_process failed: %i", status);
+ continue;
+ }
+
+ pse.id = pid;
+ pse.age = 0;
+
+ pse.num_proc = ps.num_proc;
+ pse.num_lwp = ps.num_lwp;
+ pse.vmem_size = ps.vmem_size;
+ pse.vmem_rss = ps.vmem_rss;
+ pse.vmem_data = ps.vmem_data;
+ pse.vmem_code = ps.vmem_code;
+ pse.stack_size = ps.stack_size;
+
+ pse.vmem_minflt = 0;
+ pse.vmem_minflt_counter = ps.vmem_minflt_counter;
+ pse.vmem_majflt = 0;
+ pse.vmem_majflt_counter = ps.vmem_majflt_counter;
+
+ pse.cpu_user = 0;
+ pse.cpu_user_counter = ps.cpu_user_counter;
+ pse.cpu_system = 0;
+ pse.cpu_system_counter = ps.cpu_system_counter;
+
+ pse.io_rchar = ps.io_rchar;
+ pse.io_wchar = ps.io_wchar;
+ pse.io_syscr = ps.io_syscr;
+ pse.io_syscw = ps.io_syscw;
+
+ switch (state)
+ {
+ case 'R': running++; break;
+ case 'S': sleeping++; break;
+ case 'E': detached++; break;
+ case 'Z': zombies++; break;
+ case 'T': stopped++; break;
+ case 'A': daemon++; break;
+ case 'Y': system++; break;
+ case 'O': orphan++; break;
+ }
+
+
+ ps_list_add (ps.name,
+ ps_get_cmdline ((pid_t) pid,
+ cmdline, sizeof (cmdline)),
+ &pse);
+ } /* while(readdir) */
+ closedir (proc);
+
+ ps_submit_state ("running", running);
+ ps_submit_state ("sleeping", sleeping);
+ ps_submit_state ("zombies", zombies);
+ ps_submit_state ("stopped", stopped);
+ ps_submit_state ("detached", detached);
+ ps_submit_state ("daemon", daemon);
+ ps_submit_state ("system", system);
+ ps_submit_state ("orphan", orphan);
+
+ for (ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
+ ps_submit_proc_list (ps_ptr);
+
+ read_fork_rate();
+#endif /* KERNEL_SOLARIS */
return (0);
} /* int ps_read */
diff --git a/src/redis.c b/src/redis.c
index b694e09db8f84a6be6767b20cacd50d37791b074..439cf4b8158501e2bd215228b0a369e9dcb32f52 100644 (file)
--- a/src/redis.c
+++ b/src/redis.c
#include <pthread.h>
#include <credis.h>
+#ifndef HOST_NAME_MAX
+# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+#endif
+
#define REDIS_DEF_HOST "localhost"
#define REDIS_DEF_PORT 6379
#define REDIS_DEF_TIMEOUT 2000
{
char name[MAX_REDIS_NODE_NAME];
char host[HOST_NAME_MAX];
+ char passwd[HOST_NAME_MAX];
int port;
int timeout;
}
else if (strcasecmp ("Timeout", option->key) == 0)
status = cf_util_get_int (option, &rn.timeout);
+ else if (strcasecmp ("Password", option->key) == 0)
+ status = cf_util_get_string_buffer (option, rn.passwd, sizeof (rn.passwd));
else
WARNING ("redis plugin: Option `%s' not allowed inside a `Node' "
"block. I'll ignore this option.", option->key);
continue;
}
+ if (strlen (rn->passwd) > 0)
+ {
+ DEBUG ("redis plugin: authenticanting node `%s' passwd(%s).", rn->name, rn->passwd);
+ status = credis_auth(rh, rn->passwd);
+ if (status != 0)
+ {
+ WARNING ("redis plugin: unable to authenticate on node `%s'.", rn->name);
+ credis_close (rh);
+ continue;
+ }
+ }
+
memset (&info, 0, sizeof (info));
status = credis_info (rh, &info);
if (status != 0)
diff --git a/src/rrdcached.c b/src/rrdcached.c
index 11c1c6a7f85c3e96c2380602094c81f09e4bb97f..45553b7f250ee708ec620f8058a6f18691711f34 100644 (file)
--- a/src/rrdcached.c
+++ b/src/rrdcached.c
/**
* collectd - src/rrdcached.c
- * Copyright (C) 2008 Florian octo Forster
+ * Copyright (C) 2008-2012 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
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
**/
#include "collectd.h"
*/
static char *datadir = NULL;
static char *daemon_address = NULL;
-static int config_create_files = 1;
-static int config_collect_stats = 1;
+static _Bool config_create_files = 1;
+static _Bool config_collect_stats = 1;
static rrdcreate_config_t rrdcreate_config =
{
/* stepsize = */ 0,
return (0);
} /* int value_list_to_filename */
-static const char *config_get_string (oconfig_item_t *ci)
+static int rc_config_get_int_positive (oconfig_item_t const *ci, int *ret)
{
- if ((ci->children_num != 0) || (ci->values_num != 1)
- || ((ci->values[0].type != OCONFIG_TYPE_STRING)
- && (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)))
+ int status;
+ int tmp = 0;
+
+ status = cf_util_get_int (ci, &tmp);
+ if (status != 0)
+ return (status);
+ if (tmp < 0)
+ return (EINVAL);
+
+ *ret = tmp;
+ return (0);
+} /* int rc_config_get_int_positive */
+
+static int rc_config_get_xff (oconfig_item_t const *ci, double *ret)
+{
+ double value;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
{
- ERROR ("rrdcached plugin: %s expects a single string argument.",
- ci->key);
- return (NULL);
+ ERROR ("rrdcached plugin: The \"%s\" needs exactly one numeric argument "
+ "in the range [0.0, 1.0)", ci->key);
+ return (EINVAL);
}
- if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN) {
- if (ci->values[0].value.boolean)
- return "true";
- else
- return "false";
+ value = ci->values[0].value.number;
+ if ((value >= 0.0) && (value < 1.0))
+ {
+ *ret = value;
+ return (0);
}
- return (ci->values[0].value.string);
-} /* const char *config_get_string */
+
+ ERROR ("rrdcached plugin: The \"%s\" needs exactly one numeric argument "
+ "in the range [0.0, 1.0)", ci->key);
+ return (EINVAL);
+} /* int rc_config_get_xff */
+
+static int rc_config_add_timespan (int timespan)
+{
+ int *tmp;
+
+ if (timespan <= 0)
+ return (EINVAL);
+
+ tmp = realloc (rrdcreate_config.timespans,
+ sizeof (*rrdcreate_config.timespans)
+ * (rrdcreate_config.timespans_num + 1));
+ if (tmp == NULL)
+ return (ENOMEM);
+ rrdcreate_config.timespans = tmp;
+
+ rrdcreate_config.timespans[rrdcreate_config.timespans_num] = timespan;
+ rrdcreate_config.timespans_num++;
+
+ return (0);
+} /* int rc_config_add_timespan */
static int rc_config (oconfig_item_t *ci)
{
int i;
- for (i = 0; i < ci->children_num; ++i) {
- const char *key = ci->children[i].key;
- const char *value = config_get_string (ci->children + i);
-
- if (value == NULL) /* config_get_strings prints error message */
- continue;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t const *child = ci->children + i;
+ const char *key = child->key;
+ int status = 0;
if (strcasecmp ("DataDir", key) == 0)
{
- if (datadir != NULL)
- free (datadir);
- datadir = strdup (value);
- if (datadir != NULL)
+ status = cf_util_get_string (child, &datadir);
+ if (status == 0)
{
int len = strlen (datadir);
+
while ((len > 0) && (datadir[len - 1] == '/'))
{
len--;
- datadir[len] = '\0';
+ datadir[len] = 0;
}
+
if (len <= 0)
- {
- free (datadir);
- datadir = NULL;
- }
+ sfree (datadir);
}
}
else if (strcasecmp ("DaemonAddress", key) == 0)
- {
- sfree (daemon_address);
- daemon_address = strdup (value);
- if (daemon_address == NULL)
- {
- ERROR ("rrdcached plugin: strdup failed.");
- continue;
- }
- }
+ status = cf_util_get_string (child, &daemon_address);
else if (strcasecmp ("CreateFiles", key) == 0)
+ status = cf_util_get_boolean (child, &config_create_files);
+ else if (strcasecmp ("CollectStatistics", key) == 0)
+ status = cf_util_get_boolean (child, &config_collect_stats);
+ else if (strcasecmp ("StepSize", key) == 0)
{
- if (IS_FALSE (value))
- config_create_files = 0;
- else
- config_create_files = 1;
+ int tmp = -1;
+
+ status = rc_config_get_int_positive (child, &tmp);
+ if (status == 0)
+ rrdcreate_config.stepsize = (unsigned long) tmp;
}
- else if (strcasecmp ("CollectStatistics", key) == 0)
+ else if (strcasecmp ("HeartBeat", key) == 0)
+ status = rc_config_get_int_positive (child, &rrdcreate_config.heartbeat);
+ else if (strcasecmp ("RRARows", key) == 0)
+ status = rc_config_get_int_positive (child, &rrdcreate_config.rrarows);
+ else if (strcasecmp ("RRATimespan", key) == 0)
{
- if (IS_FALSE (value))
- config_collect_stats = 0;
- else
- config_collect_stats = 1;
+ int tmp = -1;
+ status = rc_config_get_int_positive (child, &tmp);
+ if (status == 0)
+ status = rc_config_add_timespan (tmp);
}
+ else if (strcasecmp ("XFF", key) == 0)
+ status = rc_config_get_xff (child, &rrdcreate_config.xff);
else
{
WARNING ("rrdcached plugin: Ignoring invalid option %s.", key);
continue;
}
+
+ if (status != 0)
+ WARNING ("rrdcached plugin: Handling the \"%s\" option failed.", key);
}
- if (daemon_address != NULL) {
+ if (daemon_address != NULL)
+ {
plugin_register_write ("rrdcached", rc_write, /* user_data = */ NULL);
plugin_register_flush ("rrdcached", rc_flush, /* user_data = */ NULL);
}
if (daemon_address == NULL)
return (-1);
- if (config_collect_stats == 0)
+ if (!config_collect_stats)
return (-1);
vl.values = values;
static int rc_init (void)
{
- if (config_collect_stats != 0)
+ if (config_collect_stats)
plugin_register_read ("rrdcached", rc_read);
return (0);
values_array[0] = values;
values_array[1] = NULL;
- if (config_create_files != 0)
+ if (config_create_files)
{
struct stat statbuf;
diff --git a/src/rrdtool.c b/src/rrdtool.c
index 56a82d0321b8a875fdc1a8b5c93e312550388b77..e5f964e5bdc4fe01084267ee0b821e298fd42650 100644 (file)
--- a/src/rrdtool.c
+++ b/src/rrdtool.c
if (status != 0)
{
WARNING ("rrdtool plugin: rrd_update_r failed: %s: %s",
- argv[1], rrd_get_error ());
+ filename, rrd_get_error ());
}
sfree (new_argv);
diff --git a/src/snmp.c b/src/snmp.c
index 160687f0ab56aad17116f5a198155f3f03e3652b..f4966694222e7a600c2ac2866eeea478aaf6edc5 100644 (file)
--- a/src/snmp.c
+++ b/src/snmp.c
/**
* collectd - src/snmp.c
- * Copyright (C) 2007 Florian octo Forster
+ * Copyright (C) 2007-2012 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
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Florian octo Forster <octo at verplant.org>
+ * Florian octo Forster <octo at collectd.org>
**/
#include "collectd.h"
* gaps in tables. */
struct csnmp_list_instances_s
{
- oid subid;
+ oid_t suffix;
char instance[DATA_MAX_NAME_LEN];
struct csnmp_list_instances_s *next;
};
struct csnmp_table_values_s
{
- oid subid;
+ oid_t suffix;
value_t value;
struct csnmp_table_values_s *next;
};
/*
* Private functions
*/
+static void csnmp_oid_init (oid_t *dst, oid const *src, size_t n)
+{
+ assert (n <= STATIC_ARRAY_LEN (dst->oid));
+ memcpy (dst->oid, src, sizeof (*src) * n);
+ dst->oid_len = n;
+}
+
+static int csnmp_oid_compare (oid_t const *left, oid_t const *right)
+{
+ return (snmp_oid_compare (left->oid, left->oid_len,
+ right->oid, right->oid_len));
+}
+
+static int csnmp_oid_suffix (oid_t *dst, oid_t const *src,
+ oid_t const *root)
+{
+ /* Make sure "src" is in "root"s subtree. */
+ if (src->oid_len <= root->oid_len)
+ return (EINVAL);
+ if (snmp_oid_ncompare (root->oid, root->oid_len,
+ src->oid, src->oid_len,
+ /* n = */ root->oid_len) != 0)
+ return (EINVAL);
+
+ memset (dst, 0, sizeof (*dst));
+ dst->oid_len = src->oid_len - root->oid_len;
+ memcpy (dst->oid, &src->oid[root->oid_len],
+ dst->oid_len * sizeof (dst->oid[0]));
+ return (0);
+}
+
+static int csnmp_oid_to_string (char *buffer, size_t buffer_size,
+ oid_t const *o)
+{
+ char oid_str[MAX_OID_LEN][16];
+ char *oid_str_ptr[MAX_OID_LEN];
+ size_t i;
+
+ for (i = 0; i < o->oid_len; i++)
+ {
+ ssnprintf (oid_str[i], sizeof (oid_str[i]), "%lu", (unsigned long) o->oid[i]);
+ oid_str_ptr[i] = oid_str[i];
+ }
+
+ return (strjoin (buffer, buffer_size,
+ oid_str_ptr, o->oid_len, /* separator = */ "."));
+}
+
static void csnmp_host_close_session (host_definition_t *host) /* {{{ */
{
if (host->sess_handle == NULL)
if (hd->name != NULL)
{
DEBUG ("snmp plugin: Destroying host definition for host `%s'.",
- hd->name);
+ hd->name);
}
csnmp_host_close_session (hd);
@@ -212,10 +260,10 @@ static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t
dd->instance.oid.oid_len = MAX_OID_LEN;
if (!read_objid (ci->values[0].value.string,
- dd->instance.oid.oid, &dd->instance.oid.oid_len))
+ dd->instance.oid.oid, &dd->instance.oid.oid_len))
{
ERROR ("snmp plugin: read_objid (%s) failed.",
- ci->values[0].value.string);
+ ci->values[0].value.string);
return (-1);
}
}
@@ -223,7 +271,7 @@ static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t
{
/* Instance is a simple string */
sstrncpy (dd->instance.string, ci->values[0].value.string,
- sizeof (dd->instance.string));
+ sizeof (dd->instance.string));
}
return (0);
if (!dd->is_table)
{
WARNING ("snmp plugin: data %s: InstancePrefix is ignored when `Table' "
- "is set to `false'.", dd->name);
+ "is set to `false'.", dd->name);
return (-1);
}
@@ -282,10 +330,10 @@ static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *
dd->values[i].oid_len = MAX_OID_LEN;
if (NULL == snmp_parse_oid (ci->values[i].value.string,
- dd->values[i].oid, &dd->values[i].oid_len))
+ dd->values[i].oid, &dd->values[i].oid_len))
{
ERROR ("snmp plugin: snmp_parse_oid (%s) failed.",
- ci->values[i].value.string);
+ ci->values[i].value.string);
free (dd->values);
dd->values = NULL;
dd->values_len = 0;
@@ -301,7 +349,7 @@ static int csnmp_config_add_data_shift (data_definition_t *dd, oconfig_item_t *c
if ((ci->values_num != 1)
|| (ci->values[0].type != OCONFIG_TYPE_NUMBER))
{
- WARNING ("snmp plugin: The `Scale' config option needs exactly one number argument.");
+ WARNING ("snmp plugin: The `Shift' config option needs exactly one number argument.");
return (-1);
}
{
for (data = data_head; data != NULL; data = data->next)
if (strcasecmp (ci->values[i].value.string, data->name) == 0)
- break;
+ break;
if (data == NULL)
{
WARNING ("snmp plugin: No such data configured: `%s'",
- ci->values[i].value.string);
+ ci->values[i].value.string);
continue;
}
DEBUG ("snmp plugin: Collect: host = %s, data[%i] = %s;",
- host->name, host->data_list_len, data->name);
+ host->name, host->data_list_len, data->name);
host->data_list[host->data_list_len] = data;
host->data_list_len++;
snmp_error (&sess, NULL, NULL, &errstr);
ERROR ("snmp plugin: host %s: snmp_sess_open failed: %s",
- host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+ host->name, (errstr == NULL) ? "Unknown problem" : errstr);
sfree (errstr);
}
} /* void csnmp_host_open_session */
memset (oid_buffer, 0, sizeof (oid_buffer));
snprint_objid (oid_buffer, sizeof (oid_buffer) - 1,
- vl->name, vl->name_length);
+ vl->name, vl->name_length);
#ifdef ASN_NULL
if (vl->type == ASN_NULL)
INFO ("snmp plugin: OID \"%s\" is undefined (type ASN_NULL)",
- oid_buffer);
+ oid_buffer);
else
#endif
WARNING ("snmp plugin: I don't know the ASN type #%i "
string_length = sizeof (string) - 1;
if (vl->val_len < string_length)
- string_length = vl->val_len;
+ 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 `memcpy' here and not `strcpy'.
status = parse_value (string, &ret, type);
if (status != 0)
{
- ERROR ("snmp plugin: csnmp_value_list_to_value: Parsing string as %s failed: %s",
- DS_TYPE_TO_STRING (type), string);
+ ERROR ("snmp plugin: csnmp_value_list_to_value: Parsing string as %s failed: %s",
+ DS_TYPE_TO_STRING (type), string);
}
}
{
switch (type)
{
- case DS_TYPE_COUNTER:
- case DS_TYPE_DERIVE:
- case DS_TYPE_ABSOLUTE:
- memset (&ret, 0, sizeof (ret));
- break;
-
- case DS_TYPE_GAUGE:
- ret.gauge = NAN;
- break;
-
- default:
- ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown "
- "data source type: %i.", type);
- ret.gauge = NAN;
+ case DS_TYPE_COUNTER:
+ case DS_TYPE_DERIVE:
+ case DS_TYPE_ABSOLUTE:
+ memset (&ret, 0, sizeof (ret));
+ break;
+
+ case DS_TYPE_GAUGE:
+ ret.gauge = NAN;
+ break;
+
+ default:
+ ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown "
+ "data source type: %i.", type);
+ ret.gauge = NAN;
}
}
} /* if (vl->type == ASN_OCTET_STR) */
else
{
ERROR ("snmp plugin: csnmp_value_list_to_value: Unknown data source "
- "type: %i.", type);
+ "type: %i.", type);
ret.gauge = NAN;
}
vb = vb->next_variable, i++)
{
num_checked++;
- if (snmp_oid_ncompare (data->values[i].oid,
- data->values[i].oid_len,
- vb->name, vb->name_length,
- data->values[i].oid_len) != 0)
+
+ if ((vb->type == SNMP_ENDOFMIBVIEW)
+ || (snmp_oid_ncompare (data->values[i].oid,
+ data->values[i].oid_len,
+ vb->name, vb->name_length,
+ data->values[i].oid_len) != 0))
num_left_subtree++;
}
if (i < data->values_len)
{
ERROR ("snmp plugin: host %s: Expected %i variables, but got only %i",
- host->name, data->values_len, i);
+ host->name, data->values_len, i);
return (-1);
}
if (vb == NULL)
{
ERROR ("snmp plugin: host %s: Expected one more variable for "
- "the instance..", host->name);
+ "the instance..", host->name);
return (-1);
}
num_checked++;
if (snmp_oid_ncompare (data->instance.oid.oid,
- data->instance.oid.oid_len,
- vb->name, vb->name_length,
- data->instance.oid.oid_len) != 0)
+ data->instance.oid.oid_len,
+ vb->name, vb->name_length,
+ data->instance.oid.oid_len) != 0)
num_left_subtree++;
}
int status;
status = snprintf (buffer_ptr, buffer_free,
- (i == 0) ? "%02x" : ":%02x", (unsigned int) vb->val.bitstring[i]);
+ (i == 0) ? "%02x" : ":%02x", (unsigned int) vb->val.bitstring[i]);
if (status >= buffer_free)
{
{
csnmp_list_instances_t *il;
struct variable_list *vb;
+ oid_t vb_name;
+ int status;
/* Set vb on the last variable */
for (vb = res->variables;
if (vb == NULL)
return (-1);
- il = (csnmp_list_instances_t *) malloc (sizeof (csnmp_list_instances_t));
+ csnmp_oid_init (&vb_name, vb->name, vb->name_length);
+
+ il = malloc (sizeof (*il));
if (il == NULL)
{
ERROR ("snmp plugin: malloc failed.");
return (-1);
}
- il->subid = vb->name[vb->name_length - 1];
+ memset (il, 0, sizeof (*il));
il->next = NULL;
+ status = csnmp_oid_suffix (&il->suffix, &vb_name, &dd->instance.oid);
+ if (status != 0)
+ {
+ sfree (il);
+ return (status);
+ }
+
/* Get instance name */
if ((vb->type == ASN_OCTET_STR) || (vb->type == ASN_BIT_STR))
{
for (ptr = il->instance; *ptr != '\0'; ptr++)
{
if ((*ptr > 0) && (*ptr < 32))
- *ptr = ' ';
+ *ptr = ' ';
else if (*ptr == '/')
- *ptr = '_';
+ *ptr = '_';
}
DEBUG ("snmp plugin: il->instance = `%s';", il->instance);
}
value_t val = csnmp_value_list_to_value (vb, DS_TYPE_COUNTER,
/* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
ssnprintf (il->instance, sizeof (il->instance),
- "%llu", val.counter);
+ "%llu", val.counter);
}
/* TODO: Debugging output */
@@ -1048,8 +1109,8 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
csnmp_table_values_t **value_table_ptr;
int i;
- oid subid;
- int have_more;
+ _Bool have_more;
+ oid_t current_suffix;
ds = plugin_get_ds (data->type);
if (!ds)
@@ -1061,15 +1122,14 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
instance_list_ptr = instance_list;
- value_table_ptr = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
- * data->values_len);
+ value_table_ptr = malloc (sizeof (*value_table_ptr) * data->values_len);
if (value_table_ptr == NULL)
return (-1);
for (i = 0; i < data->values_len; i++)
value_table_ptr[i] = value_table[i];
vl.values_len = ds->ds_num;
- vl.values = (value_t *) malloc (sizeof (value_t) * vl.values_len);
+ vl.values = malloc (sizeof (*vl.values) * vl.values_len);
if (vl.values == NULL)
{
ERROR ("snmp plugin: malloc failed.");
@@ -1082,50 +1142,70 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
vl.interval = host->interval;
- subid = 0;
have_more = 1;
-
- while (have_more != 0)
+ memset (¤t_suffix, 0, sizeof (current_suffix));
+ while (have_more)
{
+ _Bool suffix_skipped = 0;
+
+ /* Determine next suffix to handle. */
if (instance_list != NULL)
{
- while ((instance_list_ptr != NULL)
- && (instance_list_ptr->subid < subid))
- instance_list_ptr = instance_list_ptr->next;
-
if (instance_list_ptr == NULL)
{
- have_more = 0;
- continue;
+ have_more = 0;
+ continue;
}
- else if (instance_list_ptr->subid > subid)
+
+ memcpy (¤t_suffix, &instance_list_ptr->suffix, sizeof (current_suffix));
+ }
+ else /* no instance configured */
+ {
+ csnmp_table_values_t *ptr = value_table_ptr[0];
+ if (ptr == NULL)
{
- subid = instance_list_ptr->subid;
- continue;
+ have_more = 0;
+ continue;
}
- } /* if (instance_list != NULL) */
+ memcpy (¤t_suffix, &ptr->suffix, sizeof (current_suffix));
+ }
+
+ /* Update all the value_table_ptr to point at the entry with the same
+ * trailing partial OID */
for (i = 0; i < data->values_len; i++)
{
while ((value_table_ptr[i] != NULL)
- && (value_table_ptr[i]->subid < subid))
- value_table_ptr[i] = value_table_ptr[i]->next;
+ && (csnmp_oid_compare (&value_table_ptr[i]->suffix, ¤t_suffix) < 0))
+ value_table_ptr[i] = value_table_ptr[i]->next;
if (value_table_ptr[i] == NULL)
{
- have_more = 0;
- break;
+ have_more = 0;
+ break;
}
- else if (value_table_ptr[i]->subid > subid)
+ else if (csnmp_oid_compare (&value_table_ptr[i]->suffix, ¤t_suffix) > 0)
{
- subid = value_table_ptr[i]->subid;
- break;
+ /* This suffix is missing in the subtree. Indicate this with the
+ * "suffix_skipped" flag and try the next instance / suffix. */
+ suffix_skipped = 1;
+ break;
}
} /* for (i = 0; i < columns; i++) */
- /* The subid has been increased - start scanning from the beginning
- * again.. */
- if (i < data->values_len)
+
+ if (!have_more)
+ break;
+
+ /* Matching the values failed. Start from the beginning again. */
+ if (suffix_skipped)
+ {
+ if (instance_list != NULL)
+ instance_list_ptr = instance_list_ptr->next;
+ else
+ value_table_ptr[0] = value_table_ptr[0]->next;
+
continue;
+ }
/* if we reach this line, all value_table_ptr[i] are non-NULL and are set
* to the same subid. instance_list_ptr is either NULL or points to the
@@ -1134,10 +1214,12 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
for (i = 1; i < data->values_len; i++)
{
assert (value_table_ptr[i] != NULL);
- assert (value_table_ptr[i-1]->subid == value_table_ptr[i]->subid);
+ assert (csnmp_oid_compare (&value_table_ptr[i-1]->suffix,
+ &value_table_ptr[i]->suffix) == 0);
}
assert ((instance_list_ptr == NULL)
- || (instance_list_ptr->subid == value_table_ptr[0]->subid));
+ || (csnmp_oid_compare (&instance_list_ptr->suffix,
+ &value_table_ptr[0]->suffix) == 0));
#endif
sstrncpy (vl.type, data->type, sizeof (vl.type));
@@ -1146,15 +1228,15 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
char temp[DATA_MAX_NAME_LEN];
if (instance_list_ptr == NULL)
- ssnprintf (temp, sizeof (temp), "%"PRIu32, (uint32_t) subid);
+ csnmp_oid_to_string (temp, sizeof (temp), ¤t_suffix);
else
- sstrncpy (temp, instance_list_ptr->instance, sizeof (temp));
+ sstrncpy (temp, instance_list_ptr->instance, sizeof (temp));
if (data->instance_prefix == NULL)
- sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance));
+ sstrncpy (vl.type_instance, temp, sizeof (vl.type_instance));
else
- ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
- data->instance_prefix, temp);
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%s%s",
+ data->instance_prefix, temp);
}
for (i = 0; i < data->values_len; i++)
@@ -1163,8 +1245,11 @@ static int csnmp_dispatch_table (host_definition_t *host, data_definition_t *dat
/* If we get here `vl.type_instance' and all `vl.values' have been set */
plugin_dispatch_values (&vl);
- subid++;
- } /* while (have_more != 0) */
+ if (instance_list != NULL)
+ instance_list_ptr = instance_list_ptr->next;
+ else
+ value_table_ptr[0] = value_table_ptr[0]->next;
+ } /* while (have_more) */
sfree (vl.values);
sfree (value_table_ptr);
@@ -1185,13 +1270,13 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
int status;
int i;
- /* `value_table' and `value_table_ptr' implement a linked list for each
- * value. `instance_list' and `instance_list_ptr' implement a linked list of
+ /* `value_list_head' and `value_list_tail' implement a linked list for each
+ * value. `instance_list_head' and `instance_list_tail' implement a linked list of
* instance names. This is used to jump gaps in the table. */
- csnmp_list_instances_t *instance_list;
- csnmp_list_instances_t *instance_list_ptr;
- csnmp_table_values_t **value_table;
- csnmp_table_values_t **value_table_ptr;
+ csnmp_list_instances_t *instance_list_head;
+ csnmp_list_instances_t *instance_list_tail;
+ csnmp_table_values_t **value_list_head;
+ csnmp_table_values_t **value_list_tail;
DEBUG ("snmp plugin: csnmp_read_table (host = %s, data = %s)",
host->name, data->name);
@@ -1212,7 +1297,7 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
if (ds->ds_num != data->values_len)
{
ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
- data->type, ds->ds_num, data->values_len);
+ data->type, ds->ds_num, data->values_len);
return (-1);
}
@@ -1230,20 +1315,22 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
else
oid_list_len--;
- /* Allocate the `value_table' */
- value_table = (csnmp_table_values_t **) malloc (sizeof (csnmp_table_values_t *)
- * 2 * data->values_len);
- if (value_table == NULL)
+ /* We're going to construct n linked lists, one for each "value".
+ * value_list_head will contain pointers to the heads of these linked lists,
+ * value_list_tail will contain pointers to the tail of the lists. */
+ value_list_head = calloc (data->values_len, sizeof (*value_list_head));
+ value_list_tail = calloc (data->values_len, sizeof (*value_list_tail));
+ if ((value_list_head == NULL) || (value_list_tail == NULL))
{
- ERROR ("snmp plugin: csnmp_read_table: malloc failed.");
+ ERROR ("snmp plugin: csnmp_read_table: calloc failed.");
sfree (oid_list);
+ sfree (value_list_head);
+ sfree (value_list_tail);
return (-1);
}
- memset (value_table, '\0', sizeof (csnmp_table_values_t *) * 2 * data->values_len);
- value_table_ptr = value_table + data->values_len;
-
- instance_list = NULL;
- instance_list_ptr = NULL;
+
+ instance_list_head = NULL;
+ instance_list_tail = NULL;
status = 0;
while (status == 0)
@@ -1269,11 +1356,11 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
c_complain (LOG_ERR, &host->complaint,
- "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
- host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+ "snmp plugin: host %s: snmp_sess_synch_response failed: %s",
+ host->name, (errstr == NULL) ? "Unknown problem" : errstr);
if (res != NULL)
- snmp_free_pdu (res);
+ snmp_free_pdu (res);
res = NULL;
sfree (errstr);
@@ -1285,8 +1372,8 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
status = 0;
assert (res != NULL);
c_release (LOG_INFO, &host->complaint,
- "snmp plugin: host %s: snmp_sess_synch_response successful.",
- host->name);
+ "snmp plugin: host %s: snmp_sess_synch_response successful.",
+ host->name);
vb = res->variables;
if (vb == NULL)
@@ -1303,76 +1390,90 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
break;
}
- /* if an instance-OID is configured.. */
+ /* Copy the OID of the value used as instance to oid_list, if an instance
+ * is configured. */
if (data->instance.oid.oid_len > 0)
{
/* Allocate a new `csnmp_list_instances_t', insert the instance name and
* add it to the list */
- if (csnmp_instance_list_add (&instance_list, &instance_list_ptr,
+ if (csnmp_instance_list_add (&instance_list_head, &instance_list_tail,
res, host, data) != 0)
{
- ERROR ("snmp plugin: csnmp_instance_list_add failed.");
- status = -1;
- break;
+ ERROR ("snmp plugin: csnmp_instance_list_add failed.");
+ status = -1;
+ break;
}
- /* Set vb on the last variable */
+ /* The instance OID is added to the list of OIDs to GET from the
+ * snmp agent last, so set vb on the last variable returned and copy
+ * that OID. */
for (vb = res->variables;
- (vb != NULL) && (vb->next_variable != NULL);
- vb = vb->next_variable)
- /* do nothing */;
+ (vb != NULL) && (vb->next_variable != NULL);
+ vb = vb->next_variable)
+ /* do nothing */;
assert (vb != NULL);
- /* Copy OID to oid_list[data->values_len] */
+ /* Copy the OID of the instance value to oid_list[data->values_len].
+ * "oid_list" is used for the next GETNEXT request. */
memcpy (oid_list[data->values_len].oid, vb->name,
- sizeof (oid) * vb->name_length);
+ sizeof (oid) * vb->name_length);
oid_list[data->values_len].oid_len = vb->name_length;
}
+ /* Iterate over all the (non-instance) values returned by the agent. The
+ * (i < value_len) check will make sure we're not handling the instance OID
+ * twice. */
for (vb = res->variables, i = 0;
- (vb != NULL) && (i < data->values_len);
- vb = vb->next_variable, i++)
+ (vb != NULL) && (i < data->values_len);
+ vb = vb->next_variable, i++)
{
csnmp_table_values_t *vt;
+ oid_t vb_name;
+ oid_t suffix;
- /* Check if we left the subtree */
- if (snmp_oid_ncompare (data->values[i].oid,
- data->values[i].oid_len,
- vb->name, vb->name_length,
- data->values[i].oid_len) != 0)
+ csnmp_oid_init (&vb_name, vb->name, vb->name_length);
+
+ /* Calculate the current suffix. This is later used to check that the
+ * suffix is increasing. This also checks if we left the subtree */
+ status = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
+ if (status != 0)
{
- DEBUG ("snmp plugin: host = %s; data = %s; Value %i left its subtree.",
- host->name, data->name, i);
- continue;
+ DEBUG ("snmp plugin: host = %s; data = %s; Value %i failed. "
+ "It probably left its subtree.",
+ host->name, data->name, i);
+ continue;
}
- if ((value_table_ptr[i] != NULL)
- && (vb->name[vb->name_length - 1] <= value_table_ptr[i]->subid))
+ /* Make sure the OIDs returned by the agent are increasing. Otherwise our
+ * table matching algorithm will get confused. */
+ if ((value_list_tail[i] != NULL)
+ && (csnmp_oid_compare (&suffix, &value_list_tail[i]->suffix) <= 0))
{
- DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
- "SUBID is not increasing.",
- host->name, data->name, i);
- continue;
+ DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
+ "Suffix is not increasing.",
+ host->name, data->name, i);
+ continue;
}
- vt = (csnmp_table_values_t *) malloc (sizeof (csnmp_table_values_t));
+ vt = malloc (sizeof (*vt));
if (vt == NULL)
{
- ERROR ("snmp plugin: malloc failed.");
- status = -1;
- break;
+ ERROR ("snmp plugin: malloc failed.");
+ status = -1;
+ break;
}
+ memset (vt, 0, sizeof (*vt));
- vt->subid = vb->name[vb->name_length - 1];
vt->value = csnmp_value_list_to_value (vb, ds->ds[i].type,
data->scale, data->shift, host->name, data->name);
+ memcpy (&vt->suffix, &suffix, sizeof (vt->suffix));
vt->next = NULL;
- if (value_table_ptr[i] == NULL)
- value_table[i] = vt;
+ if (value_list_tail[i] == NULL)
+ value_list_head[i] = vt;
else
- value_table_ptr[i]->next = vt;
- value_table_ptr[i] = vt;
+ value_list_tail[i]->next = vt;
+ value_list_tail[i] = vt;
/* Copy OID to oid_list[i + 1] */
memcpy (oid_list[i].oid, vb->name, sizeof (oid) * vb->name_length);
@@ -1389,28 +1490,28 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
res = NULL;
if (status == 0)
- csnmp_dispatch_table (host, data, instance_list, value_table);
+ csnmp_dispatch_table (host, data, instance_list_head, value_list_head);
/* Free all allocated variables here */
- while (instance_list != NULL)
+ while (instance_list_head != NULL)
{
- instance_list_ptr = instance_list->next;
- sfree (instance_list);
- instance_list = instance_list_ptr;
+ csnmp_list_instances_t *next = instance_list_head->next;
+ sfree (instance_list_head);
+ instance_list_head = next;
}
for (i = 0; i < data->values_len; i++)
{
- csnmp_table_values_t *tmp;
- while (value_table[i] != NULL)
+ while (value_list_head[i] != NULL)
{
- tmp = value_table[i]->next;
- sfree (value_table[i]);
- value_table[i] = tmp;
+ csnmp_table_values_t *next = value_list_head[i]->next;
+ sfree (value_list_head[i]);
+ value_list_head[i] = next;
}
}
- sfree (value_table);
+ sfree (value_list_head);
+ sfree (value_list_tail);
sfree (oid_list);
return (0);
@@ -1447,7 +1548,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
if (ds->ds_num != data->values_len)
{
ERROR ("snmp plugin: DataSet `%s' requires %i values, but config talks about %i",
- data->type, ds->ds_num, data->values_len);
+ data->type, ds->ds_num, data->values_len);
return (-1);
}
@@ -1490,7 +1591,7 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
snmp_sess_error (host->sess_handle, NULL, NULL, &errstr);
ERROR ("snmp plugin: host %s: snmp_sess_synch_response failed: %s",
- host->name, (errstr == NULL) ? "Unknown problem" : errstr);
+ host->name, (errstr == NULL) ? "Unknown problem" : errstr);
if (res != NULL)
snmp_free_pdu (res);
@@ -1508,13 +1609,13 @@ static int csnmp_read_value (host_definition_t *host, data_definition_t *data)
#if COLLECT_DEBUG
char buffer[1024];
snprint_variable (buffer, sizeof (buffer),
- vb->name, vb->name_length, vb);
+ vb->name, vb->name_length, vb);
DEBUG ("snmp plugin: Got this variable: %s", buffer);
#endif /* COLLECT_DEBUG */
for (i = 0; i < data->values_len; i++)
if (snmp_oid_compare (data->values[i].oid, data->values[i].oid_len,
- vb->name, vb->name_length) == 0)
+ vb->name, vb->name_length) == 0)
vl.values[i] = csnmp_value_list_to_value (vb, ds->ds[i].type,
data->scale, data->shift, host->name, data->name);
} /* for (res->variables) */
diff --git a/src/swap.c b/src/swap.c
index 397969eff0ce0ea7a4eb48762bdef9d0e019bbd6..46d3534fcae818cd6fc286cd448d824ad22ccad8 100644 (file)
--- a/src/swap.c
+++ b/src/swap.c
/**
* collectd - src/swap.c
- * Copyright (C) 2005-2010 Florian octo Forster
+ * Copyright (C) 2005-2012 Florian octo Forster
* Copyright (C) 2009 Stefan Völkel
* Copyright (C) 2009 Manuel Sanmartin
* Copyright (C) 2010 Aurélien Reynaud
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#if KERNEL_LINUX
-# define SWAP_HAVE_CONFIG 1
-/* No global variables */
+# define SWAP_HAVE_REPORT_BY_DEVICE 1
+static derive_t pagesize;
+static _Bool report_bytes = 0;
+static _Bool report_by_device = 0;
/* #endif KERNEL_LINUX */
#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
-# define SWAP_HAVE_CONFIG 1
+# define SWAP_HAVE_REPORT_BY_DEVICE 1
static derive_t pagesize;
+static _Bool report_by_device = 0;
/* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS */
#elif defined(VM_SWAPUSAGE)
# error "No applicable input method."
#endif /* HAVE_LIBSTATGRAB */
-#if SWAP_HAVE_CONFIG
static const char *config_keys[] =
{
+ "ReportBytes",
"ReportByDevice"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
-static _Bool report_by_device = 0;
-
static int swap_config (const char *key, const char *value) /* {{{ */
{
- if (strcasecmp ("ReportByDevice", key) == 0)
+ if (strcasecmp ("ReportBytes", key) == 0)
+ {
+#if KERNEL_LINUX
+ report_bytes = IS_TRUE (value) ? 1 : 0;
+#else
+ WARNING ("swap plugin: The \"ReportBytes\" option is only "
+ "valid under Linux. "
+ "The option is going to be ignored.");
+#endif
+ }
+ else if (strcasecmp ("ReportByDevice", key) == 0)
{
+#if SWAP_HAVE_REPORT_BY_DEVICE
if (IS_TRUE (value))
report_by_device = 1;
else
report_by_device = 0;
+#else
+ WARNING ("swap plugin: The \"ReportByDevice\" option is not "
+ "supported on this platform. "
+ "The option is going to be ignored.");
+#endif /* SWAP_HAVE_REPORT_BY_DEVICE */
}
else
{
return (0);
} /* }}} int swap_config */
-#endif /* SWAP_HAVE_CONFIG */
static int swap_init (void) /* {{{ */
{
#if KERNEL_LINUX
- /* No init stuff */
+ pagesize = (derive_t) sysconf (_SC_PAGESIZE);
/* #endif KERNEL_LINUX */
#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
swap_submit (plugin_instance, "swap", type_instance, v);
} /* }}} void swap_submit_gauge */
-#if KERNEL_LINUX
+#if KERNEL_LINUX || HAVE_PERFSTAT
static void swap_submit_derive (const char *plugin_instance, /* {{{ */
const char *type_instance, derive_t value)
{
v.derive = value;
swap_submit (plugin_instance, "swap_io", type_instance, v);
} /* }}} void swap_submit_derive */
+#endif
+#if KERNEL_LINUX
static int swap_read_separate (void) /* {{{ */
{
FILE *fh;
if (have_data != 0x03)
return (ENOENT);
+ if (report_bytes)
+ {
+ swap_in = swap_in * pagesize;
+ swap_out = swap_out * pagesize;
+ }
+
swap_submit_derive (NULL, "in", swap_in);
swap_submit_derive (NULL, "out", swap_out);
sstrerror (errno, errbuf, sizeof (errbuf)));
return (-1);
}
+
swap_submit_gauge (NULL, "used", (gauge_t) (pmemory.pgsp_total - pmemory.pgsp_free) * pagesize);
swap_submit_gauge (NULL, "free", (gauge_t) pmemory.pgsp_free * pagesize );
+ swap_submit_gauge (NULL, "reserved", (gauge_t) pmemory.pgsp_rsvd * pagesize);
+ swap_submit_derive (NULL, "in", (derive_t) pmemory.pgspins * pagesize);
+ swap_submit_derive (NULL, "out", (derive_t) pmemory.pgspouts * pagesize);
return (0);
} /* }}} int swap_read */
void module_register (void)
{
-#if SWAP_HAVE_CONFIG
- plugin_register_config ("swap", swap_config, config_keys, config_keys_num);
-#endif
+ plugin_register_config ("swap", swap_config,
+ config_keys, config_keys_num);
plugin_register_init ("swap", swap_init);
plugin_register_read ("swap", swap_read);
} /* void module_register */
diff --git a/src/tcpconns.c b/src/tcpconns.c
index 3c8fc7285e2621c57fa5f3779d08df70e8ed7179..765b892e265498e0299fb4f7c4f2265eef93290c 100644 (file)
--- a/src/tcpconns.c
+++ b/src/tcpconns.c
#endif
#if KERNEL_LINUX
+# include <asm/types.h>
+/* sys/socket.h is necessary to compile when using netlink on older systems. */
+# include <sys/socket.h>
+# include <linux/netlink.h>
+# include <linux/inet_diag.h>
+# include <sys/socket.h>
+# include <arpa/inet.h>
/* #endif KERNEL_LINUX */
#elif HAVE_SYSCTLBYNAME
#endif /* KERNEL_AIX */
#if KERNEL_LINUX
+struct nlreq {
+ struct nlmsghdr nlh;
+ struct inet_diag_req r;
+};
+
static const char *tcp_state[] =
{
"", /* 0 */
static int port_collect_listening = 0;
static port_entry_t *port_list_head = NULL;
+#if KERNEL_LINUX
+static uint32_t sequence_number = 0;
+
+enum
+{
+ SRC_DUNNO,
+ SRC_NETLINK,
+ SRC_PROC
+} linux_source = SRC_DUNNO;
+#endif
+
static void conn_submit_port_entry (port_entry_t *pe)
{
value_t values[1];
@@ -419,6 +442,140 @@ static int conn_handle_ports (uint16_t port_local, uint16_t port_remote, uint8_t
} /* int conn_handle_ports */
#if KERNEL_LINUX
+/* Returns zero on success, less than zero on socket error and greater than
+ * zero on other errors. */
+static int conn_read_netlink (void)
+{
+ int fd;
+ struct sockaddr_nl nladdr;
+ struct nlreq req;
+ struct msghdr msg;
+ struct iovec iov;
+ struct inet_diag_msg *r;
+ char buf[8192];
+
+ /* If this fails, it's likely a permission problem. We'll fall back to
+ * reading this information from files below. */
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG);
+ if (fd < 0)
+ {
+ ERROR ("tcpconns plugin: conn_read_netlink: socket(AF_NETLINK, SOCK_RAW, "
+ "NETLINK_INET_DIAG) failed: %s",
+ sstrerror (errno, buf, sizeof (buf)));
+ return (-1);
+ }
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ memset(&req, 0, sizeof(req));
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
+ /* NLM_F_ROOT: return the complete table instead of a single entry.
+ * NLM_F_MATCH: return all entries matching criteria (not implemented)
+ * NLM_F_REQUEST: must be set on all request messages */
+ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ /* The sequence_number is used to track our messages. Since netlink is not
+ * reliable, we don't want to end up with a corrupt or incomplete old
+ * message in case the system is/was out of memory. */
+ req.nlh.nlmsg_seq = ++sequence_number;
+ req.r.idiag_family = AF_INET;
+ req.r.idiag_states = 0xfff;
+ req.r.idiag_ext = 0;
+
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = &req;
+ iov.iov_len = sizeof(req);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (void*)&nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if (sendmsg (fd, &msg, 0) < 0)
+ {
+ ERROR ("tcpconns plugin: conn_read_netlink: sendmsg(2) failed: %s",
+ sstrerror (errno, buf, sizeof (buf)));
+ close (fd);
+ return (-1);
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+
+ while (1)
+ {
+ int status;
+ struct nlmsghdr *h;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = (void*)&nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ status = recvmsg(fd, (void *) &msg, /* flags = */ 0);
+ if (status < 0)
+ {
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+
+ ERROR ("tcpconns plugin: conn_read_netlink: recvmsg(2) failed: %s",
+ sstrerror (errno, buf, sizeof (buf)));
+ close (fd);
+ return (-1);
+ }
+ else if (status == 0)
+ {
+ close (fd);
+ DEBUG ("tcpconns plugin: conn_read_netlink: Unexpected zero-sized "
+ "reply from netlink socket.");
+ return (0);
+ }
+
+ h = (struct nlmsghdr*)buf;
+ while (NLMSG_OK(h, status))
+ {
+ if (h->nlmsg_seq != sequence_number)
+ {
+ h = NLMSG_NEXT(h, status);
+ continue;
+ }
+
+ if (h->nlmsg_type == NLMSG_DONE)
+ {
+ close (fd);
+ return (0);
+ }
+ else if (h->nlmsg_type == NLMSG_ERROR)
+ {
+ struct nlmsgerr *msg_error;
+
+ msg_error = NLMSG_DATA(h);
+ WARNING ("tcpconns plugin: conn_read_netlink: Received error %i.",
+ msg_error->error);
+
+ close (fd);
+ return (1);
+ }
+
+ r = NLMSG_DATA(h);
+
+ /* This code does not (need to) distinguish between IPv4 and IPv6. */
+ conn_handle_ports (ntohs(r->id.idiag_sport),
+ ntohs(r->id.idiag_dport),
+ r->idiag_state);
+
+ h = NLMSG_NEXT(h, status);
+ } /* while (NLMSG_OK) */
+ } /* while (1) */
+
+ /* Not reached because the while() loop above handles the exit condition. */
+ return (0);
+} /* int conn_read_netlink */
+
static int conn_handle_line (char *buffer)
{
char *fields[32];
static int conn_read (void)
{
- int errors_num = 0;
+ int status;
conn_reset_port_entry ();
- if (conn_read_file ("/proc/net/tcp") != 0)
- errors_num++;
- if (conn_read_file ("/proc/net/tcp6") != 0)
- errors_num++;
-
- if (errors_num < 2)
+ if (linux_source == SRC_NETLINK)
{
- conn_submit_all ();
+ status = conn_read_netlink ();
}
- else
+ else if (linux_source == SRC_PROC)
{
- ERROR ("tcpconns plugin: Neither /proc/net/tcp nor /proc/net/tcp6 "
- "coult be read.");
- return (-1);
+ int errors_num = 0;
+
+ if (conn_read_file ("/proc/net/tcp") != 0)
+ errors_num++;
+ if (conn_read_file ("/proc/net/tcp6") != 0)
+ errors_num++;
+
+ if (errors_num < 2)
+ status = 0;
+ else
+ status = ENOENT;
+ }
+ else /* if (linux_source == SRC_DUNNO) */
+ {
+ /* Try to use netlink for getting this data, it is _much_ faster on systems
+ * with a large amount of connections. */
+ status = conn_read_netlink ();
+ if (status == 0)
+ {
+ INFO ("tcpconns plugin: Reading from netlink succeeded. "
+ "Will use the netlink method from now on.");
+ linux_source = SRC_NETLINK;
+ }
+ else
+ {
+ INFO ("tcpconns plugin: Reading from netlink failed. "
+ "Will read from /proc from now on.");
+ linux_source = SRC_PROC;
+
+ /* return success here to avoid the "plugin failed" message. */
+ return (0);
+ }
}
+ if (status == 0)
+ conn_submit_all ();
+ else
+ return (status);
+
return (0);
} /* int conn_read */
/* #endif KERNEL_LINUX */
diff --git a/src/unixsock.c b/src/unixsock.c
index d729477bbc54db999322dedfe581834dc9725c21..0dc7d659400193a8bf29fc0ab3f78a9556826a90 100644 (file)
--- a/src/unixsock.c
+++ b/src/unixsock.c
close (fdin);
close (fdout);
pthread_exit ((void *) 1);
+ return ((void *) 1);
}
fhout = fdopen (fdout, "w");
fclose (fhin); /* this closes fdin as well */
close (fdout);
pthread_exit ((void *) 1);
+ return ((void *) 1);
}
/* change output buffer to line buffered mode */
fclose (fhin);
fclose (fhout);
pthread_exit ((void *) 1);
+ return ((void *) 0);
}
while (42)
errno = 0;
if (fgets (buffer, sizeof (buffer), fhin) == NULL)
{
+ if ((errno == EINTR) || (errno == EAGAIN))
+ continue;
+
if (errno != 0)
{
char errbuf[1024];
fclose (fhin);
fclose (fhout);
pthread_exit ((void *) 1);
+ return ((void *) 1);
}
if (strcasecmp (fields[0], "getval") == 0)
pthread_t th;
pthread_attr_t th_attr;
+ pthread_attr_init (&th_attr);
+ pthread_attr_setdetachstate (&th_attr, PTHREAD_CREATE_DETACHED);
+
if (us_open_socket () != 0)
pthread_exit ((void *) 1);
sstrerror (errno, errbuf, sizeof (errbuf)));
close (sock_fd);
sock_fd = -1;
+ pthread_attr_destroy (&th_attr);
pthread_exit ((void *) 1);
}
DEBUG ("Spawning child to handle connection on fd #%i", *remote_fd);
- pthread_attr_init (&th_attr);
- pthread_attr_setdetachstate (&th_attr, PTHREAD_CREATE_DETACHED);
-
status = pthread_create (&th, &th_attr, us_handle_client, (void *) remote_fd);
if (status != 0)
{
close (sock_fd);
sock_fd = -1;
+ pthread_attr_destroy (&th_attr);
status = unlink ((sock_file != NULL) ? sock_file : US_DEFAULT_PATH);
if (status != 0)
diff --git a/src/uptime.c b/src/uptime.c
index d2ba9633db290aeb17ac0a064874b3c652742b3a..064c3ceed4752a359c7ec2e5b9d84afa27068543 100644 (file)
--- a/src/uptime.c
+++ b/src/uptime.c
/* Using sysctl interface to retrieve the boot time on *BSD / Darwin / OS X systems */
/* #endif HAVE_SYS_SYSCTL_H */
+#elif HAVE_PERFSTAT
+# include <sys/protosw.h>
+# include <libperfstat.h>
+/* Using perfstat_cpu_total to retrive the boot time in AIX */
+/* #endif HAVE_PERFSTAT */
+
#else
# error "No applicable input method."
#endif
"but `boottime' is zero!");
return (-1);
}
-#endif /* HAVE_SYS_SYSCTL_H */
+/* #endif HAVE_SYS_SYSCTL_H */
+
+#elif HAVE_PERFSTAT
+ int status;
+ perfstat_cpu_total_t cputotal;
+ int hertz;
+
+ status = perfstat_cpu_total(NULL, &cputotal,
+ sizeof(perfstat_cpu_total_t), 1);
+ if (status < 0)
+ {
+ char errbuf[1024];
+ ERROR ("uptime plugin: perfstat_cpu_total: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ hertz = sysconf(_SC_CLK_TCK);
+ if (hertz <= 0)
+ hertz = HZ;
+
+ boottime = time(NULL) - cputotal.lbolt / hertz;
+#endif /* HAVE_PERFSTAT */
return (0);
} /* }}} int uptime_init */
diff --git a/src/utils_avltree.c b/src/utils_avltree.c
index 0436d8fe077eceeaffdeff607bc8f9e44ebe5aca..f71b1fd6913bbc9676bb0e494d26bba1f829e7c2 100644 (file)
--- a/src/utils_avltree.c
+++ b/src/utils_avltree.c
void c_avl_destroy (c_avl_tree_t *t)
{
+ if (t == NULL)
+ return;
free_node (t->root);
free (t);
}
{
new->parent = NULL;
t->root = new;
+ t->size = 1;
return (0);
}
diff --git a/src/utils_cache.c b/src/utils_cache.c
index dd5bcb59ffc9833b2a92341a085e32d526e9e812..fa6e6603ec3e10eedcdc6ea7d56ab64a0b04db6e 100644 (file)
--- a/src/utils_cache.c
+++ b/src/utils_cache.c
char **names = NULL;
cdtime_t *times = NULL;
size_t number = 0;
+ size_t size_arrays = 0;
int status = 0;
@@ -580,42 +581,47 @@ int uc_get_names (char ***ret_names, cdtime_t **ret_times, size_t *ret_number)
pthread_mutex_lock (&cache_lock);
+ size_arrays = (size_t) c_avl_size (cache_tree);
+ if (size_arrays < 1)
+ {
+ /* Handle the "no values" case here, to avoid the error message when
+ * calloc() returns NULL. */
+ pthread_mutex_unlock (&cache_lock);
+ return (0);
+ }
+
+ names = calloc (size_arrays, sizeof (*names));
+ times = calloc (size_arrays, sizeof (*times));
+ if ((names == NULL) || (times == NULL))
+ {
+ ERROR ("uc_get_names: calloc failed.");
+ sfree (names);
+ sfree (times);
+ pthread_mutex_unlock (&cache_lock);
+ return (ENOMEM);
+ }
+
iter = c_avl_get_iterator (cache_tree);
while (c_avl_iterator_next (iter, (void *) &key, (void *) &value) == 0)
{
- char **temp;
-
/* remove missing values when list values */
if (value->state == STATE_MISSING)
continue;
- if (ret_times != NULL)
- {
- cdtime_t *tmp_times;
+ /* c_avl_size does not return a number smaller than the number of elements
+ * returned by c_avl_iterator_next. */
+ assert (number < size_arrays);
- tmp_times = (cdtime_t *) realloc (times, sizeof (cdtime_t) * (number + 1));
- if (tmp_times == NULL)
- {
- status = -1;
- break;
- }
- times = tmp_times;
+ if (ret_times != NULL)
times[number] = value->last_time;
- }
- temp = (char **) realloc (names, sizeof (char *) * (number + 1));
- if (temp == NULL)
- {
- status = -1;
- break;
- }
- names = temp;
names[number] = strdup (key);
if (names[number] == NULL)
{
status = -1;
break;
}
+
number++;
} /* while (c_avl_iterator_next) */
diff --git a/src/utils_db_query.c b/src/utils_db_query.c
index dcac80764c665ca1dd98a456feea0cb2386692c4..aadf9c5ec1d7f6a4879a5701ebe19f2a25d23633 100644 (file)
--- a/src/utils_db_query.c
+++ b/src/utils_db_query.c
*/
static int udb_result_submit (udb_result_t *r, /* {{{ */
udb_result_preparation_area_t *r_area,
- const udb_query_t const *q, udb_query_preparation_area_t *q_area)
+ udb_query_t const *q, udb_query_preparation_area_t *q_area)
{
value_list_t vl = VALUE_LIST_INIT;
size_t i;
sstrncpy (vl.host, q_area->host, sizeof (vl.host));
sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
- sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.type_instance));
+ sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
sstrncpy (vl.type, r->type, sizeof (vl.type));
/* Set vl.type_instance {{{ */
return (0);
} /* }}} void udb_result_submit */
-static void udb_result_finish_result (const udb_result_t const *r, /* {{{ */
+static void udb_result_finish_result (udb_result_t const *r, /* {{{ */
udb_result_preparation_area_t *prep_area)
{
if ((r == NULL) || (prep_area == NULL))
static int udb_result_handle_result (udb_result_t *r, /* {{{ */
udb_query_preparation_area_t *q_area,
udb_result_preparation_area_t *r_area,
- const udb_query_t const *q, char **column_values)
+ udb_query_t const *q, char **column_values)
{
size_t i;
return udb_result_submit (r, r_area, q, q_area);
} /* }}} int udb_result_handle_result */
-static int udb_result_prepare_result (const udb_result_t const *r, /* {{{ */
+static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
udb_result_preparation_area_t *prep_area,
char **column_names, size_t column_num)
{
return (1);
} /* }}} int udb_query_check_version */
-void udb_query_finish_result (const udb_query_t const *q, /* {{{ */
+void udb_query_finish_result (udb_query_t const *q, /* {{{ */
udb_query_preparation_area_t *prep_area)
{
udb_result_preparation_area_t *r_area;
}
} /* }}} void udb_query_finish_result */
-int udb_query_handle_result (const udb_query_t const *q, /* {{{ */
+int udb_query_handle_result (udb_query_t const *q, /* {{{ */
udb_query_preparation_area_t *prep_area, char **column_values)
{
udb_result_preparation_area_t *r_area;
return (0);
} /* }}} int udb_query_handle_result */
-int udb_query_prepare_result (const udb_query_t const *q, /* {{{ */
+int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
udb_query_preparation_area_t *prep_area,
const char *host, const char *plugin, const char *db_name,
char **column_names, size_t column_num, cdtime_t interval)
diff --git a/src/utils_db_query.h b/src/utils_db_query.h
index 727be03647714e8bc76f6b4d5403508eeca74616..b6f4cea00d6351c8c0edcf97ab44d0a45cfc7e86 100644 (file)
--- a/src/utils_db_query.h
+++ b/src/utils_db_query.h
*/
int udb_query_check_version (udb_query_t *q, unsigned int version);
-int udb_query_prepare_result (const udb_query_t const *q,
+int udb_query_prepare_result (udb_query_t const *q,
udb_query_preparation_area_t *prep_area,
const char *host, const char *plugin, const char *db_name,
char **column_names, size_t column_num, cdtime_t interval);
-int udb_query_handle_result (const udb_query_t const *q,
+int udb_query_handle_result (udb_query_t const *q,
udb_query_preparation_area_t *prep_area, char **column_values);
-void udb_query_finish_result (const udb_query_t const *q,
+void udb_query_finish_result (udb_query_t const *q,
udb_query_preparation_area_t *prep_area);
udb_query_preparation_area_t *
diff --git a/src/utils_dns.c b/src/utils_dns.c
index cfa4a5cbefff989c28e4a46accb89e00f1a93f59..80a2ee577f7213c4182a57b70e5f220d6d4d92fa 100644 (file)
--- a/src/utils_dns.c
+++ b/src/utils_dns.c
#if HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
+#if HAVE_NETINET_IP6_H
+# include <netinet/ip6.h>
+#endif
+#if HAVE_NETINET_IP_COMPAT_H
+# include <netinet/ip_compat.h>
+#endif
#if HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#if HAVE_STRUCT_UDPHDR_UH_DPORT && HAVE_STRUCT_UDPHDR_UH_SPORT
# define UDP_DEST uh_dport
-# define UDP_SRC uh_dport
+# define UDP_SRC uh_sport
#elif HAVE_STRUCT_UDPHDR_DEST && HAVE_STRUCT_UDPHDR_SOURCE
# define UDP_DEST dest
# define UDP_SRC source
unsigned int offset;
int nexthdr;
- struct in6_addr s_addr;
+ struct in6_addr c_src_addr;
uint16_t payload_len;
if (0 > len)
offset = sizeof (struct ip6_hdr);
nexthdr = ipv6->ip6_nxt;
- s_addr = ipv6->ip6_src;
+ c_src_addr = ipv6->ip6_src;
payload_len = ntohs (ipv6->ip6_plen);
- if (ignore_list_match (&s_addr))
+ if (ignore_list_match (&c_src_addr))
return (0);
/* Parse extension headers. This only handles the standard headers, as
|| (IPPROTO_HOPOPTS == nexthdr) /* Hop-by-Hop options. */
|| (IPPROTO_FRAGMENT == nexthdr) /* fragmentation header. */
|| (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
- || (IPPROTO_DSTOPTS == nexthdr) /* destination options. */
|| (IPPROTO_AH == nexthdr) /* destination options. */
|| (IPPROTO_ESP == nexthdr)) /* encapsulating security payload. */
{
{
char buf[PCAP_SNAPLEN];
int offset = ip->ip_hl << 2;
- struct in6_addr s_addr;
- struct in6_addr d_addr;
+ struct in6_addr c_src_addr;
+ struct in6_addr c_dst_addr;
if (ip->ip_v == 6)
return (handle_ipv6 ((void *) ip, len));
- in6_addr_from_buffer (&s_addr, &ip->ip_src.s_addr, sizeof (ip->ip_src.s_addr), AF_INET);
- in6_addr_from_buffer (&d_addr, &ip->ip_dst.s_addr, sizeof (ip->ip_dst.s_addr), AF_INET);
- if (ignore_list_match (&s_addr))
+ in6_addr_from_buffer (&c_src_addr, &ip->ip_src.s_addr, sizeof (ip->ip_src.s_addr), AF_INET);
+ in6_addr_from_buffer (&c_dst_addr, &ip->ip_dst.s_addr, sizeof (ip->ip_dst.s_addr), AF_INET);
+ if (ignore_list_match (&c_src_addr))
return (0);
if (IPPROTO_UDP != ip->ip_p)
return 0;
diff --git a/src/utils_fbhash.c b/src/utils_fbhash.c
index d20b7e39bdd453de1bdec5c4564ed30e994647a6..97f21a1f78317ebc4cc5d8ccce7f61dcd322b0ae 100644 (file)
--- a/src/utils_fbhash.c
+++ b/src/utils_fbhash.c
if (h == NULL)
return;
+ pthread_mutex_destroy (&h->lock);
free (h->filename);
fbh_free_tree (h->tree);
} /* }}} void fbh_destroy */
diff --git a/src/utils_format_graphite.c b/src/utils_format_graphite.c
--- /dev/null
@@ -0,0 +1,240 @@
+/**
+ * collectd - src/utils_format_graphite.c
+ * Copyright (C) 2012 Thomas Meson
+ * Copyright (C) 2012 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:
+ * Thomas Meson <zllak at hycik.org>
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+
+#include "utils_cache.h"
+#include "utils_format_json.h"
+#include "utils_parse_option.h"
+
+/* Utils functions to format data sets in graphite format.
+ * Largely taken from write_graphite.c as it remains the same formatting */
+
+static int gr_format_values (char *ret, size_t ret_len,
+ int ds_num, const data_set_t *ds, const value_list_t *vl,
+ gauge_t const *rates)
+{
+ size_t offset = 0;
+ int status;
+
+ assert (0 == strcmp (ds->type, vl->type));
+
+ memset (ret, 0, ret_len);
+
+#define BUFFER_ADD(...) do { \
+ status = ssnprintf (ret + offset, ret_len - offset, \
+ __VA_ARGS__); \
+ if (status < 1) \
+ { \
+ return (-1); \
+ } \
+ else if (((size_t) status) >= (ret_len - offset)) \
+ { \
+ return (-1); \
+ } \
+ else \
+ offset += ((size_t) status); \
+} while (0)
+
+ if (ds->ds[ds_num].type == DS_TYPE_GAUGE)
+ BUFFER_ADD ("%f", vl->values[ds_num].gauge);
+ else if (rates != NULL)
+ BUFFER_ADD ("%f", rates[ds_num]);
+ else if (ds->ds[ds_num].type == DS_TYPE_COUNTER)
+ BUFFER_ADD ("%llu", vl->values[ds_num].counter);
+ else if (ds->ds[ds_num].type == DS_TYPE_DERIVE)
+ BUFFER_ADD ("%"PRIi64, vl->values[ds_num].derive);
+ else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
+ BUFFER_ADD ("%"PRIu64, vl->values[ds_num].absolute);
+ else
+ {
+ ERROR ("gr_format_values plugin: Unknown data source type: %i",
+ ds->ds[ds_num].type);
+ return (-1);
+ }
+
+#undef BUFFER_ADD
+
+ return (0);
+}
+
+static void gr_copy_escape_part (char *dst, const char *src, size_t dst_len,
+ char escape_char)
+{
+ size_t i;
+
+ memset (dst, 0, dst_len);
+
+ if (src == NULL)
+ return;
+
+ for (i = 0; i < dst_len; i++)
+ {
+ if (src[i] == 0)
+ {
+ dst[i] = 0;
+ break;
+ }
+
+ if ((src[i] == '.')
+ || isspace ((int) src[i])
+ || iscntrl ((int) src[i]))
+ dst[i] = escape_char;
+ else
+ dst[i] = src[i];
+ }
+}
+
+static int gr_format_name (char *ret, int ret_len,
+ const value_list_t *vl,
+ const char *ds_name,
+ char *prefix,
+ char *postfix,
+ char escape_char)
+{
+ char n_host[DATA_MAX_NAME_LEN];
+ char n_plugin[DATA_MAX_NAME_LEN];
+ char n_plugin_instance[DATA_MAX_NAME_LEN];
+ char n_type[DATA_MAX_NAME_LEN];
+ char n_type_instance[DATA_MAX_NAME_LEN];
+
+ char tmp_plugin[2 * DATA_MAX_NAME_LEN + 1];
+ char tmp_type[2 * DATA_MAX_NAME_LEN + 1];
+
+ if (prefix == NULL)
+ prefix = "";
+
+ if (postfix == NULL)
+ postfix = "";
+
+ gr_copy_escape_part (n_host, vl->host,
+ sizeof (n_host), escape_char);
+ gr_copy_escape_part (n_plugin, vl->plugin,
+ sizeof (n_plugin), escape_char);
+ gr_copy_escape_part (n_plugin_instance, vl->plugin_instance,
+ sizeof (n_plugin_instance), escape_char);
+ gr_copy_escape_part (n_type, vl->type,
+ sizeof (n_type), escape_char);
+ gr_copy_escape_part (n_type_instance, vl->type_instance,
+ sizeof (n_type_instance), escape_char);
+
+ if (n_plugin_instance[0] != '\0')
+ ssnprintf (tmp_plugin, sizeof (tmp_plugin), "%s%c%s",
+ n_plugin,
+ '-',
+ n_plugin_instance);
+ else
+ sstrncpy (tmp_plugin, n_plugin, sizeof (tmp_plugin));
+
+ if (n_type_instance[0] != '\0')
+ ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
+ n_type,
+ '-',
+ n_type_instance);
+ else
+ sstrncpy (tmp_type, n_type, sizeof (tmp_type));
+
+ if (ds_name != NULL)
+ ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
+ prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
+ else
+ ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
+ prefix, n_host, postfix, tmp_plugin, tmp_type);
+
+ return (0);
+}
+
+int format_graphite (char *buffer, size_t buffer_size,
+ const data_set_t *ds, const value_list_t *vl, char *prefix,
+ char *postfix, char escape_char,
+ _Bool store_rates)
+{
+ int status = 0;
+ int i;
+ int buffer_pos = 0;
+
+ gauge_t *rates = NULL;
+ if (store_rates)
+ rates = uc_get_rate (ds, vl);
+
+ for (i = 0; i < ds->ds_num; i++)
+ {
+ const char *ds_name = NULL;
+ char key[10*DATA_MAX_NAME_LEN];
+ char values[512];
+ size_t message_len;
+ char message[1024];
+
+ ds_name = ds->ds[i].name;
+
+ /* Copy the identifier to `key' and escape it. */
+ status = gr_format_name (key, sizeof (key), vl, ds_name,
+ prefix, postfix, escape_char);
+ if (status != 0)
+ {
+ ERROR ("format_graphite: error with gr_format_name");
+ sfree (rates);
+ return (status);
+ }
+
+ escape_string (key, sizeof (key));
+ /* Convert the values to an ASCII representation and put that into
+ * `values'. */
+ status = gr_format_values (values, sizeof (values), i, ds, vl, rates);
+ if (status != 0)
+ {
+ ERROR ("format_graphite: error with gr_format_values");
+ sfree (rates);
+ return (status);
+ }
+
+ /* Compute the graphite command */
+ message_len = (size_t) ssnprintf (message, sizeof (message),
+ "%s %s %u\r\n",
+ key,
+ values,
+ (unsigned int) CDTIME_T_TO_TIME_T (vl->time));
+ if (message_len >= sizeof (message)) {
+ ERROR ("format_graphite: message buffer too small: "
+ "Need %zu bytes.", message_len + 1);
+ sfree (rates);
+ return (-ENOMEM);
+ }
+
+ /* Append it in case we got multiple data set */
+ if ((buffer_pos + message_len) >= buffer_size)
+ {
+ ERROR ("format_graphite: target buffer too small");
+ sfree (rates);
+ return (-ENOMEM);
+ }
+ memcpy((void *) (buffer + buffer_pos), message, message_len);
+ buffer_pos += message_len;
+ }
+ sfree (rates);
+ return (status);
+} /* int format_graphite */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/src/utils_format_graphite.h b/src/utils_format_graphite.h
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * collectd - src/utils_format_graphite.h
+ * Copyright (C) 2012 Thomas Meson
+ *
+ * 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:
+ * Thomas Meson <zllak at hycik.org>
+ **/
+
+#ifndef UTILS_FORMAT_GRAPHITE_H
+#define UTILS_FORMAT_GRAPHITE_H 1
+
+#include "collectd.h"
+#include "plugin.h"
+
+int format_graphite (char *buffer,
+ size_t buffer_size, const data_set_t *ds,
+ const value_list_t *vl, const char *prefix,
+ const char *postfix, const char escape_char,
+ _Bool store_rates);
+
+#endif /* UTILS_FORMAT_GRAPHITE_H */
index 2a5526b29d2f77833c1d455a1b3fd10103b9aeb7..bbc3dfdb4efc9b21be341e2e1ff2845c67e5ed33 100644 (file)
--- a/src/utils_format_json.c
+++ b/src/utils_format_json.c
#undef BUFFER_ADD
return (0);
-} /* }}} int buffer_add_string */
+} /* }}} int escape_string */
static int values_to_json (char *buffer, size_t buffer_size, /* {{{ */
const data_set_t *ds, const value_list_t *vl, int store_rates)
} /* }}} int values_to_json */
static int dstypes_to_json (char *buffer, size_t buffer_size, /* {{{ */
- const data_set_t *ds, const value_list_t *vl)
+ const data_set_t *ds)
{
size_t offset = 0;
int i;
} /* }}} int dstypes_to_json */
static int dsnames_to_json (char *buffer, size_t buffer_size, /* {{{ */
- const data_set_t *ds, const value_list_t *vl)
+ const data_set_t *ds)
{
size_t offset = 0;
int i;
return (0);
} /* }}} int dsnames_to_json */
+static int meta_data_to_json (char *buffer, size_t buffer_size, /* {{{ */
+ meta_data_t *meta)
+{
+ size_t offset = 0;
+ char **keys = NULL;
+ int keys_num;
+ int status;
+ int i;
+
+ memset (buffer, 0, buffer_size);
+
+#define BUFFER_ADD(...) do { \
+ status = ssnprintf (buffer + offset, buffer_size - offset, \
+ __VA_ARGS__); \
+ if (status < 1) \
+ return (-1); \
+ else if (((size_t) status) >= (buffer_size - offset)) \
+ return (-ENOMEM); \
+ else \
+ offset += ((size_t) status); \
+} while (0)
+
+ keys_num = meta_data_toc (meta, &keys);
+ for (i = 0; i < keys_num; ++i)
+ {
+ int type;
+ char *key = keys[i];
+
+ type = meta_data_type (meta, key);
+ if (type == MD_TYPE_STRING)
+ {
+ char *value = NULL;
+ if (meta_data_get_string (meta, key, &value) == 0)
+ {
+ char temp[512] = "";
+ escape_string (temp, sizeof (temp), value);
+ sfree (value);
+ BUFFER_ADD (",\"%s\":%s", key, temp);
+ }
+ }
+ else if (type == MD_TYPE_SIGNED_INT)
+ {
+ int64_t value = 0;
+ if (meta_data_get_signed_int (meta, key, &value) == 0)
+ BUFFER_ADD (",\"%s\":%"PRIi64, key, value);
+ }
+ else if (type == MD_TYPE_UNSIGNED_INT)
+ {
+ uint64_t value = 0;
+ if (meta_data_get_unsigned_int (meta, key, &value) == 0)
+ BUFFER_ADD (",\"%s\":%"PRIu64, key, value);
+ }
+ else if (type == MD_TYPE_DOUBLE)
+ {
+ double value = 0.0;
+ if (meta_data_get_double (meta, key, &value) == 0)
+ BUFFER_ADD (",\"%s\":%f", key, value);
+ }
+ else if (type == MD_TYPE_BOOLEAN)
+ {
+ _Bool value = 0;
+ if (meta_data_get_boolean (meta, key, &value) == 0)
+ BUFFER_ADD (",\"%s\":%s", key, value ? "true" : "false");
+ }
+
+ free (key);
+ } /* for (keys) */
+ free (keys);
+
+ if (offset <= 0)
+ return (ENOENT);
+
+ buffer[0] = '{'; /* replace leading ',' */
+ BUFFER_ADD ("}");
+
+#undef BUFFER_ADD
+
+ return (0);
+} /* int meta_data_to_json */
+
static int value_list_to_json (char *buffer, size_t buffer_size, /* {{{ */
const data_set_t *ds, const value_list_t *vl, int store_rates)
{
return (status);
BUFFER_ADD ("\"values\":%s", temp);
- status = dstypes_to_json (temp, sizeof (temp), ds, vl);
+ status = dstypes_to_json (temp, sizeof (temp), ds);
if (status != 0)
return (status);
BUFFER_ADD (",\"dstypes\":%s", temp);
- status = dsnames_to_json (temp, sizeof (temp), ds, vl);
+ status = dsnames_to_json (temp, sizeof (temp), ds);
if (status != 0)
return (status);
BUFFER_ADD (",\"dsnames\":%s", temp);
BUFFER_ADD_KEYVAL ("type", vl->type);
BUFFER_ADD_KEYVAL ("type_instance", vl->type_instance);
+ if (vl->meta != NULL)
+ {
+ char meta_buffer[buffer_size];
+ memset (meta_buffer, 0, sizeof (meta_buffer));
+ status = meta_data_to_json (meta_buffer, sizeof (meta_buffer), vl->meta);
+ if (status != 0)
+ return (status);
+
+ BUFFER_ADD (",\"meta\":%s", meta_buffer);
+ } /* if (vl->meta != NULL) */
+
BUFFER_ADD ("}");
#undef BUFFER_ADD_KEYVAL
diff --git a/src/utils_rrdcreate.c b/src/utils_rrdcreate.c
index 91ac6ce548e878b4078e17d89cc7ce609995ee51..091b5fa6dce1d2cc3bc48bb093298f39e5d0af46 100644 (file)
--- a/src/utils_rrdcreate.c
+++ b/src/utils_rrdcreate.c
argv[ds_num + rra_num] = NULL;
last_up = CDTIME_T_TO_TIME_T (vl->time);
- if (last_up <= 10)
+ if (last_up <= 0)
last_up = time (NULL);
- last_up -= 10;
+ last_up -= 1;
if (cfg->stepsize > 0)
stepsize = cfg->stepsize;
diff --git a/src/varnish.c b/src/varnish.c
index 357b5f11d0033d7f7efd1384e7ce666ba2bf3a70..de60e39c7b21759f0fdefb062d3d74475df90fed 100644 (file)
--- a/src/varnish.c
+++ b/src/varnish.c
vd = VSM_New();
VSC_Setup(vd);
+ if (VSM_n_Arg(vd, conf->instance) == -1)
+ {
+ ERROR ("Varnish plugin : unable to load statistics from instance");
+ return (-1);
+ }
if (VSC_Open (vd, /* diag = */ 1))
{
ERROR ("varnish plugin: Unable to load statistics.");
diff --git a/src/write_graphite.c b/src/write_graphite.c
index d6583a75f04ebb63901649a6f6f763ae3a9aa473..2ae30efe2ca179b0fd13cfafe5914f5a031b14ff 100644 (file)
--- a/src/write_graphite.c
+++ b/src/write_graphite.c
#include "utils_cache.h"
#include "utils_parse_option.h"
+#include "utils_format_graphite.h"
/* Folks without pthread will need to disable this plugin. */
#include <pthread.h>
return (status);
}
-static int wg_format_values (char *ret, size_t ret_len,
- int ds_num, const data_set_t *ds, const value_list_t *vl,
- _Bool store_rates)
-{
- size_t offset = 0;
- int status;
- gauge_t *rates = NULL;
-
- assert (0 == strcmp (ds->type, vl->type));
-
- memset (ret, 0, ret_len);
-
-#define BUFFER_ADD(...) do { \
- status = ssnprintf (ret + offset, ret_len - offset, \
- __VA_ARGS__); \
- if (status < 1) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else if (((size_t) status) >= (ret_len - offset)) \
- { \
- sfree (rates); \
- return (-1); \
- } \
- else \
- offset += ((size_t) status); \
-} while (0)
-
- if (ds->ds[ds_num].type == DS_TYPE_GAUGE)
- BUFFER_ADD ("%f", vl->values[ds_num].gauge);
- else if (store_rates)
- {
- if (rates == NULL)
- rates = uc_get_rate (ds, vl);
- if (rates == NULL)
- {
- WARNING ("format_values: "
- "uc_get_rate failed.");
- return (-1);
- }
- BUFFER_ADD ("%g", rates[ds_num]);
- }
- else if (ds->ds[ds_num].type == DS_TYPE_COUNTER)
- BUFFER_ADD ("%llu", vl->values[ds_num].counter);
- else if (ds->ds[ds_num].type == DS_TYPE_DERIVE)
- BUFFER_ADD ("%"PRIi64, vl->values[ds_num].derive);
- else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
- BUFFER_ADD ("%"PRIu64, vl->values[ds_num].absolute);
- else
- {
- ERROR ("format_values plugin: Unknown data source type: %i",
- ds->ds[ds_num].type);
- sfree (rates);
- return (-1);
- }
-
-#undef BUFFER_ADD
-
- sfree (rates);
- return (0);
-}
-
-static void wg_copy_escape_part (char *dst, const char *src, size_t dst_len,
- char escape_char)
-{
- size_t i;
-
- memset (dst, 0, dst_len);
-
- if (src == NULL)
- return;
-
- for (i = 0; i < dst_len; i++)
- {
- if (src[i] == 0)
- {
- dst[i] = 0;
- break;
- }
-
- if ((src[i] == '.')
- || isspace ((int) src[i])
- || iscntrl ((int) src[i]))
- dst[i] = escape_char;
- else
- dst[i] = src[i];
- }
-}
-
-static int wg_format_name (char *ret, int ret_len,
- const value_list_t *vl,
- const struct wg_callback *cb,
- const char *ds_name)
-{
- char n_host[DATA_MAX_NAME_LEN];
- char n_plugin[DATA_MAX_NAME_LEN];
- char n_plugin_instance[DATA_MAX_NAME_LEN];
- char n_type[DATA_MAX_NAME_LEN];
- char n_type_instance[DATA_MAX_NAME_LEN];
-
- char *prefix;
- char *postfix;
-
- char tmp_plugin[2 * DATA_MAX_NAME_LEN + 1];
- char tmp_type[2 * DATA_MAX_NAME_LEN + 1];
-
- prefix = cb->prefix;
- if (prefix == NULL)
- prefix = "";
-
- postfix = cb->postfix;
- if (postfix == NULL)
- postfix = "";
-
- wg_copy_escape_part (n_host, vl->host,
- sizeof (n_host), cb->escape_char);
- wg_copy_escape_part (n_plugin, vl->plugin,
- sizeof (n_plugin), cb->escape_char);
- wg_copy_escape_part (n_plugin_instance, vl->plugin_instance,
- sizeof (n_plugin_instance), cb->escape_char);
- wg_copy_escape_part (n_type, vl->type,
- sizeof (n_type), cb->escape_char);
- wg_copy_escape_part (n_type_instance, vl->type_instance,
- sizeof (n_type_instance), cb->escape_char);
-
- if (n_plugin_instance[0] != '\0')
- ssnprintf (tmp_plugin, sizeof (tmp_plugin), "%s%c%s",
- n_plugin,
- cb->separate_instances ? '.' : '-',
- n_plugin_instance);
- else
- sstrncpy (tmp_plugin, n_plugin, sizeof (tmp_plugin));
-
- if (n_type_instance[0] != '\0')
- ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
- n_type,
- cb->separate_instances ? '.' : '-',
- n_type_instance);
- else
- sstrncpy (tmp_type, n_type, sizeof (tmp_type));
-
- if (ds_name != NULL)
- ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
- prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
- else
- ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
- prefix, n_host, postfix, tmp_plugin, tmp_type);
-
- return (0);
-}
-
-static int wg_send_message (const char* key, const char* value,
- cdtime_t time, struct wg_callback *cb)
+static int wg_send_message (char const *message, struct wg_callback *cb)
{
int status;
size_t message_len;
- char message[1024];
-
- message_len = (size_t) ssnprintf (message, sizeof (message),
- "%s %s %u\r\n",
- key,
- value,
- (unsigned int) CDTIME_T_TO_TIME_T (time));
- if (message_len >= sizeof (message)) {
- ERROR ("write_graphite plugin: message buffer too small: "
- "Need %zu bytes.", message_len + 1);
- return (-1);
- }
+
+ message_len = strlen (message);
pthread_mutex_lock (&cb->send_lock);
static int wg_write_messages (const data_set_t *ds, const value_list_t *vl,
struct wg_callback *cb)
{
- char key[10*DATA_MAX_NAME_LEN];
- char values[512];
-
- int status, i;
+ char buffer[4096];
+ int status;
if (0 != strcmp (ds->type, vl->type))
{
return -1;
}
- for (i = 0; i < ds->ds_num; i++)
- {
- const char *ds_name = NULL;
-
- if (cb->always_append_ds || (ds->ds_num > 1))
- ds_name = ds->ds[i].name;
-
- /* Copy the identifier to `key' and escape it. */
- status = wg_format_name (key, sizeof (key), vl, cb, ds_name);
- if (status != 0)
- {
- ERROR ("write_graphite plugin: error with format_name");
- return (status);
- }
-
- escape_string (key, sizeof (key));
- /* Convert the values to an ASCII representation and put that into
- * `values'. */
- status = wg_format_values (values, sizeof (values), i, ds, vl,
- cb->store_rates);
- if (status != 0)
- {
- ERROR ("write_graphite plugin: error with "
- "wg_format_values");
- return (status);
- }
+ memset (buffer, 0, sizeof (buffer));
+ status = format_graphite (buffer, sizeof (buffer), ds, vl,
+ cb->prefix, cb->postfix, cb->escape_char, cb->store_rates);
+ if (status != 0) /* error message has been printed already. */
+ return (status);
- /* Send the message to graphite */
- status = wg_send_message (key, values, vl->time, cb);
- if (status != 0)
- {
- ERROR ("write_graphite plugin: error with "
- "wg_send_message");
- return (status);
- }
+ wg_send_message (buffer, cb);
+ if (status != 0)
+ {
+ ERROR ("write_graphite plugin: wg_send_message failed "
+ "with status %i.", status);
+ return (status);
}
return (0);
-}
+} /* int wg_write_messages */
static int wg_write (const data_set_t *ds, const value_list_t *vl,
user_data_t *user_data)
diff --git a/src/write_mongodb.c b/src/write_mongodb.c
index 8d76b608affa4c58d1a3c23cfbeda4f16cc8f5bc..c7b768205cdf2ca59e0938b8b5a955d3deb0e78a 100644 (file)
--- a/src/write_mongodb.c
+++ b/src/write_mongodb.c
/* Assert if the connection has been established */
assert (mongo_is_connected (node->conn));
- status = mongo_insert (node->conn, collection_name, bson_record);
+ #if MONGO_MINOR >= 6
+ /* There was an API change in 0.6.0 as linked below */
+ /* https://github.com/mongodb/mongo-c-driver/blob/master/HISTORY.md */
+ status = mongo_insert (node->conn, collection_name, bson_record, NULL);
+ #else
+ status = mongo_insert (node->conn, collection_name, bson_record);
+ #endif
+
if(status != MONGO_OK)
{
ERROR ( "write_mongodb plugin: error inserting record: %d", node->conn->err);
diff --git a/src/zfs_arc.c b/src/zfs_arc.c
index e77569f5d0996c6e7f94b53eac51ece91d02805a..046b7b02120953c65d66de9c27dd2ff5ac482e8c 100644 (file)
--- a/src/zfs_arc.c
+++ b/src/zfs_arc.c
/*
* Global variables
*/
-static kstat_t *ksp;
+
extern kstat_ctl_t *kc;
static void za_submit (const char* type, const char* type_instance, value_t* values, int values_len)
long long tmp;
value_t v;
- tmp = get_kstat_value (ksp, kstat_value);
+ tmp = get_kstat_value (ksp, (char *)kstat_value);
if (tmp == -1LL)
{
ERROR ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
v.derive = (derive_t) tmp;
za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
+ return (0);
}
static int za_read_gauge (kstat_t *ksp, const char *kstat_value,
long long tmp;
value_t v;
- tmp = get_kstat_value (ksp, kstat_value);
+ tmp = get_kstat_value (ksp, (char *)kstat_value);
if (tmp == -1LL)
{
ERROR ("zfs_arc plugin: Reading kstat value \"%s\" failed.", kstat_value);
v.gauge = (gauge_t) tmp;
za_submit (type, type_instance, /* values = */ &v, /* values_num = */ 1);
+ return (0);
}
static void za_submit_ratio (const char* type_instance, gauge_t hits, gauge_t misses)
{
gauge_t arc_hits, arc_misses, l2_hits, l2_misses;
value_t l2_io[2];
+ kstat_t *ksp = NULL;
get_kstat (&ksp, "zfs", 0, "arcstats");
if (ksp == NULL)
static int za_init (void) /* {{{ */
{
- ksp = NULL;
-
/* kstats chain already opened by update_kstat (using *kc), verify everything went fine. */
if (kc == NULL)
{
diff --git a/version-gen.sh b/version-gen.sh
index 97a27a0d75f6bf3adb19cafe27622503eda72c21..d6d7bb202ba41f39a806fa6ca22ec9cb22b70961 100755 (executable)
--- a/version-gen.sh
+++ b/version-gen.sh
VERSION="`echo \"$VERSION\" | sed -e 's/-/./g'`"
-if test "x`uname -s`" = "xAIX" ; then
- echo "$VERSION\c"
-else
- echo -n "$VERSION"
-fi
+echo -n "$VERSION"