author | Florian Forster <octo@collectd.org> | |
Wed, 7 Aug 2013 06:39:28 +0000 (08:39 +0200) | ||
committer | Florian Forster <octo@collectd.org> | |
Wed, 7 Aug 2013 06:39:28 +0000 (08:39 +0200) |
44 files changed:
index 36f70e788908e8963bbb69b40c7d48280312ef31..adb74813b3559cfbf3f677a05fe77ef195432ff2 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
Jason Pepas <cell at ices.utexas.edu>
- nfs plugin.
+J. Javier Maestro <jjmaestro at ieee.org>
+ - Write-Graphite plugin: UDP support and LogSendErrors flag.
+
Jérôme Renard <jerome.renard at gmail.com>
- varnish plugin.
index 04e87abfb5edc5a15b5e311c8d8d53ab72028149..3f65963ae353a7e4dc3294acb27801025f895f94 100644 (file)
--- a/README
+++ b/README
done.
- write_graphite
- Sends data to Carbon, the storage layer of Graphite.
+ Sends data to Carbon, the storage layer of Graphite using TCP or UDP. It
+ can be configured to avoid logging send errors (especially useful when
+ using UDP).
- write_http
Sends the values collected by collectd to a web-server using HTTP POST
diff --git a/configure.in b/configure.in
index 3701d8ade781a62e988796d38bf9c81b3f1eeab4..dbdc0589a0fee67ca9566f43c07ecb40012c3ae2 100644 (file)
--- a/configure.in
+++ b/configure.in
AM_CONDITIONAL(BUILD_WITH_LM_SENSORS, test "x$with_libsensors" = "xyes")
# }}}
+# --with-libsigrok {{{
+with_libsigrok_cflags=""
+with_libsigrok_ldflags=""
+AC_ARG_WITH(libsigrok, [AS_HELP_STRING([--with-libsigrok@<:@=PREFIX@:>@], [Path to libsigrok.])],
+[
+ if test "x$withval" = "xno"
+ then
+ with_libsigrok="no"
+ else
+ with_libsigrok="yes"
+ if test "x$withval" != "xyes"
+ then
+ with_libsigrok_cflags="-I$withval/include"
+ with_libsigrok_ldflags="-L$withval/lib"
+ fi
+ fi
+],[])
+
+# libsigrok has a glib dependency
+if test "x$with_libsigrok" = "xyes"
+then
+ if test -z "m4_ifdef([AM_PATH_GLIB_2_0], [yes], [])"
+ then
+ with_libsigrok="no (glib not available)"
+ else
+ AM_PATH_GLIB_2_0([2.28.0],
+ [with_libsigrok_cflags="$with_libsigrok_cflags $GLIB_CFLAGS"; with_libsigrok_ldflags="$with_libsigrok_ldflags $GLIB_LIBS"])
+ fi
+fi
+
+# libsigrok headers
+if test "x$with_libsigrok" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libsigrok_cflags"
+
+ AC_CHECK_HEADERS(libsigrok/libsigrok.h, [], [with_libsigrok="no (libsigrok/libsigrok.h not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+
+# libsigrok library
+if test "x$with_libsigrok" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ SAVE_LDFLAGS="$LDFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libsigrok_cflags"
+ LDFLAGS="$LDFLAGS $with_libsigrok_ldflags"
+
+ AC_CHECK_LIB(sigrok, sr_init,
+ [
+ AC_DEFINE(HAVE_LIBSIGROK, 1, [Define to 1 if you have the sigrok library (-lsigrok).])
+ ],
+ [with_libsigrok="no (libsigrok not found)"])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+ LDFLAGS="$SAVE_LDFLAGS"
+fi
+if test "x$with_libsigrok" = "xyes"
+then
+ BUILD_WITH_LIBSIGROK_CFLAGS="$with_libsigrok_cflags"
+ BUILD_WITH_LIBSIGROK_LDFLAGS="$with_libsigrok_ldflags"
+ AC_SUBST(BUILD_WITH_LIBSIGROK_CFLAGS)
+ AC_SUBST(BUILD_WITH_LIBSIGROK_LDFLAGS)
+fi
+AM_CONDITIONAL(BUILD_WITH_LIBSIGROK, test "x$with_libsigrok" = "xyes")
+# }}}
+
# --with-libstatgrab {{{
with_libstatgrab_cflags=""
with_libstatgrab_ldflags=""
AC_PLUGIN([rrdtool], [$with_librrd], [RRDTool output plugin])
AC_PLUGIN([sensors], [$with_libsensors], [lm_sensors statistics])
AC_PLUGIN([serial], [$plugin_serial], [serial port traffic])
+AC_PLUGIN([sigrok], [$with_libsigrok], [sigrok acquisition sources])
AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugin])
AC_PLUGIN([statsd], [yes], [StatsD plugin])
AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics])
librouteros . . . . . $with_librouteros
librrd . . . . . . . $with_librrd
libsensors . . . . . $with_libsensors
+ libsigrok . . . . . $with_libsigrok
libstatgrab . . . . . $with_libstatgrab
libtokyotyrant . . . $with_libtokyotyrant
libupsclient . . . . $with_libupsclient
rrdtool . . . . . . . $enable_rrdtool
sensors . . . . . . . $enable_sensors
serial . . . . . . . $enable_serial
+ sigrok . . . . . . . $enable_sigrok
snmp . . . . . . . . $enable_snmp
statsd . . . . . . . $enable_statsd
swap . . . . . . . . $enable_swap
index 9af0fb008a72790e48562e7e6440c3bec8c6dd2a..809f19dee65d2ec89a030a762bacb5e98041d8aa 100644 (file)
"""
import socket,struct,sys
-try:
- from io import StringIO
-except ImportError:
- from cStringIO import StringIO
+import platform
+if platform.python_version() < '2.8.0':
+ # Python 2.7 and below io.StringIO does not like unicode
+ from StringIO import StringIO
+else:
+ try:
+ from io import StringIO
+ except ImportError:
+ from cStringIO import StringIO
from datetime import datetime
from copy import deepcopy
assert double.size == number.size
result = []
- for dstype in buf[header.size+short.size:off]:
+ for dstype in [ord(x) for x in buf[header.size+short.size:off]]:
if dstype == DS_TYPE_COUNTER:
result.append((dstype, number.unpack_from(buf, off)[0]))
off += valskip
index fb44bb4fe82bdc7f68cfc53a8263e8c260208b93..00c5519b7a211cdfde7f283aa528805020f93dc3 100644 (file)
WHEN type_inst IS NOT NULL THEN '-'
ELSE ''
END
- || coalesce(plugin_inst, '') AS identifier,
+ || coalesce(type_inst, '') AS identifier,
tstamp, name, value
FROM identifiers
JOIN values
diff --git a/src/Makefile.am b/src/Makefile.am
index 9f16fd7cb7edb7486f7d4e06965a6b98bf389c31..f35b45a35c335cc6302df127f6f87a0891c5cacd 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
collectd_DEPENDENCIES += serial.la
endif
+if BUILD_PLUGIN_SIGROK
+pkglib_LTLIBRARIES += sigrok.la
+sigrok_la_SOURCES = sigrok.c
+sigrok_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBSIGROK_CFLAGS)
+sigrok_la_LDFLAGS = -module -avoid-version $(BUILD_WITH_LIBSIGROK_LDFLAGS)
+sigrok_la_LIBADD = -lsigrok
+collectd_LDADD += "-dlopen" sigrok.la
+collectd_DEPENDENCIES += sigrok.la
+endif
+
if BUILD_PLUGIN_SNMP
pkglib_LTLIBRARIES += snmp.la
snmp_la_SOURCES = snmp.c
diff --git a/src/collectd-email.pod b/src/collectd-email.pod
index e19d13ec21e8ddc7c087835a3aa05ee7105de711..6f58542784d51a206c685eedee1eed488cd3b101 100644 (file)
--- a/src/collectd-email.pod
+++ b/src/collectd-email.pod
+=encoding UTF-8
+
=head1 NAME
collectd-email - Documentation of collectd's C<email plugin>
diff --git a/src/collectd-exec.pod b/src/collectd-exec.pod
index 10f68290e9bbc8ae8c7479364068f0b3ccae5b30..2c5963025a4269687307cf9e5c1f3d43cae70e47 100644 (file)
--- a/src/collectd-exec.pod
+++ b/src/collectd-exec.pod
+=encoding UTF-8
+
=head1 NAME
collectd-exec - Documentation of collectd's C<exec plugin>
Since examples usually let one understand a lot better, here are some:
- leeloo/cpu-0/cpu-idle N:2299366
- alice/interface/if_octets-eth0 interval=10 1180647081:421465:479194
-
-Since this action was the only one supported with older versions of the C<exec
-plugin> all lines were treated as if they were prefixed with B<PUTVAL>. This is
-still the case to maintain backwards compatibility but deprecated.
+ PUTVAL leeloo/cpu-0/cpu-idle N:2299366
+ PUTVAL alice/interface/if_octets-eth0 interval=10 1180647081:421465:479194
=item B<PUTNOTIF> [I<OptionList>] B<message=>I<Message>
diff --git a/src/collectd-java.pod b/src/collectd-java.pod
index 9e2f81aa9b9f0056d3aefa215605688b47f8ae81..00f209a56b7d69e3f35757f86876e194321dbab0 100644 (file)
--- a/src/collectd-java.pod
+++ b/src/collectd-java.pod
+=encoding UTF-8
+
=head1 NAME
collectd-java - Documentation of collectd's "java plugin"
index d7c749cd3391aefc86369c208193063111655fe6..aab753c56539d8c2a9bcb5b2196a9b8ae6c5dfd7 100644 (file)
--- a/src/collectd-nagios.pod
+++ b/src/collectd-nagios.pod
+=encoding UTF-8
+
=head1 NAME
collectd-nagios - Nagios plugin for querying collectd
diff --git a/src/collectd-perl.pod b/src/collectd-perl.pod
index ee05e002d4fea57996ed5cf6543c38d166a35c13..669e3f415ef26ef6b196d4e2a15d22127fdf8c78 100644 (file)
--- a/src/collectd-perl.pod
+++ b/src/collectd-perl.pod
+=encoding UTF-8
+
=head1 NAME
collectd-perl - Documentation of collectd's C<perl plugin>
index 39503ad0ba15dfb89ceaf66606ab3afeca442328..426a7118c99b8346d38e1d659ff2f4142090c594 100644 (file)
--- a/src/collectd-python.pod
+++ b/src/collectd-python.pod
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
+=encoding UTF-8
+
=head1 NAME
collectd-python - Documentation of collectd's C<python plugin>
diff --git a/src/collectd-snmp.pod b/src/collectd-snmp.pod
index 3c6e79970dacff29c556c423899b480ca1d85bf8..fd7a50896486211c3fac9b0ef6d10304738dcb4c 100644 (file)
--- a/src/collectd-snmp.pod
+++ b/src/collectd-snmp.pod
+=encoding UTF-8
+
=head1 NAME
collectd-snmp - Documentation of collectd's C<snmp plugin>
diff --git a/src/collectd-tg.pod b/src/collectd-tg.pod
index 5f1b630d53704993486ea25ffbe547bac6cbcb35..97112e7b6bae1e7b15475f803228ed69004632b3 100644 (file)
--- a/src/collectd-tg.pod
+++ b/src/collectd-tg.pod
+=encoding UTF-8
+
=head1 NAME
collectd-tg - Traffic generator for collectd.
index 02e41b8b83e90cc34d60faa263f558f7a54dbc89..35f8a9fcdd231a9ed4f5e8ca4086305016b83845 100644 (file)
+=encoding UTF-8
+
=head1 NAME
collectd-threshold - Documentation of collectd's I<Threshold plugin>
=item B<Interesting> B<true>|B<false>
-If set to B<true> (the default), the threshold must be treated as interesting
-and, when a number of B<Timeout> values will lost, then a missing notification
-will be dispatched. On the other hand, if set to B<false>, the missing
-notification will never dispatched for this threshold.
+If set to B<true> (the default), a notification with severity C<FAILURE> will
+be created when a matching value list is no longer updated and purged from the
+internal cache. When this happens depends on the I<interval> of the value list
+and the global B<Timeout> setting. See the B<Interval> and B<Timeout> settings
+in L<collectd.conf(5)> for details. If set to B<false>, this event will be
+ignored.
=back
index 83802a14f7a0ba2576c94f0b223b1ddc07b54f67..40626d3739db266d3f10043485cbf45fd1e7b27f 100644 (file)
+=encoding UTF-8
+
=head1 NAME
collectd-unixsock - Documentation of collectd's C<unixsock plugin>
diff --git a/src/collectd.conf.in b/src/collectd.conf.in
index c5ab3ce83a31ab4e063b3ff63fcaf6ccc1dea409..e8d4d28ef026c1c09546cdc0d143de52a19bbed5 100644 (file)
--- a/src/collectd.conf.in
+++ b/src/collectd.conf.in
#ReadThreads 5
#WriteThreads 5
+# Limit the size of the write queue. Default is no limit. Setting up a limit is
+# recommended for servers handling a high volume of traffic.
+#WriteQueueLimitHigh 1000000
+#WriteQueueLimitLow 800000
+
##############################################################################
# Logging #
#----------------------------------------------------------------------------#
@LOAD_PLUGIN_RRDTOOL@LoadPlugin rrdtool
#@BUILD_PLUGIN_SENSORS_TRUE@LoadPlugin sensors
#@BUILD_PLUGIN_SERIAL_TRUE@LoadPlugin serial
+#@BUILD_PLUGIN_SIGROK_TRUE@LoadPlugin sigrok
#@BUILD_PLUGIN_SNMP_TRUE@LoadPlugin snmp
#@BUILD_PLUGIN_STATSD_TRUE@LoadPlugin statsd
#@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap
# IgnoreSelected false
#</Plugin>
+#<Plugin sigrok>
+# LogLevel 3
+# <Device "AC Voltage">
+# Driver "fluke-dmm"
+# MinimumInterval 10
+# Conn "/dev/ttyUSB2"
+# </Device>
+# <Device "Sound Level">
+# Driver "cem-dt-885x"
+# Conn "/dev/ttyUSB1"
+# </Device>
+#</Plugin>
+
#<Plugin snmp>
# <Data "powerplus_voltge_input">
# Type "voltage"
# <Node "example">
# Host "localhost"
# Port "2003"
+# Protocol "udp"
+# LogSendErrors true
# Prefix "collectd"
# Postfix "collectd"
# StoreRates true
diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod
index 4a34fe5df3780ad76bb945be0a0ed1c926a883e7..1b73c417d9ebfc54211eefc252116d733a0b9c96 100644 (file)
--- a/src/collectd.conf.pod
+++ b/src/collectd.conf.pod
+=encoding UTF-8
+
=head1 NAME
collectd.conf - Configuration for the system statistics collection daemon B<collectd>
Include "/etc/collectd.d/*.conf"
+Starting with version 5.3, this may also be a block in which further options
+affecting the behavior of B<Include> may be specified. The following option is
+currently allowed:
+
+ <Include "/etc/collectd.d">
+ Filter "*.conf"
+ </Include>
+
+=over 4
+
+=item B<Filter> I<pattern>
+
If the C<fnmatch> function is available on your system, a shell-like wildcard
I<pattern> may be specified to filter which files to include. This may be used
in combination with recursively including a directory to easily be able to
arbitrarily mix configuration files and other documents (e.g. README files).
-The following statement is similar to the example above but includes all files
+The given example is similar to the first example above but includes all files
matching C<*.conf> in any subdirectory of C</etc/collectd.d>:
Include "/etc/collectd.d" "*.conf"
+=back
+
If more than one files are included by a single B<Include> option, the files
will be included in lexicographical order (as defined by the C<strcmp>
function). Thus, you can e.E<nbsp>g. use numbered prefixes to specify the
default value is B<5>, but you may want to increase this if you have more than
five plugins that may take relatively long to write to.
+=item B<WriteQueueLimitHigh> I<HighNum>
+
+=item B<WriteQueueLimitLow> I<LowNum>
+
+Metrics are read by the I<read threads> and then put into a queue to be handled
+by the I<write threads>. If one of the I<write plugins> is slow (e.g. network
+timeouts, I/O saturation of the disk) this queue will grow. In order to avoid
+running into memory issues in such a case, you can limit the size of this
+queue.
+
+By default, there is no limit and memory may grow indefinitely. This is most
+likely not an issue for clients, i.e. instances that only handle the local
+metrics. For servers it is recommended to set this to a non-zero value, though.
+
+You can set the limits using B<WriteQueueLimitHigh> and B<WriteQueueLimitLow>.
+Each of them takes a numerical argument which is the number of metrics in the
+queue. If there are I<HighNum> metrics in the queue, any new metrics I<will> be
+dropped. If there are less than I<LowNum> metrics in the queue, all new metrics
+I<will> be enqueued. If the number of metrics currently in the queue is between
+I<LowNum> and I<HighNum>, the metric is dropped with a probability that is
+proportional to the number of metrics in the queue (i.e. it increases linearly
+until it reaches 100%.)
+
+If B<WriteQueueLimitHigh> is set to non-zero and B<WriteQueueLimitLow> is
+unset, the latter will default to half of B<WriteQueueLimitHigh>.
+
+If you do not want to randomly drop values when the queue size is between
+I<LowNum> and I<HighNum>, set If B<WriteQueueLimitHigh> and
+B<WriteQueueLimitLow> to same value.
+
=item B<Hostname> I<Name>
Sets the hostname that identifies a host. If you omit this setting, the
many small files are stored on the disk. This is a usual scenario for mail
transfer agents and web caches.
-=item B<ReportPercentage> B<false>|B<true>
+=item B<ValuesAbsolute> B<true>|B<false>
-Enables or disables reporting of disk space and inodes as a percentage.
-Defaults to B<false>.
+Enables or disables reporting of free, used and used disk space in 1K-blocks.
+Defaults to true.
-This is useful for deploying I<collectd> on the cloud, where machines with
-different disk size may exist. Then it is more practical to configure
-thresholds based on relative disk size.
+=item B<ValuesPercentage> B<true>|B<false>
+
+Enables or disables reporting of free, used and used disk space in percentage.
+Defaults to false.
+
+This is useful for deploying collectd on the cloud, where machines with
+different disk size may exist. Then it is more practical to configure thresholds
+based on relative disk size.
=back
=back
+=head2 Plugin C<sigrok>
+
+The I<sigrok plugin> uses I<libsigrok> to retrieve measurements from any device
+supported by the L<sigrok|http://sigrok.org/> project.
+
+B<Synopsis>
+
+ <Plugin sigrok>
+ LogLevel 3
+ <Device "AC Voltage">
+ Driver "fluke-dmm"
+ MinimumInterval 10
+ Conn "/dev/ttyUSB2"
+ </Device>
+ <Device "Sound Level">
+ Driver "cem-dt-885x"
+ Conn "/dev/ttyUSB1"
+ </Device>
+ </Plugin>
+
+=over 4
+
+=item B<LogLevel> B<0-5>
+
+The I<sigrok> logging level to pass on to the I<collectd> log, as a number
+between B<0> and B<5> (inclusive). These levels correspond to C<None>,
+C<Errors>, C<Warnings>, C<Informational>, C<Debug >and C<Spew>, respectively.
+The default is B<2> (C<Warnings>). The I<sigrok> log messages, regardless of
+their level, are always submitted to I<collectd> at its INFO log level.
+
+=item E<lt>B<Device> I<Name>E<gt>
+
+A sigrok-supported device, uniquely identified by this section's options. The
+I<Name> is passed to I<collectd> as the I<plugin instance>.
+
+=item B<Driver> I<DriverName>
+
+The sigrok driver to use for this device.
+
+=item B<Conn> I<ConnectionSpec>
+
+If the device cannot be auto-discovered, or more than one might be discovered
+by the driver, I<ConnectionSpec> specifies the connection string to the device.
+It can be of the form of a device path (e.g.E<nbsp>C</dev/ttyUSB2>), or, in
+case of a non-serial USB-connected device, the USB I<VendorID>B<.>I<ProductID>
+separated by a period (e.g.E<nbsp>C<0403.6001>). A USB device can also be
+specified as I<Bus>B<.>I<Address> (e.g.E<nbsp>C<1.41>).
+
+=item B<SerialComm> I<SerialSpec>
+
+For serial devices with non-standard port settings, this option can be used
+to specify them in a form understood by I<sigrok>, e.g.E<nbsp>C<9600/8n1>.
+This should not be necessary; drivers know how to communicate with devices they
+support.
+
+=item B<MinimumInterval> I<Seconds>
+
+Specifies the minimum time between measurement dispatches to I<collectd>, in
+seconds. Since some I<sigrok> supported devices can acquire measurements many
+times per second, it may be necessary to throttle these. For example, the
+I<RRD plugin> cannot process writes more than once per second.
+
+The default B<MinimumInterval> is B<0>, meaning measurements received from the
+device are always dispatched to I<collectd>. When throttled, unused
+measurements are discarded.
+
+=back
+
=head2 Plugin C<snmp>
Since the configuration of the C<snmp plugin> is a little more complicated than
=head2 Plugin C<varnish>
-The Varnish plugin collects information about Varnish, an HTTP accelerator.
+The I<varnish plugin> collects information about Varnish, an HTTP accelerator.
+
+Synopsis:
+
+ <Plugin "varnish">
+ <Instance "example">
+ CollectCache true
+ CollectConnections true
+ CollectBackend true
+ CollectSHM true
+ CollectESI false
+ CollectFetch false
+ CollectHCB false
+ CollectSMA false
+ CollectSMS false
+ CollectSM false
+ CollectTotals false
+ CollectWorkers false
+ </Instance>
+ </Plugin>
+
+The configuration consists of one or more E<lt>B<Instance>E<nbsp>I<Name>E<gt>
+blocks. I<Name> is the parameter passed to "varnishd -n". If left empty, it
+will collectd statistics from the default "varnishd" instance (this should work
+fine in most cases).
+
+Inside each E<lt>B<Instance>E<gt> blocks, the following options are recognized:
=over 4
The C<write_graphite> plugin writes data to I<Graphite>, an open-source metrics
storage and graphing project. The plugin connects to I<Carbon>, the data layer
-of I<Graphite>, and sends data via the "line based" protocol (per default using
-portE<nbsp>2003). The data will be sent in blocks of at most 1428 bytes to
-minimize the number of network packets.
+of I<Graphite>, via I<TCP> or I<UDP> and sends data via the "line based"
+protocol (per default using portE<nbsp>2003). The data will be sent in blocks
+of at most 1428 bytes to minimize the number of network packets.
Synopsis:
<Node "example">
Host "localhost"
Port "2003"
+ Protocol "udp"
+ LogSendErrors true
Prefix "collectd"
</Node>
</Plugin>
Service name or port number to connect to. Defaults to C<2003>.
+=item B<Protocol> I<String>
+
+Protocol to use when connecting to I<Graphite>. Defaults to C<tcp>.
+
+=item B<LogSendErrors> B<false>|B<true>
+
+If set to B<true> (the default), logs errors when sending data to I<Graphite>.
+If set to B<false>, it will not log the errors. This is especially useful when
+using Protocol UDP since many times we want to use the "fire-and-forget"
+approach and logging errors fills syslog with unneeded messages.
+
=item B<Prefix> I<String>
When set, I<String> is added in front of the host name. Dots and whitespace are
diff --git a/src/collectd.pod b/src/collectd.pod
index e36dcdf3eb0c9ebe031970da77cf86d777a36059..2f7b9f707439c795fcf85acfaede29ec39821a2e 100644 (file)
--- a/src/collectd.pod
+++ b/src/collectd.pod
+=encoding UTF-8
+
=head1 NAME
collectd - System statistics collection daemon
diff --git a/src/collectdctl.pod b/src/collectdctl.pod
index 21c0b500c37d36c55b7d90a97674206a8065f876..52b8ef23d625a956bc11ce7dd7e256a9ac1a6a91 100644 (file)
--- a/src/collectdctl.pod
+++ b/src/collectdctl.pod
+=encoding UTF-8
+
=head1 NAME
collectdctl - Control interface for collectd
diff --git a/src/collectdmon.pod b/src/collectdmon.pod
index 73ba6b8c166b98b22c4b2204739dd1d4167d1f3d..3151e1104c9e73b6f251de329a93cb258480cd4c 100644 (file)
--- a/src/collectdmon.pod
+++ b/src/collectdmon.pod
+=encoding UTF-8
+
=head1 NAME
collectdmon - Monitoring daemon for collectd
diff --git a/src/common.c b/src/common.c
index d963efa556a6f60ce6f71c3472f90e791dc48c4e..161b4d67fc063d693b1f319e016687cea4ae639d 100644 (file)
--- a/src/common.c
+++ b/src/common.c
retval = (long long) kn->value.ui64; /* XXX: Might overflow! */
else
WARNING ("get_kstat_value: Not a numeric value: %s", name);
-
+
return (retval);
}
#endif /* HAVE_LIBKSTAT */
const char *plugin, const char *plugin_instance,
const char *type, const char *type_instance)
{
- int status;
+ char *buffer;
+ size_t buffer_size;
+
+ buffer = ret;
+ buffer_size = (size_t) ret_len;
+
+#define APPEND(str) do { \
+ size_t l = strlen (str); \
+ if (l >= buffer_size) \
+ return (ENOBUFS); \
+ memcpy (buffer, (str), l); \
+ buffer += l; buffer_size -= l; \
+} while (0)
- assert (plugin != NULL);
- assert (type != NULL);
+ assert (plugin != NULL);
+ assert (type != NULL);
- if ((plugin_instance == NULL) || (strlen (plugin_instance) == 0))
- {
- if ((type_instance == NULL) || (strlen (type_instance) == 0))
- status = ssnprintf (ret, ret_len, "%s/%s/%s",
- hostname, plugin, type);
- else
- status = ssnprintf (ret, ret_len, "%s/%s/%s-%s",
- hostname, plugin, type,
- type_instance);
- }
- else
- {
- if ((type_instance == NULL) || (strlen (type_instance) == 0))
- status = ssnprintf (ret, ret_len, "%s/%s-%s/%s",
- hostname, plugin, plugin_instance,
- type);
- else
- status = ssnprintf (ret, ret_len, "%s/%s-%s/%s-%s",
- hostname, plugin, plugin_instance,
- type, type_instance);
- }
+ APPEND (hostname);
+ APPEND ("/");
+ APPEND (plugin);
+ if ((plugin_instance != NULL) && (plugin_instance[0] != 0))
+ {
+ APPEND ("-");
+ APPEND (plugin_instance);
+ }
+ APPEND ("/");
+ APPEND (type);
+ if ((type_instance != NULL) && (type_instance[0] != 0))
+ {
+ APPEND ("-");
+ APPEND (type_instance);
+ }
+ assert (buffer_size > 0);
+ buffer[0] = 0;
- if ((status < 1) || (status >= ret_len))
- return (-1);
- return (0);
+#undef APPEND
+ return (0);
} /* int format_name */
int format_values (char *ret, size_t ret_len, /* {{{ */
diff --git a/src/configfile.c b/src/configfile.c
index 876ee23ee71c8c33d2f230170bf94147a6012404..0e54f267f9fdd08c15d4d4d11a427f409d708723 100644 (file)
--- a/src/configfile.c
+++ b/src/configfile.c
{"Interval", NULL, NULL},
{"ReadThreads", NULL, "5"},
{"WriteThreads", NULL, "5"},
+ {"WriteQueueLimitHigh", NULL, NULL},
+ {"WriteQueueLimitLow", NULL, NULL},
{"Timeout", NULL, "2"},
{"AutoLoadPlugin", NULL, "false"},
{"PreCacheChain", NULL, "PreCache"},
sfree (pattern);
if (new == NULL)
- continue;
+ return (-1);
/* Now replace the i'th child in `root' with `new'. */
cf_ci_replace_child (root, new, i);
const char *pattern, int depth)
{
oconfig_item_t *root;
+ int status;
assert (depth < CF_MAX_DEPTH);
return (NULL);
}
- cf_include_all (root, depth);
+ status = cf_include_all (root, depth);
+ if (status != 0)
+ {
+ oconfig_free (root);
+ return (NULL);
+ }
return (root);
} /* oconfig_item_t *cf_read_file */
wordfree (&we);
- if (root->children == NULL)
- {
- oconfig_free (root);
- return (NULL);
- }
-
return (root);
} /* oconfig_item_t *cf_read_generic */
/* #endif HAVE_WORDEXP_H */
: cf_global_options[i].def);
} /* char *global_option_get */
+long global_option_get_long (const char *option, long default_value)
+{
+ const char *str;
+ long value;
+
+ str = global_option_get (option);
+ if (NULL == str)
+ return (default_value);
+
+ errno = 0;
+ value = strtol (str, /* endptr = */ NULL, /* base = */ 0);
+ if (errno != 0)
+ return (default_value);
+
+ return (value);
+} /* char *global_option_get_long */
+
cdtime_t cf_get_default_interval (void)
{
char const *str = global_option_get ("Interval");
ERROR ("Unable to read config file %s.", filename);
return (-1);
}
+ else if (conf->children_num == 0)
+ {
+ ERROR ("Configuration file %s is empty.", filename);
+ oconfig_free (conf);
+ return (-1);
+ }
for (i = 0; i < conf->children_num; i++)
{
diff --git a/src/configfile.h b/src/configfile.h
index 5a719a421a66a25df0073d6bdc4f24e8cbe9ebac..c91fcd5f4abb0bf87bf2339ae4524ac8e3b1de99 100644 (file)
--- a/src/configfile.h
+++ b/src/configfile.h
int global_option_set (const char *option, const char *value);
const char *global_option_get (const char *option);
+long global_option_get_long (const char *option, long default_value);
+long global_option_get_long_in_range (const char *option, long default_value, long min, long max);
cdtime_t cf_get_default_interval (void);
diff --git a/src/csv.c b/src/csv.c
index 02d62c1e014e89f98becd7993ea14a646287b31b..afb4f8338c5d7e2611e489338eda5a642f3c56b8 100644 (file)
--- a/src/csv.c
+++ b/src/csv.c
return (0);
} /* int value_list_to_string */
-static int value_list_to_filename (char *buffer, int buffer_len,
- const data_set_t *ds, const value_list_t *vl)
+static int value_list_to_filename (char *buffer, size_t buffer_size,
+ value_list_t const *vl)
{
- int offset = 0;
int status;
- assert (0 == strcmp (ds->type, vl->type));
-
- if (datadir != NULL)
- {
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", datadir);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
- }
+ char *ptr;
+ size_t ptr_size;
+ time_t now;
+ struct tm struct_tm;
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", vl->host);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ status = FORMAT_VL (buffer, buffer_size, vl);
+ if (status != 0)
+ return (status);
- if (strlen (vl->plugin_instance) > 0)
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s-%s/", vl->plugin, vl->plugin_instance);
- else
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", vl->plugin);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ /* Skip all the time formatting stuff when printing to STDOUT or
+ * STDERR. */
+ if (use_stdio)
+ return (0);
- if (strlen (vl->type_instance) > 0)
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s-%s", vl->type, vl->type_instance);
- else
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s", vl->type);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ ptr_size = buffer_size - strlen (buffer);
+ ptr = buffer + strlen (buffer);
- if (!use_stdio)
+ /* "-2013-07-12" => 11 bytes */
+ if (ptr_size < 12)
{
- time_t now;
- struct tm stm;
+ ERROR ("csv plugin: Buffer too small.");
+ return (ENOMEM);
+ }
- /* TODO: Find a way to minimize the calls to `localtime_r',
- * since they are pretty expensive.. */
- now = time (NULL);
- if (localtime_r (&now, &stm) == NULL)
- {
- ERROR ("csv plugin: localtime_r failed");
- return (1);
- }
+ /* TODO: Find a way to minimize the calls to `localtime_r',
+ * since they are pretty expensive.. */
+ now = time (NULL);
+ if (localtime_r (&now, &struct_tm) == NULL)
+ {
+ ERROR ("csv plugin: localtime_r failed");
+ return (-1);
+ }
- strftime (buffer + offset, buffer_len - offset,
- "-%Y-%m-%d", &stm);
+ status = strftime (ptr, ptr_size, "-%Y-%m-%d", &struct_tm);
+ if (status == 0) /* yep, it returns zero on error. */
+ {
+ ERROR ("csv plugin: strftime failed");
+ return (-1);
}
return (0);
return -1;
}
- if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+ status = value_list_to_filename (filename, sizeof (filename), vl);
+ if (status != 0)
return (-1);
DEBUG ("csv plugin: csv_write: filename = %s;", filename);
diff --git a/src/df.c b/src/df.c
index 5ff3f59be8cbcb401dd288c17ec4b89777251b43..3d5a402c7949b8741b7568b78d987c1fe033dc6a 100644 (file)
--- a/src/df.c
+++ b/src/df.c
"ReportByDevice",
"ReportReserved",
"ReportInodes",
- "ReportPercentage"
+ "ValuesAbsolute",
+ "ValuesPercentage"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
static _Bool by_device = 0;
static _Bool report_inodes = 0;
-static _Bool report_percentage = 0;
+static _Bool values_absolute = 1;
+static _Bool values_percentage = 0;
static int df_init (void)
{
return (0);
}
+ else if (strcasecmp (key, "ValuesAbsolute") == 0)
+ {
+ if (IS_TRUE (value))
+ values_absolute = 1;
+ else
+ values_absolute = 0;
- else if (strcasecmp (key, "ReportPercentage") == 0)
+ return (0);
+ }
+ else if (strcasecmp (key, "ValuesPercentage") == 0)
{
if (IS_TRUE (value))
- report_percentage = 1;
+ values_percentage = 1;
else
- report_percentage = 0;
+ values_percentage = 0;
return (0);
}
if (strlen(disk_name) < 1)
{
- DEBUG("df: no device name name for mountpoint %s, skipping", mnt_ptr->dir);
+ DEBUG("df: no device name for mountpoint %s, skipping", mnt_ptr->dir);
continue;
}
}
blk_reserved = (uint64_t) (statbuf.f_bfree - statbuf.f_bavail);
blk_used = (uint64_t) (statbuf.f_blocks - statbuf.f_bfree);
- if (report_percentage && (statbuf.f_blocks > 0))
- {
- uint64_t blk_total = (uint64_t) statbuf.f_blocks;
- char plugin_instance[DATA_MAX_NAME_LEN];
-
- ssnprintf (plugin_instance, sizeof (plugin_instance),
- "%s-bytes", disk_name);
-
- df_submit_one (plugin_instance, "percent", "free",
- 100.0 * ((gauge_t) blk_free) / ((gauge_t) blk_total));
- df_submit_one (plugin_instance, "percent", "reserved",
- 100.0 * ((gauge_t) blk_reserved) / ((gauge_t) blk_total));
- df_submit_one (plugin_instance, "percent", "used",
- 100.0 * ((gauge_t) blk_used) / ((gauge_t) blk_total));
- }
- else if (!report_percentage)
+ if (values_absolute)
{
df_submit_one (disk_name, "df_complex", "free",
(gauge_t) (blk_free * blocksize));
(gauge_t) (blk_used * blocksize));
}
+ if (values_percentage)
+ {
+ if (statbuf.f_blocks > 0)
+ {
+ df_submit_one (disk_name, "percent_bytes", "free",
+ (gauge_t) ((float_t)(blk_free) / statbuf.f_blocks * 100));
+ df_submit_one (disk_name, "percent_bytes", "reserved",
+ (gauge_t) ((float_t)(blk_reserved) / statbuf.f_blocks * 100));
+ df_submit_one (disk_name, "percent_bytes", "used",
+ (gauge_t) ((float_t)(blk_used) / statbuf.f_blocks * 100));
+ }
+ else return (-1);
+ }
+
/* inode handling */
if (report_inodes)
{
inode_reserved = (uint64_t) (statbuf.f_ffree - statbuf.f_favail);
inode_used = (uint64_t) (statbuf.f_files - statbuf.f_ffree);
- if (report_percentage && (statbuf.f_files > 0))
+ if (values_percentage)
{
- uint64_t inode_total = (uint64_t) statbuf.f_files;
- char plugin_instance[DATA_MAX_NAME_LEN];
-
- ssnprintf (plugin_instance, sizeof (plugin_instance),
- "%s-inodes", disk_name);
-
- df_submit_one (plugin_instance, "percent", "free",
- 100.0 * ((gauge_t) inode_free) / ((gauge_t) inode_total));
- df_submit_one (plugin_instance, "percent", "reserved",
- 100.0 * ((gauge_t) inode_reserved) / ((gauge_t) inode_total));
- df_submit_one (plugin_instance, "percent", "used",
- 100.0 * ((gauge_t) inode_used) / ((gauge_t) inode_total));
+ if (statbuf.f_files > 0)
+ {
+ df_submit_one (disk_name, "percent_inodes", "free",
+ (gauge_t) ((float_t)(inode_free) / statbuf.f_files * 100));
+ df_submit_one (disk_name, "percent_inodes", "reserved",
+ (gauge_t) ((float_t)(inode_reserved) / statbuf.f_files * 100));
+ df_submit_one (disk_name, "percent_inodes", "used",
+ (gauge_t) ((float_t)(inode_used) / statbuf.f_files * 100));
+ }
+ else return (-1);
}
- else if (!report_percentage)
+ if (values_absolute)
{
df_submit_one (disk_name, "df_inodes", "free",
(gauge_t) inode_free);
diff --git a/src/dns.c b/src/dns.c
index fe3b672a21d844b2190c80e7b2f7bffd9adb9b50..00fcff191e0ccf0177ec7bea309eb2964b331228 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
pthread_mutex_unlock (&opcode_mutex);
}
-static void *dns_child_loop (__attribute__((unused)) void *dummy)
+static int dns_run_pcap_loop (void)
{
pcap_t *pcap_obj;
char pcap_error[PCAP_ERRBUF_SIZE];
"failed: %s",
(pcap_device != NULL) ? pcap_device : "any",
pcap_error);
- return (NULL);
+ return (PCAP_ERROR);
}
memset (&fp, 0, sizeof (fp));
- if (pcap_compile (pcap_obj, &fp, "udp port 53", 1, 0) < 0)
+ status = pcap_compile (pcap_obj, &fp, "udp port 53", 1, 0);
+ if (status < 0)
{
- ERROR ("dns plugin: pcap_compile failed");
- return (NULL);
+ ERROR ("dns plugin: pcap_compile failed: %s",
+ pcap_statustostr (status));
+ return (status);
}
- if (pcap_setfilter (pcap_obj, &fp) < 0)
+
+ status = pcap_setfilter (pcap_obj, &fp);
+ if (status < 0)
{
- ERROR ("dns plugin: pcap_setfilter failed");
- return (NULL);
+ ERROR ("dns plugin: pcap_setfilter failed: %s",
+ pcap_statustostr (status));
+ return (status);
}
DEBUG ("dns plugin: PCAP object created.");
status = pcap_loop (pcap_obj,
-1 /* loop forever */,
handle_pcap /* callback */,
- NULL /* Whatever this means.. */);
- if (status < 0)
- ERROR ("dns plugin: Listener thread is exiting "
- "abnormally: %s", pcap_geterr (pcap_obj));
-
- DEBUG ("dns plugin: Child is exiting.");
+ NULL /* user data */);
+ INFO ("dns plugin: pcap_loop exited with status %i.", status);
+ /* We need to handle "PCAP_ERROR" specially because libpcap currently
+ * doesn't return PCAP_ERROR_IFACE_NOT_UP for compatibility reasons. */
+ if (status == PCAP_ERROR)
+ status = PCAP_ERROR_IFACE_NOT_UP;
pcap_close (pcap_obj);
- listen_thread_init = 0;
- pthread_exit (NULL);
+ return (status);
+} /* int dns_run_pcap_loop */
+
+static int dns_sleep_one_interval (void) /* {{{ */
+{
+ cdtime_t interval;
+ struct timespec ts = { 0, 0 };
+ int status = 0;
+
+ interval = plugin_get_interval ();
+ CDTIME_T_TO_TIMESPEC (interval, &ts);
+
+ while (42)
+ {
+ struct timespec rem = { 0, 0 };
+
+ status = nanosleep (&ts, &rem);
+ if (status == 0)
+ break;
+ else if ((errno == EINTR) || (errno == EAGAIN))
+ {
+ ts = rem;
+ continue;
+ }
+ else
+ break;
+ }
+
+ return (status);
+} /* }}} int dns_sleep_one_interval */
+
+static void *dns_child_loop (__attribute__((unused)) void *dummy) /* {{{ */
+{
+ int status;
+
+ while (42)
+ {
+ status = dns_run_pcap_loop ();
+ if (status != PCAP_ERROR_IFACE_NOT_UP)
+ break;
+ dns_sleep_one_interval ();
+ }
+
+ if (status != PCAP_ERROR_BREAK)
+ ERROR ("dns plugin: PCAP returned error %s.",
+ pcap_statustostr (status));
+
+ listen_thread_init = 0;
return (NULL);
-} /* static void dns_child_loop (void) */
+} /* }}} void *dns_child_loop */
static int dns_init (void)
{
diff --git a/src/memcached.c b/src/memcached.c
index a09f45ec6dae1a2e537fe986af7677f4130bd662..535ea84704b3dac328a5af495f69bccdbdfedb9a 100644 (file)
--- a/src/memcached.c
+++ b/src/memcached.c
gauge_t bytes_total = NAN;
gauge_t hits = NAN;
gauge_t gets = NAN;
+ gauge_t incr_hits = NAN;
+ derive_t incr = 0;
+ gauge_t decr_hits = NAN;
+ derive_t decr = 0;
derive_t rusage_user = 0;
derive_t rusage_syst = 0;
derive_t octets_rx = 0;
gets = atof (fields[2]);
}
+ /*
+ * Increment/Decrement
+ */
+ else if (FIELD_IS("incr_misses"))
+ {
+ derive_t incr_count = atoll (fields[2]);
+ submit_derive ("memcached_ops", "incr_misses", incr_count, st);
+ incr += incr_count;
+ }
+ else if (FIELD_IS ("incr_hits"))
+ {
+ derive_t incr_count = atoll (fields[2]);
+ submit_derive ("memcached_ops", "incr_hits", incr_count, st);
+ incr_hits = atof (fields[2]);
+ incr += incr_count;
+ }
+ else if (FIELD_IS ("decr_misses"))
+ {
+ derive_t decr_count = atoll (fields[2]);
+ submit_derive ("memcached_ops", "decr_misses", decr_count, st);
+ decr += decr_count;
+ }
+ else if (FIELD_IS ("decr_hits"))
+ {
+ derive_t decr_count = atoll (fields[2]);
+ submit_derive ("memcached_ops", "decr_hits", decr_count, st);
+ decr_hits = atof (fields[2]);
+ decr += decr_count;
+ }
+
/*
* Operations on the cache, i. e. cache hits, cache misses and evictions of items
*/
submit_gauge ("percent", "hitratio", rate, st);
}
+ if (!isnan (incr_hits) && incr != 0)
+ {
+ gauge_t incr_rate = 100.0 * incr_hits / incr;
+ submit_gauge ("percent", "incr_hitratio", incr_rate, st);
+ submit_derive ("memcached_ops", "incr", incr, st);
+ }
+
+ if (!isnan (decr_hits) && decr != 0)
+ {
+ gauge_t decr_rate = 100.0 * decr_hits / decr;
+ submit_gauge ("percent", "decr_hitratio", decr_rate, st);
+ submit_derive ("memcached_ops", "decr", decr, st);
+ }
+
return 0;
} /* int memcached_read */
diff --git a/src/modbus.c b/src/modbus.c
index 8a9fe93fd83eaf3b6a32221ea9c92598c225802a..887c63c03235922c2f7c62eff1d7e4409eee4f80 100644 (file)
--- a/src/modbus.c
+++ b/src/modbus.c
modbus_t *connection;
#endif
_Bool is_connected;
- _Bool have_reconnected;
}; /* }}} */
typedef struct mb_host_s mb_host_t;
union
{
uint8_t b[4];
+ uint16_t s[2];
float f;
} conv;
if (host == NULL)
return (EINVAL);
- if (host->is_connected)
- return (0);
-
- /* Only reconnect once per interval. */
- if (host->have_reconnected)
- return (-1);
-
modbus_set_debug (&host->connection, 1);
/* We'll do the error handling ourselves. */
}
host->is_connected = 1;
- host->have_reconnected = 1;
return (0);
} /* }}} int mb_init_connection */
/* #endif LEGACY_LIBMODBUS */
if (host->connection != NULL)
return (0);
- /* Only reconnect once per interval. */
- if (host->have_reconnected)
- return (-1);
-
if ((host->port < 1) || (host->port > 65535))
host->port = MODBUS_TCP_DEFAULT_PORT;
host->connection = modbus_new_tcp (host->node, host->port);
if (host->connection == NULL)
{
- host->have_reconnected = 1;
ERROR ("Modbus plugin: Creating new Modbus/TCP object failed.");
return (-1);
}
return (status);
}
- host->have_reconnected = 1;
return (0);
} /* }}} int mb_init_connection */
#endif /* !LEGACY_LIBMODBUS */
int values_num;
const data_set_t *ds;
int status;
- int i;
if ((host == NULL) || (slave == NULL) || (data == NULL))
return (EINVAL);
else
values_num = 1;
+ status = 0;
+ if (host->connection == NULL)
+ {
+ status = EBADF;
+ }
+ else
+ {
+ struct sockaddr sockaddr;
+ socklen_t saddrlen = sizeof (sockaddr);
+
+ status = getpeername (modbus_get_socket (host->connection),
+ &sockaddr, &saddrlen);
+ if (status != 0)
+ status = errno;
+ }
+
+ if ((status == EBADF) || (status == ENOTSOCK) || (status == ENOTCONN))
+ {
+ status = mb_init_connection (host);
+ if (status != 0)
+ {
+ ERROR ("Modbus plugin: mb_init_connection (%s/%s) failed. ",
+ host->host, host->node);
+ host->is_connected = 0;
+ host->connection = NULL;
+ return (-1);
+ }
+ }
+ else if (status != 0)
+ {
+#if LEGACY_LIBMODBUS
+ modbus_close (&host->connection);
+#else
+ modbus_close (host->connection);
+ modbus_free (host->connection);
+#endif
+ }
+
#if LEGACY_LIBMODBUS
/* Version 2.0.3: Pass the connection struct as a pointer and pass the slave
* id to each call of "read_holding_registers". */
}
#endif
- for (i = 0; i < 2; i++)
- {
- status = modbus_read_registers (host->connection,
+ status = modbus_read_registers (host->connection,
/* start_addr = */ data->register_base,
/* num_registers = */ values_num, /* buffer = */ values);
- if (status > 0)
- break;
-
- if (host->is_connected)
- {
+ if (status != values_num)
+ {
+ ERROR ("Modbus plugin: modbus_read_registers (%s/%s) failed. status = %i, values_num = %i "
+ "Giving up.", host->host, host->node, status, values_num);
#if LEGACY_LIBMODBUS
- modbus_close (&host->connection);
- host->is_connected = 0;
+ modbus_close (&host->connection);
#else
- modbus_close (host->connection);
- modbus_free (host->connection);
- host->connection = NULL;
+ modbus_close (host->connection);
+ modbus_free (host->connection);
#endif
- }
-
- /* If we already tried reconnecting this round, give up. */
- if (host->have_reconnected)
- {
- ERROR ("Modbus plugin: modbus_read_registers (%s) failed. "
- "Reconnecting has already been tried. Giving up.", host->host);
- return (-1);
- }
-
- /* Maybe the device closed the connection during the waiting interval.
- * Try re-establishing the connection. */
- status = mb_init_connection (host);
- if (status != 0)
- {
- ERROR ("Modbus plugin: modbus_read_registers (%s) failed. "
- "While trying to reconnect, connecting to \"%s\" failed. "
- "Giving up.",
- host->host, host->node);
- return (-1);
- }
-
- DEBUG ("Modbus plugin: Re-established connection to %s", host->host);
-
- /* try again */
- continue;
- } /* for (i = 0, 1) */
+ host->connection = NULL;
+ return (-1);
+ }
DEBUG ("Modbus plugin: mb_read_data: Success! "
"modbus_read_registers returned with status %i.", status);
host = user_data->data;
- /* Clear the reconnect flag. */
- host->have_reconnected = 0;
-
success = 0;
for (i = 0; i < host->slaves_num; i++)
{
diff --git a/src/mysql.c b/src/mysql.c
index d2d0b4bfc57a9ad695b592835cadd4707935fac0..d15a055fe3296f70835e8e6daed68a46b37965bc 100644 (file)
--- a/src/mysql.c
+++ b/src/mysql.c
ssnprintf (n.message, sizeof (n.message),
"slave SQL thread started");
plugin_dispatch_notification (&n);
- db->slave_sql_running = 0;
+ db->slave_sql_running = 1;
}
}
diff --git a/src/nginx.c b/src/nginx.c
index 7568a2c5ee2ded6439b6eb24927d64bb1b503e4a..de52262f4ec817b1b54ca876652b02e06a845252 100644 (file)
--- a/src/nginx.c
+++ b/src/nginx.c
values[0].gauge = value;
else if (strcmp (type, "nginx_requests") == 0)
values[0].derive = value;
+ else if (strcmp (type, "connections") == 0)
+ values[0].derive = value;
else
return;
&& (atoll (fields[1]) != 0)
&& (atoll (fields[2]) != 0))
{
+ submit ("connections", "accepted", atoll (fields[0]));
+ submit ("connections", "handled", atoll (fields[1]));
submit ("nginx_requests", NULL, atoll (fields[2]));
}
}
diff --git a/src/plugin.c b/src/plugin.c
index 894b0e51d72731ba1f7faab5c032a122063e85be..6c7aa057cf2d272b126eadf6308a76188d3f3b1a 100644 (file)
--- a/src/plugin.c
+++ b/src/plugin.c
#include "utils_llist.h"
#include "utils_heap.h"
#include "utils_time.h"
+#include "utils_random.h"
#if HAVE_PTHREAD_H
# include <pthread.h>
static write_queue_t *write_queue_head;
static write_queue_t *write_queue_tail;
+static long write_queue_length = 0;
static _Bool write_loop = 1;
static pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t write_cond = PTHREAD_COND_INITIALIZER;
static pthread_key_t plugin_ctx_key;
static _Bool plugin_ctx_key_initialized = 0;
+static long write_limit_high = 0;
+static long write_limit_low = 0;
+
/*
* Static functions
*/
{
write_queue_head = q;
write_queue_tail = q;
+ write_queue_length = 1;
}
else
{
write_queue_tail->next = q;
write_queue_tail = q;
+ write_queue_length += 1;
}
pthread_cond_signal (&write_cond);
q = write_queue_head;
write_queue_head = q->next;
- if (write_queue_head == NULL)
+ write_queue_length -= 1;
+ if (write_queue_head == NULL) {
write_queue_tail = NULL;
+ assert(0 == write_queue_length);
+ }
pthread_mutex_unlock (&write_lock);
}
write_queue_head = NULL;
write_queue_tail = NULL;
+ write_queue_length = 0;
pthread_mutex_unlock (&write_lock);
if (i > 0)
(void *) callback, /* user_data = */ NULL));
} /* int plugin_register_shutdown */
+static void plugin_free_data_sets (void)
+{
+ void *key;
+ void *value;
+
+ if (data_sets == NULL)
+ return;
+
+ while (c_avl_pick (data_sets, &key, &value) == 0)
+ {
+ data_set_t *ds = value;
+ /* key is a pointer to ds->type */
+
+ sfree (ds->ds);
+ sfree (ds);
+ }
+
+ c_avl_destroy (data_sets);
+ data_sets = NULL;
+} /* void plugin_free_data_sets */
+
int plugin_register_data_set (const data_set_t *ds)
{
data_set_t *ds_copy;
void plugin_init_all (void)
{
- const char *chain_name;
+ char const *chain_name;
+ long write_threads_num;
llentry_t *le;
int status;
chain_name = global_option_get ("PostCacheChain");
post_cache_chain = fc_chain_get_by_name (chain_name);
+ write_limit_high = global_option_get_long ("WriteQueueLimitHigh",
+ /* default = */ 0);
+ if (write_limit_high < 0)
{
- char const *tmp = global_option_get ("WriteThreads");
- int num = atoi (tmp);
+ ERROR ("WriteQueueLimitHigh must be positive or zero.");
+ write_limit_high = 0;
+ }
- if (num < 1)
- num = 5;
+ write_limit_low = global_option_get_long ("WriteQueueLimitLow",
+ /* default = */ write_limit_high / 2);
+ if (write_limit_low < 0)
+ {
+ ERROR ("WriteQueueLimitLow must be positive or zero.");
+ write_limit_low = write_limit_high / 2;
+ }
+ else if (write_limit_low > write_limit_high)
+ {
+ ERROR ("WriteQueueLimitLow must not be larger than "
+ "WriteQueueLimitHigh.");
+ write_limit_low = write_limit_high;
+ }
- start_write_threads ((size_t) num);
+ write_threads_num = global_option_get_long ("WriteThreads",
+ /* default = */ 5);
+ if (write_threads_num < 1)
+ {
+ ERROR ("WriteThreads must be positive.");
+ write_threads_num = 5;
}
+ start_write_threads ((size_t) write_threads_num);
+
if ((list_init == NULL) && (read_heap == NULL))
return;
destroy_all_callbacks (&list_log);
plugin_free_loaded ();
+ plugin_free_data_sets ();
} /* void plugin_shutdown_all */
int plugin_dispatch_missing (const value_list_t *vl) /* {{{ */
return (0);
} /* int plugin_dispatch_values_internal */
+static double get_drop_probability (void) /* {{{ */
+{
+ long pos;
+ long size;
+ long wql;
+
+ pthread_mutex_lock (&write_lock);
+ wql = write_queue_length;
+ pthread_mutex_unlock (&write_lock);
+
+ if (wql < write_limit_low)
+ return (0.0);
+ if (wql >= write_limit_high)
+ return (1.0);
+
+ pos = 1 + wql - write_limit_low;
+ size = 1 + write_limit_high - write_limit_low;
+
+ return (((double) pos) / ((double) size));
+} /* }}} double get_drop_probability */
+
+static _Bool check_drop_value (void) /* {{{ */
+{
+ static cdtime_t last_message_time = 0;
+ static pthread_mutex_t last_message_lock = PTHREAD_MUTEX_INITIALIZER;
+
+ double p;
+ double q;
+ int status;
+
+ if (write_limit_high == 0)
+ return (0);
+
+ p = get_drop_probability ();
+ if (p == 0.0)
+ return (0);
+
+ status = pthread_mutex_trylock (&last_message_lock);
+ if (status == 0)
+ {
+ cdtime_t now;
+
+ now = cdtime ();
+ if ((now - last_message_time) > TIME_T_TO_CDTIME_T (1))
+ {
+ last_message_time = now;
+ ERROR ("plugin_dispatch_values: Low water mark "
+ "reached. Dropping %.0f%% of metrics.",
+ 100.0 * p);
+ }
+ pthread_mutex_unlock (&last_message_lock);
+ }
+
+ if (p == 1.0)
+ return (1);
+
+ q = cdrand_d ();
+ if (q > p)
+ return (1);
+ else
+ return (0);
+} /* }}} _Bool check_drop_value */
+
int plugin_dispatch_values (value_list_t const *vl)
{
int status;
+ if (check_drop_value ())
+ return (0);
+
status = plugin_write_enqueue (vl);
if (status != 0)
{
diff --git a/src/rrdcached.c b/src/rrdcached.c
index 7e0b1e77ef3b523f45eb3a188598a0ee3b8bae2a..e5e11d4317b045fbb8587a3de3cc3f332653e858 100644 (file)
--- a/src/rrdcached.c
+++ b/src/rrdcached.c
return (0);
} /* int value_list_to_string */
-static int value_list_to_filename (char *buffer, int buffer_len,
- const data_set_t *ds, const value_list_t *vl)
+static int value_list_to_filename (char *buffer, size_t buffer_size,
+ value_list_t const *vl)
{
- int offset = 0;
+ char const suffix[] = ".rrd";
int status;
+ size_t len;
- assert (0 == strcmp (ds->type, vl->type));
-
- if (datadir != NULL)
- {
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", datadir);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
- }
-
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", vl->host);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
-
- if (strlen (vl->plugin_instance) > 0)
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s-%s/", vl->plugin, vl->plugin_instance);
- else
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", vl->plugin);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ status = FORMAT_VL (buffer, buffer_size, vl);
+ if (status != 0)
+ return (status);
- if (strlen (vl->type_instance) > 0)
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s-%s", vl->type, vl->type_instance);
- else
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s", vl->type);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ len = strlen (buffer);
+ assert (len < buffer_size);
+ buffer += len;
+ buffer_size -= len;
- strncpy (buffer + offset, ".rrd", buffer_len - offset);
- buffer[buffer_len - 1] = 0;
+ if (buffer_size <= sizeof (suffix))
+ return (ENOMEM);
+ memcpy (buffer, suffix, sizeof (suffix));
return (0);
} /* int value_list_to_filename */
return (-1);
}
- if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+ if (value_list_to_filename (filename, sizeof (filename), vl) != 0)
{
ERROR ("rrdcached plugin: value_list_to_filename failed.");
return (-1);
diff --git a/src/rrdtool.c b/src/rrdtool.c
index 2c80762ecb905454f843620fd86cf3cd449ba8f7..2f28329f0fbef43f17c70b3b7136a6b4f187e2b8 100644 (file)
--- a/src/rrdtool.c
+++ b/src/rrdtool.c
} /* int srrd_update */
#endif /* !HAVE_THREADSAFE_LIBRRD */
-static int value_list_to_string (char *buffer, int buffer_len,
+static int value_list_to_string_multiple (char *buffer, int buffer_len,
const data_set_t *ds, const value_list_t *vl)
{
int offset;
} /* for ds->ds_num */
return (0);
-} /* int value_list_to_string */
+} /* int value_list_to_string_multiple */
-static int value_list_to_filename (char *buffer, int buffer_len,
- const data_set_t __attribute__((unused)) *ds, const value_list_t *vl)
+static int value_list_to_string (char *buffer, int buffer_len,
+ const data_set_t *ds, const value_list_t *vl)
{
- int offset = 0;
int status;
+ time_t tt;
+
+ if (ds->ds_num != 1)
+ return (value_list_to_string_multiple (buffer, buffer_len,
+ ds, vl));
- if (datadir != NULL)
+ tt = CDTIME_T_TO_TIME_T (vl->time);
+ switch (ds->ds[0].type)
{
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", datadir);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ case DS_TYPE_DERIVE:
+ status = ssnprintf (buffer, buffer_len, "%u:%"PRIi64,
+ (unsigned) tt, vl->values[0].derive);
+ break;
+ case DS_TYPE_GAUGE:
+ status = ssnprintf (buffer, buffer_len, "%u:%lf",
+ (unsigned) tt, vl->values[0].gauge);
+ break;
+ case DS_TYPE_COUNTER:
+ status = ssnprintf (buffer, buffer_len, "%u:%llu",
+ (unsigned) tt, vl->values[0].counter);
+ break;
+ case DS_TYPE_ABSOLUTE:
+ status = ssnprintf (buffer, buffer_len, "%u:%"PRIu64,
+ (unsigned) tt, vl->values[0].absolute);
+ break;
+ default:
+ return (EINVAL);
}
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", vl->host);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ if ((status < 1) || (status >= buffer_len))
+ return (ENOMEM);
- if (strlen (vl->plugin_instance) > 0)
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s-%s/", vl->plugin, vl->plugin_instance);
- else
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s/", vl->plugin);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+ return (0);
+} /* int value_list_to_string */
- if (strlen (vl->type_instance) > 0)
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s-%s.rrd", vl->type, vl->type_instance);
- else
- status = ssnprintf (buffer + offset, buffer_len - offset,
- "%s.rrd", vl->type);
- if ((status < 1) || (status >= buffer_len - offset))
- return (-1);
- offset += status;
+static int value_list_to_filename (char *buffer, size_t buffer_size,
+ value_list_t const *vl)
+{
+ char const suffix[] = ".rrd";
+ int status;
+ size_t len;
+
+ status = FORMAT_VL (buffer, buffer_size, vl);
+ if (status != 0)
+ return (status);
+
+ len = strlen (buffer);
+ assert (len < buffer_size);
+ buffer += len;
+ buffer_size -= len;
+
+ if (buffer_size <= sizeof (suffix))
+ return (ENOMEM);
+ memcpy (buffer, suffix, sizeof (suffix));
return (0);
} /* int value_list_to_filename */
return -1;
}
- if (value_list_to_filename (filename, sizeof (filename), ds, vl) != 0)
+ if (value_list_to_filename (filename, sizeof (filename), vl) != 0)
return (-1);
if (value_list_to_string (values, sizeof (values), ds, vl) != 0)
diff --git a/src/sigrok.c b/src/sigrok.c
--- /dev/null
+++ b/src/sigrok.c
@@ -0,0 +1,399 @@
+/*
+ * collectd - src/sigrok.c
+ * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
+
+#include <glib.h>
+#include <libsigrok/libsigrok.h>
+
+/* Minimum interval between dispatches coming from this plugin. The RRD
+ * plugin, at least, complains when written to with sub-second intervals.*/
+#define DEFAULT_MIN_DISPATCH_INTERVAL TIME_T_TO_CDTIME_T(0)
+
+static pthread_t sr_thread;
+static int sr_thread_running = FALSE;
+GSList *config_devices;
+static int num_devices;
+static int loglevel = SR_LOG_WARN;
+static struct sr_context *sr_ctx;
+
+struct config_device {
+ char *name;
+ char *driver;
+ char *conn;
+ char *serialcomm;
+ struct sr_dev_inst *sdi;
+ cdtime_t min_dispatch_interval;
+ cdtime_t last_dispatch;
+};
+
+
+static int sigrok_log_callback(void*cb_data __attribute__((unused)),
+ int msg_loglevel, const char *format, va_list args)
+{
+ char s[512];
+
+ if (msg_loglevel <= loglevel) {
+ vsnprintf(s, 512, format, args);
+ plugin_log(LOG_INFO, "sigrok plugin: %s", s);
+ }
+
+ return 0;
+}
+
+static int sigrok_config_device(oconfig_item_t *ci)
+{
+ struct config_device *cfdev;
+ int i;
+
+ if (!(cfdev = malloc(sizeof(struct config_device)))) {
+ ERROR("sigrok plugin: malloc() failed.");
+ return -1;
+ }
+ memset(cfdev, 0, sizeof(*cfdev));
+ if (cf_util_get_string(ci, &cfdev->name)) {
+ free(cfdev);
+ WARNING("sigrok plugin: Invalid device name.");
+ return -1;
+ }
+ cfdev->min_dispatch_interval = DEFAULT_MIN_DISPATCH_INTERVAL;
+
+ for (i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *item = ci->children + i;
+ if (!strcasecmp(item->key, "driver"))
+ cf_util_get_string(item, &cfdev->driver);
+ else if (!strcasecmp(item->key, "conn"))
+ cf_util_get_string(item, &cfdev->conn);
+ else if (!strcasecmp(item->key, "serialcomm"))
+ cf_util_get_string(item, &cfdev->serialcomm);
+ else if (!strcasecmp(item->key, "minimuminterval"))
+ cf_util_get_cdtime(item, &cfdev->min_dispatch_interval);
+ else
+ WARNING("sigrok plugin: Invalid keyword \"%s\".",
+ item->key);
+ }
+
+ config_devices = g_slist_append(config_devices, cfdev);
+
+ return 0;
+}
+
+static int sigrok_config(oconfig_item_t *ci)
+{
+ int i;
+
+ for (i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *item = ci->children + i;
+ if (strcasecmp("LogLevel", item->key) == 0) {
+ int status;
+ int tmp = -1;
+
+ status = cf_util_get_int (item, &tmp);
+ if (status != 0)
+ continue;
+ else if ((tmp < 0) || (tmp > 5)) {
+ ERROR ("sigrok plugin: The \"LogLevel\" "
+ "configuration option expects "
+ "an integer between 0 and 5 "
+ "(inclusive); you provided %i.",
+ tmp);
+ continue;
+ }
+ loglevel = tmp;
+ } else if (!strcasecmp(item->key, "Device"))
+ sigrok_config_device(item);
+ else
+ WARNING("sigrok plugin: Invalid keyword \"%s\".",
+ item->key);
+ }
+
+ return 0;
+}
+
+static char *sigrok_value_type(const struct sr_datafeed_analog *analog)
+{
+ char *s;
+
+ if (analog->mq == SR_MQ_VOLTAGE)
+ s = "voltage";
+ else if (analog->mq == SR_MQ_CURRENT)
+ s = "current";
+ else if (analog->mq == SR_MQ_FREQUENCY)
+ s = "frequency";
+ else if (analog->mq == SR_MQ_POWER)
+ s = "power";
+ else if (analog->mq == SR_MQ_TEMPERATURE)
+ s = "temperature";
+ else if (analog->mq == SR_MQ_RELATIVE_HUMIDITY)
+ s = "humidity";
+ else if (analog->mq == SR_MQ_SOUND_PRESSURE_LEVEL)
+ s = "spl";
+ else
+ s = "gauge";
+
+ return s;
+}
+
+static void sigrok_feed_callback(const struct sr_dev_inst *sdi,
+ const struct sr_datafeed_packet *packet, void *cb_data)
+{
+ const struct sr_datafeed_analog *analog;
+ struct config_device *cfdev;
+ GSList *l;
+ value_t value;
+ value_list_t vl = VALUE_LIST_INIT;
+
+ /* Find this device's configuration. */
+ cfdev = NULL;
+ for (l = config_devices; l; l = l->next) {
+ cfdev = l->data;
+ if (cfdev->sdi == sdi) {
+ /* Found it. */
+ break;
+ }
+ cfdev = NULL;
+ }
+
+ if (!cfdev) {
+ ERROR("sigrok plugin: Received data from driver \"%s\" but "
+ "can't find a configuration / device matching "
+ "it.", sdi->driver->name);
+ return;
+ }
+
+ if (packet->type == SR_DF_END) {
+ /* TODO: try to restart acquisition after a delay? */
+ WARNING("sigrok plugin: acquisition for \"%s\" ended.",
+ cfdev->name);
+ return;
+ }
+
+ if (packet->type != SR_DF_ANALOG)
+ return;
+
+ if ((cfdev->min_dispatch_interval != 0)
+ && ((cdtime() - cfdev->last_dispatch)
+ < cfdev->min_dispatch_interval))
+ return;
+
+ /* Ignore all but the first sample on the first probe. */
+ analog = packet->payload;
+ value.gauge = analog->data[0];
+ vl.values = &value;
+ vl.values_len = 1;
+ sstrncpy(vl.host, hostname_g, sizeof(vl.host));
+ sstrncpy(vl.plugin, "sigrok", sizeof(vl.plugin));
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance),
+ "%s", cfdev->name);
+ sstrncpy(vl.type, sigrok_value_type(analog), sizeof(vl.type));
+
+ plugin_dispatch_values(&vl);
+ cfdev->last_dispatch = cdtime();
+}
+
+static void sigrok_free_drvopts(struct sr_config *src)
+{
+ g_variant_unref(src->data);
+ g_free(src);
+}
+
+static int sigrok_init_driver(struct config_device *cfdev,
+ struct sr_dev_driver *drv)
+{
+ struct sr_config *src;
+ GSList *devlist, *drvopts;
+ char hwident[512];
+
+ if (sr_driver_init(sr_ctx, drv) != SR_OK)
+ /* Error was logged by libsigrok. */
+ return -1;
+
+ drvopts = NULL;
+ if (cfdev->conn) {
+ if (!(src = malloc(sizeof(struct sr_config))))
+ return -1;
+ src->key = SR_CONF_CONN;
+ src->data = g_variant_new_string(cfdev->conn);
+ drvopts = g_slist_append(drvopts, src);
+ }
+ if (cfdev->serialcomm) {
+ if (!(src = malloc(sizeof(struct sr_config))))
+ return -1;
+ src->key = SR_CONF_SERIALCOMM;
+ src->data = g_variant_new_string(cfdev->serialcomm);
+ drvopts = g_slist_append(drvopts, src);
+ }
+ devlist = sr_driver_scan(drv, drvopts);
+ g_slist_free_full(drvopts, (GDestroyNotify)sigrok_free_drvopts);
+ if (!devlist) {
+ /* Not an error, but the user should know about it. */
+ WARNING("sigrok plugin: No device found for \"%s\".",
+ cfdev->name);
+ return 0;
+ }
+
+ if (g_slist_length(devlist) > 1) {
+ INFO("sigrok plugin: %d sigrok devices for device entry "
+ "\"%s\": must be 1.",
+ g_slist_length(devlist), cfdev->name);
+ return -1;
+ }
+ cfdev->sdi = devlist->data;
+ g_slist_free(devlist);
+ ssnprintf(hwident, sizeof(hwident), "%s %s %s",
+ cfdev->sdi->vendor ? cfdev->sdi->vendor : "",
+ cfdev->sdi->model ? cfdev->sdi->model : "",
+ cfdev->sdi->version ? cfdev->sdi->version : "");
+ INFO("sigrok plugin: Device \"%s\" is a %s", cfdev->name, hwident);
+
+ if (sr_dev_open(cfdev->sdi) != SR_OK)
+ return -1;
+
+ if (sr_session_dev_add(cfdev->sdi) != SR_OK)
+ return -1;
+
+ return 1;
+}
+
+static void *sigrok_read_thread(void *arg __attribute__((unused)))
+{
+ struct sr_dev_driver *drv, **drvlist;
+ GSList *l;
+ struct config_device *cfdev;
+ int ret, i;
+
+ sr_log_callback_set(sigrok_log_callback, NULL);
+ sr_log_loglevel_set(loglevel);
+
+ if ((ret = sr_init(&sr_ctx)) != SR_OK) {
+ ERROR("sigrok plugin: Failed to initialize libsigrok: %s.",
+ sr_strerror(ret));
+ return NULL;
+ }
+
+ if (!sr_session_new())
+ return NULL;
+
+ num_devices = 0;
+ drvlist = sr_driver_list();
+ for (l = config_devices; l; l = l->next) {
+ cfdev = l->data;
+ drv = NULL;
+ for (i = 0; drvlist[i]; i++) {
+ if (!strcmp(drvlist[i]->name, cfdev->driver)) {
+ drv = drvlist[i];
+ break;
+ }
+ }
+ if (!drv) {
+ ERROR("sigrok plugin: Unknown driver \"%s\".",
+ cfdev->driver);
+ return NULL;
+ }
+
+ if ((ret = sigrok_init_driver(cfdev, drv)) < 0)
+ /* Error was already logged. */
+ return NULL;
+
+ num_devices += ret;
+ }
+
+ if (num_devices > 0) {
+ /* Do this only when we're sure there's hardware to talk to. */
+ if (sr_session_datafeed_callback_add(sigrok_feed_callback, NULL)
+ != SR_OK)
+ return NULL;
+
+ /* Start acquisition on all devices. */
+ if (sr_session_start() != SR_OK)
+ return NULL;
+
+ /* Main loop, runs forever. */
+ sr_session_run();
+
+ sr_session_stop();
+ sr_session_dev_remove_all();
+ }
+
+ sr_session_destroy();
+
+ sr_exit(sr_ctx);
+
+ pthread_exit(NULL);
+ sr_thread_running = FALSE;
+
+ return NULL;
+}
+
+static int sigrok_init(void)
+{
+ int status;
+
+ if (sr_thread_running) {
+ ERROR("sigrok plugin: Thread already running.");
+ return -1;
+ }
+
+ if ((status = plugin_thread_create(&sr_thread, NULL, sigrok_read_thread,
+ NULL)) != 0) {
+ ERROR("sigrok plugin: Failed to create thread: %s.",
+ strerror(status));
+ return -1;
+ }
+ sr_thread_running = TRUE;
+
+ return 0;
+}
+
+static int sigrok_shutdown(void)
+{
+ struct config_device *cfdev;
+ GSList *l;
+
+ if (sr_thread_running) {
+ pthread_cancel(sr_thread);
+ pthread_join(sr_thread, NULL);
+ }
+
+ for (l = config_devices; l; l = l->next) {
+ cfdev = l->data;
+ free(cfdev->name);
+ free(cfdev->driver);
+ free(cfdev->conn);
+ free(cfdev->serialcomm);
+ free(cfdev);
+ }
+ g_slist_free(config_devices);
+
+ return 0;
+}
+
+void module_register(void)
+{
+ plugin_register_complex_config("sigrok", sigrok_config);
+ plugin_register_init("sigrok", sigrok_init);
+ plugin_register_shutdown("sigrok", sigrok_shutdown);
+}
diff --git a/src/snmp.c b/src/snmp.c
index 4f849320a3f3f6bdc2bdfb3730bf60fdc08016c5..ad81c89214a926d8e194bad96d2dd207bf6fa707 100644 (file)
--- a/src/snmp.c
+++ b/src/snmp.c
@@ -1373,13 +1373,14 @@ static int csnmp_read_table (host_definition_t *host, data_definition_t *data)
csnmp_table_values_t *vt;
oid_t vb_name;
oid_t suffix;
+ int ret;
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)
+ ret = csnmp_oid_suffix (&suffix, &vb_name, data->values + i);
+ if (ret != 0)
{
DEBUG ("snmp plugin: host = %s; data = %s; i = %i; "
"Value probably left its subtree.",
diff --git a/src/tail.c b/src/tail.c
index 25cbcd4c1b5188df787e843c60aecb895aad5688..bcb157255fcd1a30a8048d7977271cb1dc46e027 100644 (file)
--- a/src/tail.c
+++ b/src/tail.c
cu_tail_match_t **tail_match_list = NULL;
size_t tail_match_list_num = 0;
-static int ctail_config_add_string (const char *name, char **dest, oconfig_item_t *ci)
-{
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- WARNING ("tail plugin: `%s' needs exactly one string argument.", name);
- return (-1);
- }
-
- sfree (*dest);
- *dest = strdup (ci->values[0].value.string);
- if (*dest == NULL)
- return (-1);
-
- return (0);
-} /* int ctail_config_add_string */
-
static int ctail_config_add_match_dstype (ctail_config_match_t *cm,
oconfig_item_t *ci)
{
oconfig_item_t *option = ci->children + i;
if (strcasecmp ("Regex", option->key) == 0)
- status = ctail_config_add_string ("Regex", &cm.regex, option);
+ status = cf_util_get_string (option, &cm.regex);
else if (strcasecmp ("ExcludeRegex", option->key) == 0)
- status = ctail_config_add_string ("ExcludeRegex", &cm.excluderegex,
- option);
+ status = cf_util_get_string (option, &cm.excluderegex);
else if (strcasecmp ("DSType", option->key) == 0)
status = ctail_config_add_match_dstype (&cm, option);
else if (strcasecmp ("Type", option->key) == 0)
- status = ctail_config_add_string ("Type", &cm.type, option);
+ status = cf_util_get_string (option, &cm.type);
else if (strcasecmp ("Instance", option->key) == 0)
- status = ctail_config_add_string ("Instance", &cm.type_instance, option);
+ status = cf_util_get_string (option, &cm.type_instance);
else
{
WARNING ("tail plugin: Option `%s' not allowed here.", option->key);
status = 0;
}
else if (strcasecmp ("Instance", option->key) == 0)
- status = ctail_config_add_string ("Instance", &plugin_instance, option);
+ status = cf_util_get_string (option, &plugin_instance);
else
{
WARNING ("tail plugin: Option `%s' not allowed here.", option->key);
diff --git a/src/threshold.c b/src/threshold.c
index d4cfd6ea922ef2dbc984e6ca137f28774aa6ed68..7df4d616a977cb5ca53028c6808b08c1c580ba80 100644 (file)
--- a/src/threshold.c
+++ b/src/threshold.c
char identifier[6 * DATA_MAX_NAME_LEN];
notification_t n;
- /* dispatch notifications for "interesting" values only */
if (threshold_tree == NULL)
return (0);
th = threshold_search (vl);
- if (th == NULL)
+ /* dispatch notifications for "interesting" values only */
+ if ((th == NULL) || ((th->flags & UT_FLAG_INTERESTING) == 0))
return (0);
missing_time = cdtime () - vl->time;
diff --git a/src/types.db b/src/types.db
index 950f6b0d842dd087b9db3e7b012d280da6ec417b..723b477d72e45e1c4eac75ef719a4aa7d06ec641 100644 (file)
--- a/src/types.db
+++ b/src/types.db
irq value:DERIVE:0:U
latency value:GAUGE:0:65535
links value:GAUGE:0:U
-load shortterm:GAUGE:0:100, midterm:GAUGE:0:100, longterm:GAUGE:0:100
+load shortterm:GAUGE:0:5000, midterm:GAUGE:0:5000, longterm:GAUGE:0:5000
md_disks value:GAUGE:0:U
memcached_command value:DERIVE:0:U
memcached_connections value:GAUGE:0:U
objects value:GAUGE:0:U
operations value:DERIVE:0:U
percent value:GAUGE:0:100.1
+percent_bytes value:GAUGE:0:100.1
+percent_inodes value:GAUGE:0:100.1
pf_counters value:DERIVE:0:U
pf_limits value:DERIVE:0:U
pf_source value:DERIVE:0:U
snr value:GAUGE:0:U
spam_check value:GAUGE:0:U
spam_score value:GAUGE:U:U
+spl value:GAUGE:U:U
swap_io value:DERIVE:0:U
swap value:GAUGE:0:1099511627776
tcp_connections value:GAUGE:0:4294967295
-temperature value:GAUGE:-273.15:U
+temperature value:GAUGE:U:U
threads value:GAUGE:0:U
time_dispersion value:GAUGE:-1000000:1000000
timeleft value:GAUGE:0:U
diff --git a/src/types.db.pod b/src/types.db.pod
index 67f988195af55580ea6ab47a6d578afded6c546d..111742ba0dc5c5ae9c3a866dc9920fd4cb566bd1 100644 (file)
--- a/src/types.db.pod
+++ b/src/types.db.pod
+=encoding UTF-8
+
=head1 NAME
types.db - Data-set specifications for the system statistics collection daemon
diff --git a/src/utils_mount.h b/src/utils_mount.h
index 1f2403c3aa26412acd36046c790db290b0610ff0..83f789be9cd3acdf7f5535cb2e41ed035e3cbc2b 100644 (file)
--- a/src/utils_mount.h
+++ b/src/utils_mount.h
#ifndef COLLECTD_UTILS_MOUNT_H
#define COLLECTD_UTILS_MOUNT_H 1
+#include <stdio.h>
#if HAVE_FS_INFO_H
# include <fs_info.h>
#endif
diff --git a/src/varnish.c b/src/varnish.c
index f7bca416880648a0e2a7843c8877a466a3149c96..e2ced0e4e20e128184f56330634aa854ae9c21b1 100644 (file)
--- a/src/varnish.c
+++ b/src/varnish.c
else
{
WARNING ("Varnish plugin: Ignoring unknown "
- "configuration option: \"%s\"",
+ "configuration option: \"%s\". Did "
+ "you forget to add an <Instance /> "
+ "block around the configuration?",
child->key);
}
}
diff --git a/src/write_graphite.c b/src/write_graphite.c
index 949a8425178f700b952787f15bc0426f4f6d7299..6124d33edf5a07ae26f922b1cc7a151a959b6c28 100644 (file)
--- a/src/write_graphite.c
+++ b/src/write_graphite.c
* <Carbon>
* Host "localhost"
* Port "2003"
+ * Protocol "udp"
+ * LogSendErrors true
* Prefix "collectd"
* </Carbon>
* </Plugin>
# define WG_DEFAULT_SERVICE "2003"
#endif
+#ifndef WG_DEFAULT_PROTOCOL
+# define WG_DEFAULT_PROTOCOL "udp"
+#endif
+
+#ifndef WG_DEFAULT_LOG_SEND_ERRORS
+# define WG_DEFAULT_LOG_SEND_ERRORS 1
+#endif
+
#ifndef WG_DEFAULT_ESCAPE
# define WG_DEFAULT_ESCAPE '_'
#endif
char *node;
char *service;
+ char *protocol;
+ _Bool log_send_errors;
char *prefix;
char *postfix;
char escape_char;
ssize_t status = 0;
status = swrite (cb->sock_fd, cb->send_buf, strlen (cb->send_buf));
- if (status < 0)
+ if (cb->log_send_errors && status < 0)
{
char errbuf[1024];
- ERROR ("write_graphite plugin: send failed with status %zi (%s)",
+ ERROR ("write_graphite plugin: send to %s:%s (%s) failed with status %zi (%s)",
+ cb->node, cb->service, cb->protocol,
status, sstrerror (errno, errbuf, sizeof (errbuf)));
const char *node = cb->node ? cb->node : WG_DEFAULT_NODE;
const char *service = cb->service ? cb->service : WG_DEFAULT_SERVICE;
+ const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
if (cb->sock_fd > 0)
return (0);
ai_hints.ai_flags |= AI_ADDRCONFIG;
#endif
ai_hints.ai_family = AF_UNSPEC;
- ai_hints.ai_socktype = SOCK_STREAM;
+
+ if (0 == strcasecmp ("tcp", protocol))
+ ai_hints.ai_socktype = SOCK_STREAM;
+ else
+ ai_hints.ai_socktype = SOCK_DGRAM;
ai_list = NULL;
status = getaddrinfo (node, service, &ai_hints, &ai_list);
if (status != 0)
{
- ERROR ("write_graphite plugin: getaddrinfo (%s, %s) failed: %s",
- node, service, gai_strerror (status));
+ ERROR ("write_graphite plugin: getaddrinfo (%s, %s, %s) failed: %s",
+ node, service, protocol, gai_strerror (status));
return (-1);
}
{
char errbuf[1024];
c_complain (LOG_ERR, &cb->init_complaint,
- "write_graphite plugin: Connecting to %s:%s failed. "
- "The last error was: %s", node, service,
+ "write_graphite plugin: Connecting to %s:%s via %s failed. "
+ "The last error was: %s", node, service, protocol,
sstrerror (errno, errbuf, sizeof (errbuf)));
- close (cb->sock_fd);
return (-1);
}
else
{
c_release (LOG_INFO, &cb->init_complaint,
- "write_graphite plugin: Successfully connected to %s:%s.",
- node, service);
+ "write_graphite plugin: Successfully connected to %s:%s via %s.",
+ node, service, protocol);
}
wg_reset_buffer (cb);
wg_flush_nolock (/* timeout = */ 0, cb);
- close(cb->sock_fd);
- cb->sock_fd = -1;
+ if (cb->sock_fd >= 0)
+ {
+ close (cb->sock_fd);
+ cb->sock_fd = -1;
+ }
sfree(cb->name);
sfree(cb->node);
+ sfree(cb->protocol);
sfree(cb->service);
sfree(cb->prefix);
sfree(cb->postfix);
cb->send_buf_fill += message_len;
cb->send_buf_free -= message_len;
- DEBUG ("write_graphite plugin: [%s]:%s buf %zu/%zu (%.1f %%) \"%s\"",
+ DEBUG ("write_graphite plugin: [%s]:%s (%s) buf %zu/%zu (%.1f %%) \"%s\"",
cb->node,
cb->service,
+ cb->protocol,
cb->send_buf_fill, sizeof (cb->send_buf),
100.0 * ((double) cb->send_buf_fill) / ((double) sizeof (cb->send_buf)),
message);
return (status);
/* Send the message to graphite */
- wg_send_message (buffer, cb);
- if (status != 0)
- {
- /* An error message has already been printed. */
+ status = wg_send_message (buffer, cb);
+ if (status != 0) /* error message has been printed already. */
return (status);
- }
return (0);
} /* int wg_write_messages */
user_data_t user_data;
char callback_name[DATA_MAX_NAME_LEN];
int i;
+ int status = 0;
cb = malloc (sizeof (*cb));
if (cb == NULL)
cb->name = NULL;
cb->node = NULL;
cb->service = NULL;
+ cb->protocol = NULL;
+ cb->log_send_errors = WG_DEFAULT_LOG_SEND_ERRORS;
cb->prefix = NULL;
cb->postfix = NULL;
cb->escape_char = WG_DEFAULT_ESCAPE;
/* FIXME: Legacy configuration syntax. */
if (strcasecmp ("Carbon", ci->key) != 0)
{
- int status = cf_util_get_string (ci, &cb->name);
+ status = cf_util_get_string (ci, &cb->name);
if (status != 0)
{
wg_callback_free (cb);
cf_util_get_string (child, &cb->node);
else if (strcasecmp ("Port", child->key) == 0)
cf_util_get_service (child, &cb->service);
+ else if (strcasecmp ("Protocol", child->key) == 0)
+ {
+ cf_util_get_string (child, &cb->protocol);
+
+ if (strcasecmp ("UDP", cb->protocol) != 0 &&
+ strcasecmp ("TCP", cb->protocol) != 0)
+ {
+ ERROR ("write_graphite plugin: Unknown protocol (%s)",
+ cb->protocol);
+ status = -1;
+ }
+ }
+ else if (strcasecmp ("LogSendErrors", child->key) == 0)
+ cf_util_get_boolean (child, &cb->log_send_errors);
else if (strcasecmp ("Prefix", child->key) == 0)
cf_util_get_string (child, &cb->prefix);
else if (strcasecmp ("Postfix", child->key) == 0)
{
ERROR ("write_graphite plugin: Invalid configuration "
"option: %s.", child->key);
+ status = -1;
}
+
+ if (status != 0)
+ break;
+ }
+
+ if (status != 0)
+ {
+ wg_callback_free (cb);
+ return (status);
}
/* FIXME: Legacy configuration syntax. */
if (cb->name == NULL)
- ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s/%s",
+ ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s/%s/%s",
cb->node != NULL ? cb->node : WG_DEFAULT_NODE,
- cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE);
+ cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE,
+ cb->protocol != NULL ? cb->protocol : WG_DEFAULT_PROTOCOL);
else
ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
cb->name);
diff --git a/src/write_riemann.c b/src/write_riemann.c
index 3e2ddd75b0d5caec3bbc40b5121b1de20ab819b4..3345d0444a94653a4e3be42a9d9051bfd264e790 100644 (file)
--- a/src/write_riemann.c
+++ b/src/write_riemann.c
static void riemann_event_protobuf_free (Event *event) /* {{{ */
{
+ size_t i;
+
if (event == NULL)
return;
event->tags = NULL;
event->n_tags = 0;
+ for (i = 0; i < event->n_attributes; i++)
+ {
+ sfree (event->attributes[i]->key);
+ sfree (event->attributes[i]->value);
+ sfree (event->attributes[i]);
+ }
+ sfree (event->attributes);
+ event->n_attributes = 0;
+
sfree (event);
} /* }}} void riemann_event_protobuf_free */