#ide stuff
.vscode
+# cscope stuff
+cscope.*
+
# Unit tests
src/daemon/test-suite.log
src/tests/
Jiri Tyr <jiri.tyr at gmail.com>
- fhcount plugin.
+Julien Ammous <j.ammous at gmail.com>
+ - Lua plugin.
+
Kevin Bowling <kbowling at llnw.com>
- write_tsdb plugin for http://opentsdb.net/
Detailed CPU statistics of the “Logical Partitions” virtualization
technique built into IBM's POWER processors.
+ - lua
+ The Lua plugin implements a Lua interpreter into collectd. This
+ makes it possible to write plugins in Lua which are executed by
+ collectd without the need to start a heavy interpreter every interval.
+ See collectd-lua(5) for details.
+
- lvm
Size of “Logical Volumes” (LV) and “Volume Groups” (VG) of Linux'
“Logical Volume Manager” (LVM).
diskspace but is extremely portable and can be analysed with almost
every program that can analyse anything. Even Microsoft's Excel..
+ - lua
+ It's possible to implement write plugins in Lua using the Lua
+ plugin. See collectd-lua(5) for details.
+
- network
Send the data to a remote host to save the data somehow. This is useful
for large setups where the data should be saved by a dedicated machine.
Used by the `openldap' plugin.
<http://www.openldap.org/>
+ * liblua (optional)
+ Used by the `lua' plugin. Currently, Lua 5.1 and later are supported.
+ <https://www.lua.org/>
+
* liblvm2 (optional)
Used by the `lvm' plugin.
<ftp://sources.redhat.com/pub/lvm2/>
<http://code.google.com/p/protobuf-c/>
* libpython (optional)
- Used by the `python' plugin. Currently, Python 2.3 and later and Python 3
+ Used by the `python' plugin. Currently, Python 2.6 and later and Python 3
are supported.
<http://www.python.org/>
#include <linux/major.h>
#include <linux/types.h>
])
+ AC_CHECK_HEADERS([sys/sysmacros.h])
else
have_linux_raid_md_u_h="no"
fi
wordexp.h \
])
-AC_CHECK_HEADERS([xfs/xqm.h], [], [],
-[
-#define _GNU_SOURCE
-])
+# --enable-xfs {{{
+AC_ARG_ENABLE([xfs],
+ [AS_HELP_STRING([--enable-xfs], [xfs support in df plugin @<:@default=yes@:>@])],
+ [],
+ [enable_xfs="auto"]
+)
+
+if test "x$enable_xfs" != "xno"; then
+ AC_CHECK_HEADERS([xfs/xqm.h],
+ [],
+ [
+ if test "x$enable_xfs" = "xyes"; then
+ AC_MSG_ERROR([xfs/xqm.h not found])
+ fi
+ ],
+ [[#define _GNU_SOURCE]]
+ )
+fi
+
+# }}}
# For the dns plugin
AC_CHECK_HEADERS(arpa/nameser.h)
then
AC_LANG_PUSH(C++)
SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$with_libgrpcpp_cppflags $GRPCPP_CFLAGS $CPPFLAGS -std=c++11"
+ CPPFLAGS="-std=c++11 $with_libgrpcpp_cppflags $GRPCPP_CFLAGS $CPPFLAGS"
AC_CHECK_HEADERS([grpc++/grpc++.h], [],
[with_libgrpcpp="no (<grpc++/grpc++.h> not found)"]
)
if test "x$with_libgrpcpp" = "xyes"
then
AC_LANG_PUSH(C++)
+ SAVE_CPPFLAGS="$CPPFLAGS"
SAVE_LDFLAGS="$LDFLAGS"
SAVE_LIBS="$LIBS"
+ CPPFLAGS="-std=c++11 $with_libgrpcpp_cppflags $GRPCPP_CFLAGS $CPPFLAGS"
LDFLAGS="$with_libgrpcpp_ldflags"
if test "x$GRPCPP_LIBS" = "x"
then
],
[with_libgrpcpp="no (libgrpc++ not found)"]
)
+ CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
LIBS="$SAVE_LIBS"
AC_LANG_POP(C++)
AM_CONDITIONAL(BUILD_WITH_LIBLDAP, test "x$with_libldap" = "xyes")
# }}}
+# --with-liblua {{{
+with_liblua_cppflags=""
+with_liblua_ldflags=""
+with_liblua_libs=""
+with_liblua="yes"
+
+AC_ARG_VAR([LIBLUA_PKG_CONFIG_NAME], [Name of liblua used by pkg-config])
+if test "x$LIBLUA_PKG_CONFIG_NAME" = "x"
+then
+ LIBLUA_PKG_CONFIG_NAME="lua"
+fi
+
+if test "x$with_liblua" = "xyes"
+then
+ $PKG_CONFIG --exists $LIBLUA_PKG_CONFIG_NAME 2>/dev/null
+ lua_config_status=$?
+
+ if test 0 -ne $lua_config_status
+ then
+ with_liblua="no"
+ fi
+fi
+
+if test "x$with_liblua" = "xyes"
+then
+ with_liblua_cppflags=`$PKG_CONFIG --cflags-only-I $LIBLUA_PKG_CONFIG_NAME` || with_liblua="no"
+ with_liblua_ldflags=`$PKG_CONFIG --libs-only-L $LIBLUA_PKG_CONFIG_NAME` || with_liblua="no"
+ with_liblua_libs=`$PKG_CONFIG --libs-only-l $LIBLUA_PKG_CONFIG_NAME` || with_liblua="no"
+fi
+if test "x$with_liblua" = "xyes"
+then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_liblua_cppflags"
+
+ AC_CHECK_HEADERS(lua.h lauxlib.h lualib.h, [], [with_liblua="no (header not found)"], [])
+
+ CPPFLAGS="$SAVE_CPPFLAGS"
+fi
+if test "x$with_liblua" = "xyes"
+then
+ SAVE_LDFLAGS="$LDFLAGS"
+ SAVE_LIBS="$LIBS"
+ LDFLAGS="$SAVE_LDFLAGS $with_liblua_ldflags"
+ LIBS="$LIBS $with_liblua_libs"
+
+ AC_CHECK_FUNC(lua_settop, [with_liblua="yes"], [with_liblua="no (symbol 'lua_settop' not found)"])
+
+ LDFLAGS="$SAVE_LDFLAGS"
+ LIBS="$SAVE_LIBS"
+fi
+if test "x$with_liblua" = "xyes"
+then
+ BUILD_WITH_LIBLUA_CPPFLAGS="$with_liblua_cppflags"
+ BUILD_WITH_LIBLUA_LDFLAGS="$with_liblua_ldflags"
+ BUILD_WITH_LIBLUA_LIBS="$with_liblua_libs"
+fi
+AC_SUBST(BUILD_WITH_LIBLUA_CPPFLAGS)
+AC_SUBST(BUILD_WITH_LIBLUA_LDFLAGS)
+AC_SUBST(BUILD_WITH_LIBLUA_LIBS)
+# }}}
+
# --with-liblvm2app {{{
with_liblvm2app_cppflags=""
with_liblvm2app_ldflags=""
# }}}
# --with-libnetsnmp {{{
-with_snmp_config="net-snmp-config"
-with_snmp_cflags=""
-with_snmp_libs=""
AC_ARG_WITH(libnetsnmp, [AS_HELP_STRING([--with-libnetsnmp@<:@=PREFIX@:>@], [Path to the Net-SNMPD library.])],
[
if test "x$withval" = "xno"
then
with_libnetsnmp="yes"
else
- if test -x "$withval"
- then
- with_snmp_config="$withval"
- with_libnetsnmp="yes"
- else
- with_snmp_config="$withval/bin/net-snmp-config"
- with_libnetsnmp="yes"
- fi
+ with_libnetsnmp_cppflags="-I$withval/include"
+ with_libnetsnmp_ldflags="-I$withval/lib"
+ with_libnetsnmp="yes"
fi; fi
],
[with_libnetsnmp="yes"])
if test "x$with_libnetsnmp" = "xyes"
then
- with_snmp_cflags=`$with_snmp_config --cflags 2>/dev/null`
- snmp_config_status=$?
-
- if test $snmp_config_status -ne 0
- then
- with_libnetsnmp="no ($with_snmp_config failed)"
- else
- SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_snmp_cflags"
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libnetsnmp_cppflags"
- AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
+ AC_CHECK_HEADERS(net-snmp/net-snmp-config.h, [], [with_libnetsnmp="no (net-snmp/net-snmp-config.h not found)"])
- CPPFLAGS="$SAVE_CPPFLAGS"
- fi
+ CPPFLAGS="$SAVE_CPPFLAGS"
fi
if test "x$with_libnetsnmp" = "xyes"
then
- with_snmp_libs=`$with_snmp_config --libs 2>/dev/null`
- snmp_config_status=$?
+ SAVE_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $with_libnetsnmp_ldflags"
- if test $snmp_config_status -ne 0
- then
- with_libnetsnmp="no ($with_snmp_config failed)"
- else
- AC_CHECK_LIB(netsnmp, init_snmp,
+ AC_CHECK_LIB(netsnmp, init_snmp,
[with_libnetsnmp="yes"],
[with_libnetsnmp="no (libnetsnmp not found)"],
[$with_snmp_libs])
- fi
+
+ LDFLAGS="$SAVE_LDFLAGS"
fi
if test "x$with_libnetsnmp" = "xyes"
then
- BUILD_WITH_LIBSNMP_CFLAGS="$with_snmp_cflags"
- BUILD_WITH_LIBSNMP_LIBS="$with_snmp_libs"
- AC_SUBST(BUILD_WITH_LIBSNMP_CFLAGS)
- AC_SUBST(BUILD_WITH_LIBSNMP_LIBS)
+ BUILD_WITH_LIBNETSNMP_CPPFLAGS="$with_libnetsnmp_cppflags"
+ BUILD_WITH_LIBNETSNMP_LDFLAGS="$with_libnetsnmp_ldflags"
+ BUILD_WITH_LIBNETSNMP_LIBS="-lnetsnmp"
fi
-AM_CONDITIONAL(BUILD_WITH_LIBNETSNMP, test "x$with_libnetsnmp" = "xyes")
+AC_SUBST(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
+AC_SUBST(BUILD_WITH_LIBNETSNMP_LDFLAGS)
+AC_SUBST(BUILD_WITH_LIBNETSNMP_LIBS)
# }}}
# --with-liboconfig {{{
save_CPPFLAGS="$CPPFLAGS"
LDFLAGS="$liboconfig_LDFLAGS"
CPPFLAGS="$liboconfig_CPPFLAGS"
-AC_CHECK_LIB(oconfig, oconfig_parse_fh,
+AC_CHECK_LIB(oconfig, oconfig_parse_file,
[
with_liboconfig="yes"
with_own_liboconfig="no"
AC_PLUGIN([log_logstash], [$plugin_log_logstash], [Logstash json_event compatible logging])
AC_PLUGIN([logfile], [yes], [File logging plugin])
AC_PLUGIN([lpar], [$with_perfstat], [AIX logical partitions statistics])
+AC_PLUGIN([lua], [$with_liblua], [Lua plugin])
AC_PLUGIN([lvm], [$with_liblvm2app], [LVM statistics])
AC_PLUGIN([madwifi], [$have_linux_wireless_h], [Madwifi wireless statistics])
AC_PLUGIN([match_empty_counter], [yes], [The empty counter match])
with_perl_bindings="no (no perl interpreter found)"
fi
])
+
+if test "x$with_perl_bindings" = "xyes"
+then
+ AC_MSG_CHECKING([for the ExtUtils::MakeMaker module])
+ if $PERL -MExtUtils::MakeMaker -e '' 2>/dev/null; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ with_perl_bindings="no (ExtUtils::MakeMaker not found)"
+ fi
+fi
+
if test "x$with_perl_bindings" = "xyes"
then
PERL_BINDINGS="perl"
AC_MSG_RESULT([ libkstat . . . . . . $with_kstat])
AC_MSG_RESULT([ libkvm . . . . . . . $with_libkvm])
AC_MSG_RESULT([ libldap . . . . . . . $with_libldap])
+AC_MSG_RESULT([ liblua . . . . . . . $with_liblua])
AC_MSG_RESULT([ liblvm2app . . . . . $with_liblvm2app])
AC_MSG_RESULT([ libmemcached . . . . $with_libmemcached])
AC_MSG_RESULT([ libmnl . . . . . . . $with_libmnl])
AC_MSG_RESULT([ logfile . . . . . . . $enable_logfile])
AC_MSG_RESULT([ log_logstash . . . . $enable_log_logstash])
AC_MSG_RESULT([ lpar . . . . . . . . $enable_lpar])
+AC_MSG_RESULT([ lua . . . . . . . . . $enable_lua])
AC_MSG_RESULT([ lvm . . . . . . . . . $enable_lvm])
AC_MSG_RESULT([ madwifi . . . . . . . $enable_madwifi])
AC_MSG_RESULT([ match_empty_counter . $enable_match_empty_counter])
%define with_filecount 0%{!?_without_filecount:1}
%define with_fscache 0%{!?_without_fscache:1}
%define with_gmond 0%{!?_without_gmond:1}
+%define with_gps 0%{!?_without_gps:1}
%define with_hddtemp 0%{!?_without_hddtemp:1}
%define with_interface 0%{!?_without_interface:1}
%define with_ipc 0%{!?_without_ipc:1}
%define with_load 0%{!?_without_load:1}
%define with_log_logstash 0%{!?_without_log_logstash:1}
%define with_logfile 0%{!?_without_logfile:1}
+%define with_lua 0%{!?_without_lua:1}
%define with_lvm 0%{!?_without_lvm:1}
%define with_madwifi 0%{!?_without_madwifi:1}
%define with_mbmon 0%{!?_without_mbmon:1}
Summary: Statistics collection and monitoring daemon
Name: collectd
Version: 5.5.2
-Release: 1%{?dist}
+Release: 2%{?dist}
URL: https://collectd.org
Source: https://collectd.org/files/%{name}-%{version}.tar.bz2
License: GPLv2
This plugin logs in logstash JSON format
%endif
+%if %{with_lua}
+%package lua
+Summary: Lua plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: lua-devel
+%description lua
+The Lua plugin embeds a Lua interpreter into collectd and exposes the
+application programming interface (API) to Lua scripts.
+%endif
+
%if %{with_lvm}
%package lvm
Summary: LVM plugin for collectd
%define _with_lpar --disable-lpar
%endif
+%if %{with_lua}
+%define _with_lua --enable-lua
+%else
+%define _with_lua --disable-lua
+%endif
+
%if %{with_lvm}
%define _with_lvm --enable-lvm
%else
%{?_with_log_logstash} \
%{?_with_logfile} \
%{?_with_lpar} \
+ %{?_with_lua} \
%{?_with_lvm} \
%{?_with_madwifi} \
%{?_with_mbmon} \
rm -f %{buildroot}%{_mandir}/man5/collectd-java.5*
%endif
+%if ! %{with_lua}
+rm -f %{buildroot}%{_mandir}/man5/collectd-lua.5*
+%endif
+
%if ! %{with_perl}
rm -f %{buildroot}%{_mandir}/man5/collectd-perl.5*
rm -f %{buildroot}%{_mandir}/man3/Collectd::Unixsock.3pm*
%{_libdir}/%{name}/log_logstash.so
%endif
+%if %{with_lua}
+%files lua
+%{_mandir}/man5/collectd-lua*
+%{_libdir}/%{name}/lua.so
+%endif
+
%if %{with_lvm}
%files lvm
%{_libdir}/%{name}/lvm.so
%doc contrib/
%changelog
+* Sun Aug 14 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.5.2-2
+- Add new Lua plugin
+
* Tue Jul 26 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.5.2-1
- New upstream version
- Contains fix for CVE-2016-6254
syntax = "proto3";
package collectd;
+option go_package = "collectd.org/rpc/proto";
import "types.proto";
service Collectd {
- // Dispatch collected values to collectd.
- rpc DispatchValues(DispatchValuesRequest) returns (DispatchValuesReply);
-
- // Query a list of values available from collectd's value cache.
- rpc QueryValues(QueryValuesRequest) returns (QueryValuesReply);
+ // DispatchValues reads the value lists from the DispatchValuesRequest stream.
+ // The gRPC server embedded into collectd will inject them into the system
+ // just like the network plugin.
+ rpc DispatchValues(stream DispatchValuesRequest)
+ returns (DispatchValuesResponse);
+
+ // QueryValues returns a stream of matching value lists from collectd's
+ // internal cache.
+ rpc QueryValues(QueryValuesRequest) returns (stream QueryValuesResponse);
}
// The arguments to DispatchValues.
message DispatchValuesRequest {
- collectd.types.ValueList values = 1;
+ // value_list is the metric to be sent to the server.
+ collectd.types.ValueList value_list = 1;
}
// The response from DispatchValues.
-message DispatchValuesReply {
-}
+message DispatchValuesResponse {}
// The arguments to QueryValues.
message QueryValuesRequest {
- // Query by the fields of the identifier. Only return values matching the
- // specified shell wildcard patterns (see fnmatch(3)). Use '*' to match
- // any value.
- collectd.types.Identifier identifier = 1;
+ // Query by the fields of the identifier. Only return values matching the
+ // specified shell wildcard patterns (see fnmatch(3)). Use '*' to match
+ // any value.
+ collectd.types.Identifier identifier = 1;
}
// The response from QueryValues.
-message QueryValuesReply {
- repeated collectd.types.ValueList values = 1;
-}
+message QueryValuesResponse { collectd.types.ValueList value_list = 1; }
syntax = "proto3";
package collectd.types;
+option go_package = "collectd.org/rpc/proto/types";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
message Identifier {
- string host = 1;
- string plugin = 2;
- string plugin_instance = 3;
- string type = 4;
- string type_instance = 5;
+ string host = 1;
+ string plugin = 2;
+ string plugin_instance = 3;
+ string type = 4;
+ string type_instance = 5;
}
message Value {
- oneof value {
- uint64 counter = 1;
- double gauge = 2;
- int64 derive = 3;
- uint64 absolute = 4;
- };
+ oneof value {
+ uint64 counter = 1;
+ double gauge = 2;
+ int64 derive = 3;
+ uint64 absolute = 4;
+ };
}
message ValueList {
- repeated Value value = 1;
+ repeated Value values = 1;
- google.protobuf.Timestamp time = 2;
- google.protobuf.Duration interval = 3;
+ google.protobuf.Timestamp time = 2;
+ google.protobuf.Duration interval = 3;
- Identifier identifier = 4;
+ Identifier identifier = 4;
+
+ repeated string ds_names = 5;
}
apache_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS)
endif
+
if BUILD_PLUGIN_APCUPS
pkglib_LTLIBRARIES += apcups.la
apcups_la_SOURCES = apcups.c
lpar_la_LIBADD = -lperfstat
endif
+if BUILD_PLUGIN_LUA
+pkglib_LTLIBRARIES += lua.la
+lua_la_SOURCES = lua.c \
+ utils_lua.c utils_lua.h
+lua_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBLUA_CPPFLAGS)
+lua_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBLUA_LDFLAGS)
+lua_la_LIBADD = $(BUILD_WITH_LIBLUA_LIBS)
+endif
+
if BUILD_PLUGIN_LVM
pkglib_LTLIBRARIES += lvm.la
lvm_la_SOURCES = lvm.c
if BUILD_PLUGIN_SNMP
pkglib_LTLIBRARIES += snmp.la
snmp_la_SOURCES = snmp.c
-snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-snmp_la_CFLAGS = $(AM_CFLAGS)
-snmp_la_LIBADD =
-if BUILD_WITH_LIBNETSNMP
-snmp_la_CFLAGS += $(BUILD_WITH_LIBSNMP_CFLAGS)
-snmp_la_LIBADD += $(BUILD_WITH_LIBSNMP_LIBS)
-endif
+snmp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
+snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS)
+snmp_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS)
endif
if BUILD_PLUGIN_STATSD
collectd-exec.5 \
collectdctl.1 \
collectd-java.5 \
+ collectd-lua.5 \
collectdmon.1 \
collectd-nagios.1 \
collectd-perl.5 \
collectd-exec.pod \
collectdctl.pod \
collectd-java.pod \
+ collectd-lua.pod \
collectdmon.pod \
collectd-nagios.pod \
collectd-perl.pod \
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include "meta_data.h"
#include "utils_cache.h" /* for uc_get_rate() */
#include "utils_subst.h"
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <curl/curl.h>
#include "common.h" /* rrd_update_file */
#include "plugin.h" /* plugin_register, plugin_submit */
-#include "configfile.h" /* cf_register */
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <curl/curl.h>
#include <libxml/parser.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include <math.h>
+#include <sys/ioctl.h>
/* ------------ MPL115 defines ------------ */
/* I2C address of the MPL115 sensor */
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
/* Some versions of libcurl don't include this themselves and then don't have
* fd_set available. */
#if HAVE_YAJL_YAJL_VERSION_H
#include <yajl/yajl_version.h>
#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
#include <limits.h>
#include <poll.h>
static struct ceph_daemon **g_daemons = NULL;
/** Number of elements in g_daemons */
-static int g_num_daemons = 0;
+static size_t g_num_daemons = 0;
/**
* A set of data that we build up in memory while parsing the JSON.
#define BUFFER_ADD(dest, src) do { \
size_t dest_size = sizeof (dest); \
- strncat ((dest), (src), dest_size - strlen (dest)); \
- (dest)[dest_size - 1] = '\0'; \
+ size_t dest_len = strlen (dest); \
+ if (dest_size > dest_len) { \
+ sstrncpy ((dest) + dest_len, (src), dest_size - dest_len); \
+ } \
+ (dest)[dest_size - 1] = 0; \
} while (0)
static int
{
yajl_struct *state = (yajl_struct*) ctx;
char buffer[number_len+1];
- char key[2 * DATA_MAX_NAME_LEN];
+ char key[2 * DATA_MAX_NAME_LEN] = { 0 };
_Bool latency_type = 0;
int status;
- key[0] = '\0';
memcpy(buffer, number_val, number_len);
buffer[sizeof(buffer) - 1] = '\0';
static void ceph_daemons_print(void)
{
- for(int i = 0; i < g_num_daemons; ++i)
+ for(size_t i = 0; i < g_num_daemons; ++i)
{
ceph_daemon_print(g_daemons[i]);
}
return ENOMEM;
}
memcpy(nd, &cd, sizeof(*nd));
- g_daemons[g_num_daemons++] = nd;
+ g_daemons[g_num_daemons] = nd;
+ g_num_daemons++;
return 0;
}
/* create cconn array */
memset(io_array, 0, sizeof(io_array));
- for(int i = 0; i < g_num_daemons; ++i)
+ for(size_t i = 0; i < g_num_daemons; ++i)
{
io_array[i].d = g_daemons[i];
io_array[i].request_type = request_type;
struct pollfd fds[g_num_daemons];
memset(fds, 0, sizeof(fds));
nfds = 0;
- for(int i = 0; i < g_num_daemons; ++i)
+ for(size_t i = 0; i < g_num_daemons; ++i)
{
struct cconn *io = io_array + i;
ret = cconn_prepare(io, fds + nfds);
if(ret < 0)
{
- WARNING("ceph plugin: cconn_prepare(name=%s,i=%d,st=%d)=%d",
+ WARNING("ceph plugin: cconn_prepare(name=%s,i=%zu,st=%d)=%d",
io->d->name, i, io->state, ret);
cconn_close(io);
io->request_type = ASOK_REQ_NONE;
if(revents == 0)
{
/* do nothing */
+ continue;
}
else if(cconn_validate_revents(io, revents))
{
}
}
}
- done: for(int i = 0; i < g_num_daemons; ++i)
+ done: for(size_t i = 0; i < g_num_daemons; ++i)
{
cconn_close(io_array + i);
}
static int ceph_init(void)
{
int ret;
+
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_DAC_OVERRIDE)
+ if (check_capability (CAP_DAC_OVERRIDE) != 0)
+ {
+ if (getuid () == 0)
+ WARNING ("ceph plugin: Running collectd as root, but the "
+ "CAP_DAC_OVERRIDE capability is missing. The plugin's read "
+ "function will probably fail. Is your init system dropping "
+ "capabilities?");
+ else
+ WARNING ("ceph plugin: collectd doesn't have the CAP_DAC_OVERRIDE "
+ "capability. If you don't want to run collectd as root, try running "
+ "\"setcap cap_dac_override=ep\" on the collectd binary.");
+ }
+#endif
+
ceph_daemons_print();
ret = cconn_main_loop(ASOK_REQ_VERSION);
static int ceph_shutdown(void)
{
- for(int i = 0; i < g_num_daemons; ++i)
+ for(size_t i = 0; i < g_num_daemons; ++i)
{
ceph_daemon_free(g_daemons[i]);
}
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_mount.h"
#include "utils_ignorelist.h"
if (chrony_set_timeout())
{
- ERROR(PLUGIN_NAME ": Error setting timeout to %lds. Errno = %d",
- g_chrony_timeout, errno);
+ ERROR(PLUGIN_NAME ": Error setting timeout to %llds. Errno = %d",
+ (long long)g_chrony_timeout, errno);
return CHRONY_RC_FAIL;
}
return CHRONY_RC_OK;
--- /dev/null
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# 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-lua - Documentation of collectd's C<Lua plugin>
+
+=head1 SYNOPSIS
+
+ LoadPlugin lua
+ # ...
+ <Plugin lua>
+ BasePath "/path/to/your/lua/scripts"
+ Script "script1.lua"
+ Script "script2.lua"
+ </Plugin>
+
+=head1 DESCRIPTION
+
+The C<Lua plugin> embeds a Lua interpreter into collectd and provides an
+interface to collectd's plugin system. This makes it possible to write plugins
+for collectd in Lua. This is a lot more efficient than executing a
+Lua script every time you want to read a value with the C<exec plugin> (see
+L<collectd-exec(5)>) and provides a lot more functionality, too.
+
+The minimum required Lua version is I<5.1>.
+
+=head1 CONFIGURATION
+
+=over 4
+
+=item B<LoadPlugin> I<Lua>
+
+Loads the Lua plugin.
+
+=item B<BasePath> I<Name>
+
+The directory the C<Lua plugin> looks in to find script B<Script>.
+If set, this is also prepended to B<package.path>.
+
+=item B<Script> I<Name>
+
+The script the C<Lua plugin> is going to run.
+If B<BasePath> is not specified, this needs to be an absolute path.
+
+=back
+
+=head1 WRITING YOUR OWN PLUGINS
+
+Writing your own plugins is quite simple. collectd manages plugins by means of
+B<dispatch functions> which call the appropriate B<callback functions>
+registered by the plugins. Any plugin basically consists of the implementation
+of these callback functions and initializing code which registers the
+functions with collectd. See the section "EXAMPLES" below for a really basic
+example. The following types of B<callback functions> are implemented in the
+Lua plugin (all of them are optional):
+
+=over 4
+
+=item read functions
+
+These are used to collect the actual data. It is called once
+per interval (see the B<Interval> configuration option of collectd). Usually
+it will call B<collectd.dispatch_values> to dispatch the values to collectd
+which will pass them on to all registered B<write functions>. If this function
+does not return 0 the plugin will be skipped for an increasing
+amount of time until it returns normally again.
+
+=item write functions
+
+These are used to write the dispatched values. They are called
+once for every value that was dispatched by any plugin.
+
+=back
+
+=head1 FUNCTIONS
+
+The following functions are provided to Lua modules:
+
+=over 4
+
+=item register_read(callback)
+
+The callback will be called without arguments.
+If this callback function does not return 0 the next call will be delayed by
+an increasing interval.
+
+=item register_write
+
+The callback function will be called with one argument passed, which will be a
+table of values.
+If this callback function does not return 0 next call will be delayed by
+an increasing interval.
+
+=item log_error, log_warning, log_notice, log_info, log_debug(I<message>)
+
+Log a message with the specified severity.
+
+=back
+
+=head1 EXAMPLES
+
+=over 4
+
+A very simple read function might look like:
+
+ function read()
+ collectd.log_info("read function called")
+ t = {
+ host = 'localhost',
+ plugin = 'myplugin',
+ type = 'counter',
+ values = {42},
+ }
+ collectd.dispatch_values(t)
+ return 0
+ end
+
+A very simple write function might look like:
+
+ function write(vl)
+ for i = 1, #vl.values do
+ collectd.log_info(vl.host .. '.' .. vl.plugin .. '.' .. vl.type .. ' ' .. vl.values[i])
+ end
+ return 0
+ end
+
+To register those functions with collectd:
+
+ collectd.register_read(read)
+ collectd.register_write(write)
+
+=back
+
+=head1 SEE ALSO
+
+L<collectd(1)>,
+L<collectd.conf(5)>,
+L<lua(1)>,
+
+=head1 AUTHOR
+
+The C<Lua plugin> has been written by
+Julien Ammous E<lt>j.ammous<nbsp>atE<nbsp>gmail.comE<gt>,
+Florian Forster E<lt>octoE<nbsp>atE<nbsp>collectd.orgE<gt> and
+Ruben Kerkhof E<lt>ruben<nbsp>atE<nbsp>rubenkerkhof.com<gt> and
+
+This manpage has been written by Ruben Kerkhof
+E<lt>ruben<nbsp>atE<nbsp>rubenkerkhof.com<gt>.
+It is based on the L<collectd-perl(5)> manual page by
+Florian Forster E<lt>octoE<nbsp>atE<nbsp>collectd.orgE<gt> and
+Sebastian Harl E<lt>shE<nbsp>atE<nbsp>tokkee.orgE<gt>.
+
+=cut
#@BUILD_PLUGIN_JAVA_TRUE@LoadPlugin java
@BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
#@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
+#@BUILD_PLUGIN_LUA_TRUE@LoadPlugin lua
#@BUILD_PLUGIN_LVM_TRUE@LoadPlugin lvm
#@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
#@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
#</Plugin>
#<Plugin grpc>
-# WorkerThreads 5
+# <Server "example.com" "50051">
+# EnableSSL true
+# SSLCACertificateFile "/path/to/root.pem"
+# SSLCertificateFile "/path/to/server.pem"
+# SSLCertificateKeyFile "/path/to/server.key"
+# </Server>
# <Listen "0.0.0.0" "50051">
# EnableSSL true
-# SSLRootCerts "/path/to/root.pem"
-# SSLServerCert "/path/to/server.pem"
-# SSLServerKey "/path/to/server.key"
+# SSLCACertificateFile "/path/to/root.pem"
+# SSLCertificateFile "/path/to/client.pem"
+# SSLCertificateKeyFile "/path/to/client.key"
# </Listen>
#</Plugin>
# ReportBySerial false
#</Plugin>
+#<Plugin lua>
+# BasePath "@prefix@/share/@PACKAGE_NAME@/lua"
+# Script "script1.lua"
+# Script "script2.lua"
+#</Plugin>
+
#<Plugin madwifi>
# Interface "wlan0"
# IgnoreSelected false
# User "db_user"
# Password "secret"
# Database "db_name"
+# SSLKey "/path/to/key.pem"
+# SSLCert "/path/to/cert.pem"
+# SSLCA "/path/to/ca.pem"
+# SSLCAPath "/path/to/cas/"
+# SSLCipher "DHE-RSA-AES256-SHA"
# MasterStats true
# ConnectTimeout 10
# InnodbStats true
Jiffies. By setting this option to B<true>, you can request percentage values
in the un-aggregated (per-CPU, per-state) mode as well.
+=item B<ReportNumCpu> B<false>|B<true>
+
+When set to B<true>, reports the number of available CPUs.
+Defaults to B<false>.
+
=back
=head2 Plugin C<cpufreq>
=over 4
+=item B<Host> I<Name>
+
+Use I<Name> as the host name when submitting values. Defaults to the global
+host name setting.
+
=item B<Instance> I<Instance>
Sets the plugin instance to I<Instance>.
=over 4
+=item B<Server> I<Host> I<Port>
+
+The B<Server> statement sets the address of a server to which to send metrics
+via the C<DispatchValues> function.
+
+The argument I<Host> may be a hostname, an IPv4 address, or an IPv6 address.
+
+Optionally, B<Server> may be specified as a configuration block which supports
+the following options:
+
+=over 4
+
+=item B<EnableSSL> B<false>|B<true>
+
+Whether to require SSL for outgoing connections. Default: false.
+
+=item B<SSLCACertificateFile> I<Filename>
+
+=item B<SSLCertificateFile> I<Filename>
+
+=item B<SSLCertificateKeyFile> I<Filename>
+
+Filenames specifying SSL certificate and key material to be used with SSL
+connections.
+
+=back
+
=item B<Listen> I<Host> I<Port>
The B<Listen> statement sets the network address to bind to. When multiple
Whether to enable SSL for incoming connections. Default: false.
-=item B<SSLRootCerts> I<Filename>
+=item B<SSLCACertificateFile> I<Filename>
-=item B<SSLServerKey> I<Filename>
+=item B<SSLCertificateFile> I<Filename>
-=item B<SSLServerCert> I<Filename>
+=item B<SSLCertificateKeyFile> I<Filename>
Filenames specifying SSL certificate and key material to be used with SSL
connections.
=back
-=item B<WorkerThreads> I<Num>
-
-Number of threads to start for handling incoming connections. The default
-value is B<5>.
-
=back
=head2 Plugin C<hddtemp>
=back
+=head2 Plugin C<lua>
+
+This plugin embeds a Lua interpreter into collectd and provides an interface
+to collectd's plugin system. See L<collectd-lua(5)> for its documentation.
+
+
=head2 Plugin C<mbmon>
The C<mbmon plugin> uses mbmon to retrieve temperature, voltage, etc.
Port "3306"
MasterStats true
ConnectTimeout 10
+ SSLKey "/path/to/key.pem"
+ SSLCert "/path/to/cert.pem"
+ SSLCA "/path/to/ca.pem"
+ SSLCAPath "/path/to/cas/"
+ SSLCipher "DHE-RSA-AES256-SHA"
</Database>
<Database bar>
A B<Database> block defines one connection to a MySQL database. It accepts a
single argument which specifies the name of the database. None of the other
options are required. MySQL will use default values as documented in the
-section "mysql_real_connect()" in the B<MySQL reference manual>.
+"mysql_real_connect()" and "mysql_ssl_set()" sections in the
+B<MySQL reference manual>.
=over 4
Sets the connect timeout for the MySQL client.
+=item B<SSLKey> I<Path>
+
+If provided, the X509 key in PEM format.
+
+=item B<SSLCert> I<Path>
+
+If provided, the X509 cert in PEM format.
+
+=item B<SSLCA> I<Path>
+
+If provided, the CA file in PEM format (check OpenSSL docs).
+
+=item B<SSLCAPath> I<Path>
+
+If provided, the CA directory (check OpenSSL docs).
+
+=item B<SSLCipher> I<String>
+
+If provided, the SSL cipher to use.
+
=back
=head2 Plugin C<netapp>
#include "libcollectdclient/collectd/client.h"
+#ifndef PREFIX
+# define PREFIX "/opt/" PACKAGE_NAME
+#endif
+
+#ifndef LOCALSTATEDIR
+# define LOCALSTATEDIR PREFIX "/var"
+#endif
+
#define DEFAULT_SOCK LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock"
extern char *optarg;
#include <unistd.h>
+#ifndef PREFIX
+# define PREFIX "/opt/" PACKAGE_NAME
+#endif
+
+#ifndef LOCALSTATEDIR
+# define LOCALSTATEDIR PREFIX "/var"
+#endif
+
#ifndef COLLECTDMON_PIDFILE
# define COLLECTDMON_PIDFILE LOCALSTATEDIR"/run/collectdmon.pid"
#endif /* ! COLLECTDMON_PIDFILE */
static _Bool report_by_cpu = 1;
static _Bool report_by_state = 1;
static _Bool report_percent = 0;
+static _Bool report_num_cpu = 0;
static const char *config_keys[] =
{
"ReportByCpu",
"ReportByState",
+ "ReportNumCpu",
"ValuesPercentage"
};
static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
report_percent = IS_TRUE (value) ? 1 : 0;
else if (strcasecmp (key, "ReportByState") == 0)
report_by_state = IS_TRUE (value) ? 1 : 0;
+ else if (strcasecmp (key, "ReportNumCpu") == 0)
+ report_num_cpu = IS_TRUE (value) ? 1 : 0;
else
return (-1);
}
} /* }}} void cpu_commit_one */
+/* Commits the number of cores */
+static void cpu_commit_num_cpu (gauge_t num_cpu) /* {{{ */
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = num_cpu;
+
+ vl.values = values;
+ vl.values_len = 1;
+
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
+ sstrncpy (vl.type, "count", sizeof (vl.type));
+
+ plugin_dispatch_values (&vl);
+} /* }}} void cpu_commit_num_cpu */
+
/* Resets the internal aggregation. This is called by the read callback after
* each iteration / after each call to cpu_commit(). */
static void cpu_reset (void) /* {{{ */
NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */
};
+ if (report_num_cpu)
+ cpu_commit_num_cpu ((gauge_t) global_cpu_num);
+
if (report_by_state && report_by_cpu && !report_percent)
{
cpu_commit_without_aggregation ();
host_t cpu_host;
- for (int cpu = 0; cpu < cpu_list_len; cpu++)
+ for (mach_msg_type_number_t cpu = 0; cpu < cpu_list_len; cpu++)
{
cpu_host = 0;
cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_curl_stats.h"
#include "utils_match.h"
#include "utils_time.h"
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_avltree.h"
#include "utils_complain.h"
#include "utils_curl_stats.h"
/* If all went well, register this database for reading */
if (status == 0)
{
- user_data_t ud = { 0 };
char *cb_name;
if (db->instance == NULL)
DEBUG ("curl_json plugin: Registering new read callback: %s",
db->instance);
- ud.data = (void *) db;
- ud.free_func = cj_free;
-
cb_name = ssnprintf_alloc ("curl_json-%s-%s",
db->instance, db->url ? db->url : db->sock);
+ user_data_t ud = {
+ .data = db,
+ .free_func = cj_free
+ };
+
plugin_register_complex_read (/* group = */ NULL, cb_name, cj_read,
/* interval = */ db->interval,
&ud);
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_curl_stats.h"
#include "utils_llist.h"
/* If all went well, register this database for reading */
if (status == 0)
{
- user_data_t ud = { 0 };
char *cb_name;
if (db->instance == NULL)
DEBUG ("curl_xml plugin: Registering new read callback: %s",
db->instance);
- ud.data = (void *) db;
- ud.free_func = cx_free;
-
cb_name = ssnprintf_alloc ("curl_xml-%s-%s", db->instance, db->url);
+
+ user_data_t ud = {
+ .data = db,
+ .free_func = cx_free
+ };
+
plugin_register_complex_read (/* group = */ "curl_xml", cb_name, cx_read,
/* interval = */ 0, &ud);
sfree (cb_name);
# include <netinet/in.h>
#endif
+#if HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+
/* for ntohl and htonl */
#if HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
#ifdef HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
#endif
return (-1);
} /* int service_name_to_port_number */
+void set_sock_opts (int sockfd) /* {{{ */
+{
+ int status;
+ int socktype;
+
+ socklen_t socklen = sizeof (socklen_t);
+ int so_keepalive = 1;
+
+ status = getsockopt (sockfd, SOL_SOCKET, SO_TYPE, &socktype, &socklen);
+ if (status != 0)
+ {
+ WARNING ("set_sock_opts: failed to determine socket type");
+ return;
+ }
+
+ if (socktype == SOCK_STREAM)
+ {
+ status = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+ &so_keepalive, sizeof (so_keepalive));
+ if (status != 0)
+ WARNING ("set_sock_opts: failed to set socket keepalive flag");
+
+#ifdef TCP_KEEPIDLE
+ int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1);
+ status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
+ &tcp_keepidle, sizeof (tcp_keepidle));
+ if (status != 0)
+ WARNING ("set_sock_opts: failed to set socket tcp keepalive time");
+#endif
+
+#ifdef TCP_KEEPINTVL
+ int tcp_keepintvl = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 1000 + 1);
+ status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
+ &tcp_keepintvl, sizeof (tcp_keepintvl));
+ if (status != 0)
+ WARNING ("set_sock_opts: failed to set socket tcp keepalive interval");
+#endif
+ }
+} /* }}} void set_sock_opts */
+
int strtoderive (const char *string, derive_t *ret_value) /* {{{ */
{
derive_t tmp;
sfree (array[i]);
sfree (array);
} /* }}} void strarray_free */
+
+#ifdef HAVE_SYS_CAPABILITY_H
+int check_capability (int capability) /* {{{ */
+{
+#ifdef _LINUX_CAPABILITY_VERSION_3
+ cap_user_header_t cap_header = calloc(1, sizeof (*cap_header));
+ if (cap_header == NULL)
+ {
+ ERROR("check_capability: calloc failed");
+ return (-1);
+ }
+
+ cap_user_data_t cap_data = calloc(1, sizeof (*cap_data));
+ if (cap_data == NULL)
+ {
+ ERROR("check_capability: calloc failed");
+ sfree(cap_header);
+ return (-1);
+ }
+
+ cap_header->pid = getpid();
+ cap_header->version = _LINUX_CAPABILITY_VERSION;
+ if (capget(cap_header, cap_data) < 0)
+ {
+ ERROR("check_capability: capget failed");
+ sfree(cap_header);
+ sfree(cap_data);
+ return (-1);
+ }
+
+ if ((cap_data->effective & (1 << capability)) == 0)
+ {
+ sfree(cap_header);
+ sfree(cap_data);
+ return (-1);
+ }
+ else
+ {
+ sfree(cap_header);
+ sfree(cap_data);
+ return (0);
+ }
+#else
+ WARNING ("check_capability: unsupported capability implementation. "
+ "Some plugin(s) may require elevated privileges to work properly.");
+ return (0);
+#endif /* _LINUX_CAPABILITY_VERSION_3 */
+} /* }}} int check_capability */
+#endif /* HAVE_SYS_CAPABILITY_H */
* (in the range [1-65535]). Returns less than zero on error. */
int service_name_to_port_number (const char *service_name);
+/* Sets various, non-default, socket options */
+void set_sock_opts (int sockfd);
+
/** Parse a string to a derive_t value. Returns zero on success or non-zero on
* failure. If failure is returned, ret_value is not touched. */
int strtoderive (const char *string, derive_t *ret_value);
int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str);
void strarray_free (char **array, size_t array_len);
+#ifdef HAVE_SYS_CAPABILITY_H
+/** Check if the current process benefits from the capability passed in
+ * argument. Returns zero if it does, less than zero if it doesn't or on error.
+ * See capabilities(7) for the list of possible capabilities.
+ * */
+int check_capability (int capability);
+#endif /* HAVE_SYS_CAPABILITY_H */
+
#endif /* COMMON_H */
int global_option_set (const char *option, const char *value, _Bool from_cli);
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 global_option_get_time (char const *option, cdtime_t default_value);
typedef int (*plugin_shutdown_cb) (void);
typedef int (*plugin_notification_cb) (const notification_t *,
user_data_t *);
-
/*
* NAME
* plugin_set_dir
#include "plugin.h"
/* vcomplain returns 0 if it did not report, 1 else */
+__attribute__ ((format (printf, 3, 0)))
static int vcomplain (int level, c_complain_t *c,
const char *format, va_list ap)
{
if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC)
{
- data->value.counter++;
+ data->value.derive++;
data->values_num++;
return (0);
}
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_db_query.h"
#include <dbi/dbi.h>
}
else
{
- user_data_t ud = { 0 };
char *name = NULL;
databases = temp;
databases[databases_num] = db;
databases_num++;
- ud.data = (void *) db;
- ud.free_func = NULL;
name = ssnprintf_alloc("dbi:%s", db->name);
+ user_data_t ud = {
+ .data = db
+ };
+
plugin_register_complex_read (/* group = */ NULL,
/* name = */ name ? name : db->name,
/* callback = */ cdbi_read_database,
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_mount.h"
#include "utils_ignorelist.h"
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_dns.h"
#include <poll.h>
#include <pcap.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
/*
* Private data types
*/
listen_thread_init = 1;
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_RAW)
+ if (check_capability (CAP_NET_RAW) != 0)
+ {
+ if (getuid () == 0)
+ WARNING ("dns plugin: Running collectd as root, but the CAP_NET_RAW "
+ "capability is missing. The plugin's read function will probably "
+ "fail. Is your init system dropping capabilities?");
+ else
+ WARNING ("dns plugin: collectd doesn't have the CAP_NET_RAW capability. "
+ "If you don't want to run collectd as root, try running \"setcap "
+ "cap_net_raw=ep\" on the collectd binary.");
+ }
+#endif
+
return (0);
} /* int dns_init */
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
-
#include <stddef.h>
#include <sys/un.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_avltree.h"
#include "utils_complain.h"
#include <grp.h>
#include <signal.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
#define PL_NORMAL 0x01
#define PL_NOTIF_ACTION 0x02
sigaction (SIGCHLD, &sa, NULL);
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SETUID) && defined(CAP_SETGID)
+ if ((check_capability (CAP_SETUID) != 0) ||
+ (check_capability (CAP_SETGID) != 0))
+ {
+ if (getuid () == 0)
+ WARNING ("exec plugin: Running collectd as root, but the CAP_SETUID "
+ "or CAP_SETGID capabilities are missing. The plugin's read function "
+ "will probably fail. Is your init system dropping capabilities?");
+ else
+ WARNING ("exec plugin: collectd doesn't have the CAP_SETUID or "
+ "CAP_SETGID capabilities. If you don't want to run collectd as root, "
+ "try running \"setcap 'cap_setuid=ep cap_setgid=ep'\" on the "
+ "collectd binary.");
+ }
+#endif
+
return (0);
} /* int exec_init }}} */
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
static const char *config_keys[] = {
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include "utils_avltree.h"
#if HAVE_NETDB_H
#include "common.h"
#include "plugin.h"
#include "utils_time.h"
-#include "configfile.h"
#define CGPS_TRUE 1
#define CGPS_FALSE 0
#include <fstream>
#include <iostream>
+#include <queue>
#include <vector>
#include "collectd.grpc.pb.h"
#include "collectd.h"
#include "common.h"
-#include "configfile.h"
#include "plugin.h"
#include "daemon/utils_cache.h"
using collectd::Collectd;
using collectd::DispatchValuesRequest;
-using collectd::DispatchValuesReply;
+using collectd::DispatchValuesResponse;
using collectd::QueryValuesRequest;
-using collectd::QueryValuesReply;
+using collectd::QueryValuesResponse;
using google::protobuf::util::TimeUtil;
msg->set_allocated_interval(new google::protobuf::Duration(d));
for (size_t i = 0; i < vl->values_len; ++i) {
- auto v = msg->add_value();
+ auto v = msg->add_values();
switch (ds->ds[i].type) {
case DS_TYPE_COUNTER:
v->set_counter(vl->values[i].counter);
return grpc::Status(grpc::StatusCode::INTERNAL,
grpc::string("unknown value type"));
}
+
+ auto name = msg->add_ds_names();
+ name->assign(ds->ds[i].name);
}
return grpc::Status::OK;
size_t values_len = 0;
status = grpc::Status::OK;
- for (auto v : msg.value()) {
+ for (auto v : msg.values()) {
value_t *val = (value_t *)realloc(values, (values_len + 1) * sizeof(*values));
if (!val) {
status = grpc::Status(grpc::StatusCode::RESOURCE_EXHAUSTED,
} /* unmarshal_value_list() */
/*
- * request call-backs and call objects
+ * Collectd service
*/
-
-static grpc::Status Process(grpc::ServerContext *ctx,
- DispatchValuesRequest request, DispatchValuesReply *reply)
-{
- value_list_t vl = VALUE_LIST_INIT;
- auto status = unmarshal_value_list(request.values(), &vl);
- if (!status.ok())
- return status;
-
- if (plugin_dispatch_values(&vl))
- status = grpc::Status(grpc::StatusCode::INTERNAL,
- grpc::string("failed to enqueue values for writing"));
- return status;
-} /* Process(): DispatchValues */
-
-static grpc::Status Process(grpc::ServerContext *ctx,
- QueryValuesRequest request, QueryValuesReply *reply)
-{
- uc_iter_t *iter;
- char *name = NULL;
-
- value_list_t matcher;
- auto status = unmarshal_ident(request.identifier(), &matcher, false);
- if (!status.ok())
- return status;
-
- if ((iter = uc_get_iterator()) == NULL) {
- return grpc::Status(grpc::StatusCode::INTERNAL,
- grpc::string("failed to query values: cannot create iterator"));
- }
-
- status = grpc::Status::OK;
- while (uc_iterator_next(iter, &name) == 0) {
- value_list_t res;
- if (parse_identifier_vl(name, &res) != 0) {
- status = grpc::Status(grpc::StatusCode::INTERNAL,
- grpc::string("failed to parse identifier"));
- break;
+class CollectdImpl : public collectd::Collectd::Service {
+public:
+ grpc::Status QueryValues(grpc::ServerContext *ctx, QueryValuesRequest const *req, grpc::ServerWriter<QueryValuesResponse> *writer) override {
+ value_list_t match;
+ auto status = unmarshal_ident(req->identifier(), &match, false);
+ if (!status.ok()) {
+ return status;
}
- if (!ident_matches(&res, &matcher))
- continue;
-
- if (uc_iterator_get_time(iter, &res.time) < 0) {
- status = grpc::Status(grpc::StatusCode::INTERNAL,
- grpc::string("failed to retrieve value timestamp"));
- break;
+ std::queue<value_list_t> value_lists;
+ status = this->queryValuesRead(&match, &value_lists);
+ if (status.ok()) {
+ status = this->queryValuesWrite(ctx, writer, &value_lists);
}
- if (uc_iterator_get_interval(iter, &res.interval) < 0) {
- status = grpc::Status(grpc::StatusCode::INTERNAL,
- grpc::string("failed to retrieve value interval"));
- break;
- }
- if (uc_iterator_get_values(iter, &res.values, &res.values_len) < 0) {
- status = grpc::Status(grpc::StatusCode::INTERNAL,
- grpc::string("failed to retrieve values"));
- break;
+
+ while (!value_lists.empty()) {
+ auto vl = value_lists.front();
+ value_lists.pop();
+ sfree(vl.values);
}
- auto vl = reply->add_values();
- status = marshal_value_list(&res, vl);
- free(res.values);
- if (!status.ok())
- break;
+ return status;
}
- uc_iterator_destroy(iter);
+ grpc::Status DispatchValues(grpc::ServerContext *ctx,
+ grpc::ServerReader<DispatchValuesRequest> *reader,
+ DispatchValuesResponse *res) override {
+ DispatchValuesRequest req;
- return status;
-} /* Process(): QueryValues */
-
-class Call
-{
-public:
- Call(Collectd::AsyncService *service, grpc::ServerCompletionQueue *cq)
- : service_(service), cq_(cq), status_(CREATE)
- { }
-
- virtual ~Call()
- { }
+ while (reader->Read(&req)) {
+ value_list_t vl = VALUE_LIST_INIT;
+ auto status = unmarshal_value_list(req.value_list(), &vl);
+ if (!status.ok())
+ return status;
- void Handle()
- {
- if (status_ == CREATE) {
- Create();
- status_ = PROCESS;
- }
- else if (status_ == PROCESS) {
- Process();
- status_ = FINISH;
- }
- else {
- GPR_ASSERT(status_ == FINISH);
- Finish();
+ if (plugin_dispatch_values(&vl))
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("failed to enqueue values for writing"));
}
- } /* Handle() */
-
-protected:
- virtual void Create() = 0;
- virtual void Process() = 0;
- virtual void Finish() = 0;
- Collectd::AsyncService *service_;
- grpc::ServerCompletionQueue *cq_;
- grpc::ServerContext ctx_;
+ res->Clear();
+ return grpc::Status::OK;
+ }
private:
- enum CallStatus { CREATE, PROCESS, FINISH };
- CallStatus status_;
-}; /* class Call */
+ grpc::Status queryValuesRead(value_list_t const *match, std::queue<value_list_t> *value_lists) {
+ uc_iter_t *iter;
+ if ((iter = uc_get_iterator()) == NULL) {
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("failed to query values: cannot create iterator"));
+ }
-template<typename RequestT, typename ReplyT>
-class RpcCall final : public Call
-{
- typedef void (Collectd::AsyncService::*CreatorT)(grpc::ServerContext *,
- RequestT *, grpc::ServerAsyncResponseWriter<ReplyT> *,
- grpc::CompletionQueue *, grpc::ServerCompletionQueue *, void *);
+ grpc::Status status = grpc::Status::OK;
+ char *name = NULL;
+ while (uc_iterator_next(iter, &name) == 0) {
+ value_list_t vl;
+ if (parse_identifier_vl(name, &vl) != 0) {
+ status = grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("failed to parse identifier"));
+ break;
+ }
-public:
- RpcCall(Collectd::AsyncService *service,
- CreatorT creator, grpc::ServerCompletionQueue *cq)
- : Call(service, cq), creator_(creator), responder_(&ctx_)
- {
- Handle();
- } /* RpcCall() */
+ if (!ident_matches(&vl, match))
+ continue;
- virtual ~RpcCall()
- { }
+ if (uc_iterator_get_time(iter, &vl.time) < 0) {
+ status = grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("failed to retrieve value timestamp"));
+ break;
+ }
+ if (uc_iterator_get_interval(iter, &vl.interval) < 0) {
+ status = grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("failed to retrieve value interval"));
+ break;
+ }
+ if (uc_iterator_get_values(iter, &vl.values, &vl.values_len) < 0) {
+ status = grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("failed to retrieve values"));
+ break;
+ }
-private:
- void Create()
- {
- (service_->*creator_)(&ctx_, &request_, &responder_, cq_, cq_, this);
- } /* Create() */
+ value_lists->push(vl);
+ } // while (uc_iterator_next(iter, &name) == 0)
- void Process()
- {
- // Add a new request object to the queue.
- new RpcCall<RequestT, ReplyT>(service_, creator_, cq_);
- grpc::Status status = ::Process(&ctx_, request_, &reply_);
- responder_.Finish(reply_, status, this);
- } /* Process() */
+ uc_iterator_destroy(iter);
+ return status;
+ }
- void Finish()
- {
- delete this;
- } /* Finish() */
+ grpc::Status queryValuesWrite(grpc::ServerContext *ctx,
+ grpc::ServerWriter<QueryValuesResponse> *writer,
+ std::queue<value_list_t> *value_lists) {
+ while (!value_lists->empty()) {
+ auto vl = value_lists->front();
+ QueryValuesResponse res;
+ res.Clear();
+
+ auto status = marshal_value_list(&vl, res.mutable_value_list());
+ if (!status.ok()) {
+ return status;
+ }
- CreatorT creator_;
+ if (!writer->Write(res)) {
+ return grpc::Status::CANCELLED;
+ }
- RequestT request_;
- ReplyT reply_;
+ value_lists->pop();
+ sfree(vl.values);
+ }
- grpc::ServerAsyncResponseWriter<ReplyT> responder_;
-}; /* class RpcCall */
+ return grpc::Status::OK;
+ }
+};
/*
* gRPC server implementation
*/
-
class CollectdServer final
{
public:
}
}
- builder.RegisterService(&service_);
- cq_ = builder.AddCompletionQueue();
+ builder.RegisterService(&collectd_service_);
+
server_ = builder.BuildAndStart();
} /* Start() */
void Shutdown()
{
server_->Shutdown();
- cq_->Shutdown();
} /* Shutdown() */
- void Mainloop()
- {
- // Register request types.
- new RpcCall<DispatchValuesRequest, DispatchValuesReply>(&service_,
- &Collectd::AsyncService::RequestDispatchValues, cq_.get());
- new RpcCall<QueryValuesRequest, QueryValuesReply>(&service_,
- &Collectd::AsyncService::RequestQueryValues, cq_.get());
-
- while (true) {
- void *req = NULL;
- bool ok = false;
-
- if (!cq_->Next(&req, &ok))
- break; // Queue shut down.
- if (!ok) {
- ERROR("grpc: Failed to read from queue");
- break;
- }
-
- static_cast<Call *>(req)->Handle();
- }
- } /* Mainloop() */
-
private:
- Collectd::AsyncService service_;
+ CollectdImpl collectd_service_;
std::unique_ptr<grpc::Server> server_;
- std::unique_ptr<grpc::ServerCompletionQueue> cq_;
}; /* class CollectdServer */
+class CollectdClient final
+{
+public:
+ CollectdClient(std::shared_ptr<grpc::ChannelInterface> channel) : stub_(Collectd::NewStub(channel)) {
+ }
+
+ int DispatchValues(value_list_t const *vl) {
+ grpc::ClientContext ctx;
+
+ DispatchValuesRequest req;
+ auto status = marshal_value_list(vl, req.mutable_value_list());
+ if (!status.ok()) {
+ ERROR("grpc: Marshalling value_list_t failed.");
+ return -1;
+ }
+
+ DispatchValuesResponse res;
+ auto stream = stub_->DispatchValues(&ctx, &res);
+ if (!stream->Write(req)) {
+ NOTICE("grpc: Broken stream.");
+ /* intentionally not returning. */
+ }
+
+ stream->WritesDone();
+ status = stream->Finish();
+ if (!status.ok()) {
+ ERROR ("grpc: Error while closing stream.");
+ return -1;
+ }
+
+ return 0;
+ } /* int DispatchValues */
+
+private:
+ std::unique_ptr<Collectd::Stub> stub_;
+};
+
static CollectdServer *server = nullptr;
/*
* collectd plugin interface
*/
-
extern "C" {
- static pthread_t *workers;
- static size_t workers_num = 5;
+ static void c_grpc_destroy_write_callback (void *ptr) {
+ delete (CollectdClient *) ptr;
+ }
- static void *worker_thread(void *arg)
- {
- CollectdServer *s = (CollectdServer *)arg;
- s->Mainloop();
- return NULL;
- } /* worker_thread() */
+ static int c_grpc_write(__attribute__((unused)) data_set_t const *ds,
+ value_list_t const *vl,
+ user_data_t *ud) {
+ CollectdClient *c = (CollectdClient *) ud->data;
+ return c->DispatchValues(vl);
+ }
static int c_grpc_config_listen(oconfig_item_t *ci)
{
return -1;
}
}
- else if (!strcasecmp("SSLRootCerts", child->key)) {
+ else if (!strcasecmp("SSLCACertificateFile", child->key)) {
char *certs = NULL;
if (cf_util_get_string(child, &certs)) {
ERROR("grpc: Option `%s` expects a string value",
}
ssl_opts->pem_root_certs = read_file(certs);
}
- else if (!strcasecmp("SSLServerKey", child->key)) {
+ else if (!strcasecmp("SSLCertificateKeyFile", child->key)) {
char *key = NULL;
if (cf_util_get_string(child, &key)) {
ERROR("grpc: Option `%s` expects a string value",
}
pkcp.private_key = read_file(key);
}
- else if (!strcasecmp("SSLServerCert", child->key)) {
+ else if (!strcasecmp("SSLCertificateFile", child->key)) {
char *cert = NULL;
if (cf_util_get_string(child, &cert)) {
ERROR("grpc: Option `%s` expects a string value",
return 0;
} /* c_grpc_config_listen() */
+ static int c_grpc_config_server(oconfig_item_t *ci)
+ {
+ if ((ci->values_num != 2)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || (ci->values[1].type != OCONFIG_TYPE_STRING)) {
+ ERROR("grpc: The `%s` config option needs exactly "
+ "two string argument (address and port).", ci->key);
+ return -1;
+ }
+
+ grpc::SslCredentialsOptions ssl_opts;
+ bool use_ssl = false;
+
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (!strcasecmp("EnableSSL", child->key)) {
+ if (cf_util_get_boolean(child, &use_ssl)) {
+ return -1;
+ }
+ }
+ else if (!strcasecmp("SSLCACertificateFile", child->key)) {
+ char *certs = NULL;
+ if (cf_util_get_string(child, &certs)) {
+ return -1;
+ }
+ ssl_opts.pem_root_certs = read_file(certs);
+ }
+ else if (!strcasecmp("SSLCertificateKeyFile", child->key)) {
+ char *key = NULL;
+ if (cf_util_get_string(child, &key)) {
+ return -1;
+ }
+ ssl_opts.pem_private_key = read_file(key);
+ }
+ else if (!strcasecmp("SSLCertificateFile", child->key)) {
+ char *cert = NULL;
+ if (cf_util_get_string(child, &cert)) {
+ return -1;
+ }
+ ssl_opts.pem_cert_chain = read_file(cert);
+ }
+ else {
+ WARNING("grpc: Option `%s` not allowed in <%s> block.",
+ child->key, ci->key);
+ }
+ }
+
+ auto node = grpc::string(ci->values[0].value.string);
+ auto service = grpc::string(ci->values[1].value.string);
+ auto addr = node + ":" + service;
+
+ CollectdClient *client;
+ if (use_ssl) {
+ auto channel_creds = grpc::SslCredentials(ssl_opts);
+ auto channel = grpc::CreateChannel(addr, channel_creds);
+ client = new CollectdClient(channel);
+ } else {
+ auto channel = grpc::CreateChannel(addr, grpc::InsecureChannelCredentials());
+ client = new CollectdClient(channel);
+ }
+
+ auto callback_name = grpc::string("grpc/") + addr;
+ user_data_t ud = {
+ .data = client,
+ .free_func = c_grpc_destroy_write_callback,
+ };
+
+ plugin_register_write (callback_name.c_str(), c_grpc_write, &ud);
+ return 0;
+ } /* c_grpc_config_server() */
+
static int c_grpc_config(oconfig_item_t *ci)
{
int i;
if (c_grpc_config_listen(child))
return -1;
}
- else if (!strcasecmp("WorkerThreads", child->key)) {
- int n;
- if (cf_util_get_int(child, &n))
+ else if (!strcasecmp("Server", child->key)) {
+ if (c_grpc_config_server(child))
return -1;
- workers_num = (size_t)n;
}
+
else {
WARNING("grpc: Option `%s` not allowed here.", child->key);
}
static int c_grpc_init(void)
{
server = new CollectdServer();
- size_t i;
-
- if (! server) {
+ if (!server) {
ERROR("grpc: Failed to create server");
return -1;
}
- workers = (pthread_t *)calloc(workers_num, sizeof(*workers));
- if (! workers) {
- delete server;
- server = nullptr;
-
- ERROR("grpc: Failed to allocate worker threads");
- return -1;
- }
-
server->Start();
- for (i = 0; i < workers_num; i++) {
- plugin_thread_create(&workers[i], /* attr = */ NULL,
- worker_thread, server);
- }
- INFO("grpc: Started %zu workers", workers_num);
return 0;
} /* c_grpc_init() */
static int c_grpc_shutdown(void)
{
- size_t i;
-
if (!server)
- return -1;
+ return 0;
server->Shutdown();
- INFO("grpc: Waiting for %zu workers to terminate", workers_num);
- for (i = 0; i < workers_num; i++)
- pthread_join(workers[i], NULL);
- free(workers);
- workers = NULL;
- workers_num = 0;
-
delete server;
server = nullptr;
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
# include <netdb.h>
# include <netinet/in.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_ignorelist.h"
#if HAVE_SYS_TYPES_H
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#if KERNEL_LINUX
/* _GNU_SOURCE is needed for struct shm_info.used_ids on musl libc */
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <libiptc/libiptc.h>
#include <libiptc/libip6tc.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
/*
* iptc_handle_t was available before libiptc was officially available as a
* shared library. Note, that when the shared lib was introduced, the API and
return (0);
} /* int iptables_shutdown */
+static int iptables_init (void)
+{
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_ADMIN)
+ if (check_capability (CAP_NET_ADMIN) != 0)
+ {
+ if (getuid () == 0)
+ WARNING ("iptables plugin: Running collectd as root, but the "
+ "CAP_NET_ADMIN capability is missing. The plugin's read "
+ "function will probably fail. Is your init system dropping "
+ "capabilities?");
+ else
+ WARNING ("iptables plugin: collectd doesn't have the CAP_NET_ADMIN "
+ "capability. If you don't want to run collectd as root, try "
+ "running \"setcap cap_net_admin=ep\" on the collectd binary.");
+ }
+#endif
+ return (0);
+} /* int iptables_init */
+
void module_register (void)
{
plugin_register_config ("iptables", iptables_config,
config_keys, config_keys_num);
+ plugin_register_init ("iptables", iptables_init);
plugin_register_read ("iptables", iptables_read);
plugin_register_shutdown ("iptables", iptables_shutdown);
} /* void module_register */
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_ignorelist.h"
#if !KERNEL_LINUX
static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */
jobject this, jobject o_name, jobject o_read)
{
- user_data_t ud = { 0 };
cjni_callback_info_t *cbi;
cbi = cjni_callback_info_create (jvm_env, o_name, o_read, CB_TYPE_READ);
DEBUG ("java plugin: Registering new read callback: %s", cbi->name);
- ud.data = (void *) cbi;
- ud.free_func = cjni_callback_info_destroy;
+ user_data_t ud = {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy
+ };
plugin_register_complex_read (/* group = */ NULL, cbi->name, cjni_read,
/* interval = */ 0, &ud);
static jint JNICALL cjni_api_register_write (JNIEnv *jvm_env, /* {{{ */
jobject this, jobject o_name, jobject o_write)
{
- user_data_t ud = { 0 };
cjni_callback_info_t *cbi;
cbi = cjni_callback_info_create (jvm_env, o_name, o_write, CB_TYPE_WRITE);
DEBUG ("java plugin: Registering new write callback: %s", cbi->name);
- ud.data = (void *) cbi;
- ud.free_func = cjni_callback_info_destroy;
+ user_data_t ud = {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy
+ };
plugin_register_write (cbi->name, cjni_write, &ud);
static jint JNICALL cjni_api_register_flush (JNIEnv *jvm_env, /* {{{ */
jobject this, jobject o_name, jobject o_flush)
{
- user_data_t ud = { 0 };
cjni_callback_info_t *cbi;
cbi = cjni_callback_info_create (jvm_env, o_name, o_flush, CB_TYPE_FLUSH);
DEBUG ("java plugin: Registering new flush callback: %s", cbi->name);
- ud.data = (void *) cbi;
- ud.free_func = cjni_callback_info_destroy;
+ user_data_t ud = {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy
+ };
plugin_register_flush (cbi->name, cjni_flush, &ud);
static jint JNICALL cjni_api_register_log (JNIEnv *jvm_env, /* {{{ */
jobject this, jobject o_name, jobject o_log)
{
- user_data_t ud = { 0 };
cjni_callback_info_t *cbi;
cbi = cjni_callback_info_create (jvm_env, o_name, o_log, CB_TYPE_LOG);
DEBUG ("java plugin: Registering new log callback: %s", cbi->name);
- ud.data = (void *) cbi;
- ud.free_func = cjni_callback_info_destroy;
+ user_data_t ud = {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy
+ };
plugin_register_log (cbi->name, cjni_log, &ud);
static jint JNICALL cjni_api_register_notification (JNIEnv *jvm_env, /* {{{ */
jobject this, jobject o_name, jobject o_notification)
{
- user_data_t ud = { 0 };
cjni_callback_info_t *cbi;
cbi = cjni_callback_info_create (jvm_env, o_name, o_notification,
DEBUG ("java plugin: Registering new notification callback: %s", cbi->name);
- ud.data = (void *) cbi;
- ud.free_func = cjni_callback_info_destroy;
+ user_data_t ud = {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy
+ };
plugin_register_notification (cbi->name, cjni_notification, &ud);
/*
* Private functions
*/
+__attribute__ ((format (printf, 1, 0)))
static int lcc_tracef(char const *format, ...)
{
va_list ap;
yyin = fd;
} /* void yyset_in */
-oconfig_item_t *oconfig_parse_fh (FILE *fh)
+static oconfig_item_t *oconfig_parse_fh (FILE *fh)
{
int status;
oconfig_item_t *ret;
/*
* Functions
*/
-oconfig_item_t *oconfig_parse_fh (FILE *fh);
oconfig_item_t *oconfig_parse_file (const char *file);
oconfig_item_t *oconfig_clone (const oconfig_item_t *ci);
#include "aux_types.h"
#include "parser.h"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsign-compare"
+
/* multiline string buffer */
static char *ml_buffer = NULL;
static int ml_pos = 0;
return;
} /* ml_append */
+#pragma clang diagnostic pop
+#pragma GCC diagnostic pop
--- /dev/null
+/**
+ * collectd - src/lua.c
+ * Copyright (C) 2010 Julien Ammous
+ * Copyright (C) 2010 Florian Forster
+ * Copyright (C) 2016 Ruben Kerkhof
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Julien Ammous
+ * Florian Forster <octo at collectd.org>
+ * Ruben Kerkhof <ruben at rubenkerkhof.com>
+ **/
+
+/* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
+ * GCC will complain about the macro definition. */
+#define DONT_POISON_SPRINTF_YET
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+/* Include the Lua API header files. */
+#include "utils_lua.h"
+#include <lauxlib.h>
+#include <lua.h>
+#include <lualib.h>
+
+#include <pthread.h>
+
+#if COLLECT_DEBUG && __GNUC__
+#undef sprintf
+#pragma GCC poison sprintf
+#endif
+
+typedef struct lua_script_s {
+ char *script_path;
+ lua_State *lua_state;
+ struct lua_script_s *next;
+} lua_script_t;
+
+typedef struct {
+ lua_State *lua_state;
+ const char *lua_function_name;
+ pthread_mutex_t lock;
+ int callback_id;
+} clua_callback_data_t;
+
+static char base_path[PATH_MAX];
+static lua_script_t *scripts;
+
+static int clua_store_callback(lua_State *L, int idx) /* {{{ */
+{
+ /* Copy the function pointer */
+ lua_pushvalue(L, idx);
+
+ return luaL_ref(L, LUA_REGISTRYINDEX);
+} /* }}} int clua_store_callback */
+
+static int clua_load_callback(lua_State *L, int callback_ref) /* {{{ */
+{
+ lua_rawgeti(L, LUA_REGISTRYINDEX, callback_ref);
+
+ if (!lua_isfunction(L, -1)) {
+ lua_pop(L, 1);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int clua_load_callback */
+
+/* Store the threads in a global variable so they are not cleaned up by the
+ * garbage collector. */
+static int clua_store_thread(lua_State *L, int idx) /* {{{ */
+{
+ if (idx < 0)
+ idx += lua_gettop(L) + 1;
+
+ /* Copy the thread pointer */
+ lua_pushvalue(L, idx); /* +1 = 3 */
+ if (!lua_isthread(L, -1)) {
+ lua_pop(L, 3); /* -3 = 0 */
+ return (-1);
+ }
+
+ luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_pop(L, 1); /* -1 = 0 */
+ return (0);
+} /* }}} int clua_store_thread */
+
+static int clua_read(user_data_t *ud) /* {{{ */
+{
+ clua_callback_data_t *cb = ud->data;
+
+ pthread_mutex_lock(&cb->lock);
+
+ lua_State *L = cb->lua_state;
+
+ int status = clua_load_callback(L, cb->callback_id);
+ if (status != 0) {
+ ERROR("Lua plugin: Unable to load callback \"%s\" (id %i).",
+ cb->lua_function_name, cb->callback_id);
+ pthread_mutex_unlock(&cb->lock);
+ return (-1);
+ }
+ /* +1 = 1 */
+
+ status = lua_pcall(L, 0, 1, 0);
+ if (status != 0) {
+ const char *errmsg = lua_tostring(L, -1);
+ if (errmsg == NULL)
+ ERROR("Lua plugin: Calling a read callback failed. "
+ "In addition, retrieving the error message failed.");
+ else
+ ERROR("Lua plugin: Calling a read callback failed: %s", errmsg);
+ lua_pop(L, 1);
+ pthread_mutex_unlock(&cb->lock);
+ return (-1);
+ }
+
+ if (!lua_isnumber(L, -1)) {
+ ERROR("Lua plugin: Read function \"%s\" (id %i) did not return a numeric "
+ "status.",
+ cb->lua_function_name, cb->callback_id);
+ status = -1;
+ } else {
+ status = (int)lua_tointeger(L, -1);
+ }
+
+ /* pop return value and function */
+ lua_pop(L, 1); /* -1 = 0 */
+
+ pthread_mutex_unlock(&cb->lock);
+ return (status);
+} /* }}} int clua_read */
+
+static int clua_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
+ user_data_t *ud) {
+ clua_callback_data_t *cb = ud->data;
+
+ pthread_mutex_lock(&cb->lock);
+
+ lua_State *L = cb->lua_state;
+
+ int status = clua_load_callback(L, cb->callback_id);
+ if (status != 0) {
+ ERROR("Lua plugin: Unable to load callback \"%s\" (id %i).",
+ cb->lua_function_name, cb->callback_id);
+ pthread_mutex_unlock(&cb->lock);
+ return (-1);
+ }
+ /* +1 = 1 */
+
+ status = luaC_pushvaluelist(L, ds, vl);
+ if (status != 0) {
+ lua_pop(L, 1); /* -1 = 0 */
+ pthread_mutex_unlock(&cb->lock);
+ ERROR("Lua plugin: luaC_pushvaluelist failed.");
+ return (-1);
+ }
+ /* +1 = 2 */
+
+ status = lua_pcall(L, 1, 1, 0); /* -2+1 = 1 */
+ if (status != 0) {
+ const char *errmsg = lua_tostring(L, -1);
+ if (errmsg == NULL)
+ ERROR("Lua plugin: Calling the write callback failed. "
+ "In addition, retrieving the error message failed.");
+ else
+ ERROR("Lua plugin: Calling the write callback failed:\n%s", errmsg);
+ lua_pop(L, 1); /* -1 = 0 */
+ pthread_mutex_unlock(&cb->lock);
+ return (-1);
+ }
+
+ if (!lua_isnumber(L, -1)) {
+ ERROR("Lua plugin: Write function \"%s\" (id %i) did not return a numeric "
+ "value.",
+ cb->lua_function_name, cb->callback_id);
+ status = -1;
+ } else {
+ status = (int)lua_tointeger(L, -1);
+ }
+
+ lua_pop(L, 1); /* -1 = 0 */
+ pthread_mutex_unlock(&cb->lock);
+ return (status);
+} /* }}} int clua_write */
+
+/*
+ * Exported functions
+ */
+
+static int lua_cb_log_debug(lua_State *L) /* {{{ */
+{
+ const char *msg = luaL_checkstring(L, 1);
+ plugin_log(LOG_DEBUG, "%s", msg);
+ return 0;
+} /* }}} int lua_cb_log_debug */
+
+static int lua_cb_log_error(lua_State *L) /* {{{ */
+{
+ const char *msg = luaL_checkstring(L, 1);
+ plugin_log(LOG_ERR, "%s", msg);
+ return 0;
+} /* }}} int lua_cb_log_error */
+
+static int lua_cb_log_info(lua_State *L) /* {{{ */
+{
+ const char *msg = luaL_checkstring(L, 1);
+ plugin_log(LOG_INFO, "%s", msg);
+ return 0;
+} /* }}} int lua_cb_log_info */
+
+static int lua_cb_log_notice(lua_State *L) /* {{{ */
+{
+ const char *msg = luaL_checkstring(L, 1);
+ plugin_log(LOG_NOTICE, "%s", msg);
+ return 0;
+} /* }}} int lua_cb_log_notice */
+
+static int lua_cb_log_warning(lua_State *L) /* {{{ */
+{
+ const char *msg = luaL_checkstring(L, 1);
+ plugin_log(LOG_WARNING, "%s", msg);
+ return 0;
+} /* }}} int lua_cb_log_warning */
+
+static int lua_cb_dispatch_values(lua_State *L) /* {{{ */
+{
+ int nargs = lua_gettop(L);
+
+ if (nargs != 1)
+ return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+
+ luaL_checktype(L, 1, LUA_TTABLE);
+
+ value_list_t *vl = luaC_tovaluelist(L, -1);
+ if (vl == NULL)
+ return luaL_error(L, "%s", "luaC_tovaluelist failed");
+
+#if COLLECT_DEBUG
+ char identifier[6 * DATA_MAX_NAME_LEN];
+ FORMAT_VL(identifier, sizeof(identifier), vl);
+
+ DEBUG("Lua plugin: collectd.dispatch_values(): Received value list \"%s\", "
+ "time %.3f, interval %.3f.",
+ identifier, CDTIME_T_TO_DOUBLE(vl->time),
+ CDTIME_T_TO_DOUBLE(vl->interval));
+#endif
+
+ plugin_dispatch_values(vl);
+
+ sfree(vl->values);
+ sfree(vl);
+ return 0;
+} /* }}} lua_cb_dispatch_values */
+
+static int lua_cb_register_read(lua_State *L) /* {{{ */
+{
+ int nargs = lua_gettop(L);
+
+ if (nargs != 1)
+ return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+
+ char function_name[DATA_MAX_NAME_LEN];
+ ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
+
+ int callback_id = clua_store_callback(L, 1);
+ if (callback_id < 0)
+ return luaL_error(L, "%s", "Storing callback function failed");
+
+ lua_State *thread = lua_newthread(L);
+ if (thread == NULL)
+ return luaL_error(L, "%s", "lua_newthread failed");
+ clua_store_thread(L, -1);
+ lua_pop(L, 1);
+
+ clua_callback_data_t *cb = calloc(1, sizeof(*cb));
+ if (cb == NULL)
+ return luaL_error(L, "%s", "calloc failed");
+
+ cb->lua_state = thread;
+ cb->callback_id = callback_id;
+ cb->lua_function_name = strdup(function_name);
+ pthread_mutex_init(&cb->lock, NULL);
+
+ user_data_t ud = {
+ .data = cb
+ };
+
+ int status = plugin_register_complex_read(/* group = */ "lua",
+ /* name = */ function_name,
+ /* callback = */ clua_read,
+ /* interval = */ 0,
+ /* user_data = */ &ud);
+
+ if (status != 0)
+ return luaL_error(L, "%s", "plugin_register_complex_read failed");
+ return 0;
+} /* }}} int lua_cb_register_read */
+
+static int lua_cb_register_write(lua_State *L) /* {{{ */
+{
+ int nargs = lua_gettop(L);
+
+ if (nargs != 1)
+ return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+
+ char function_name[DATA_MAX_NAME_LEN] = "";
+ ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
+
+ int callback_id = clua_store_callback(L, 1);
+ if (callback_id < 0)
+ return luaL_error(L, "%s", "Storing callback function failed");
+
+ lua_State *thread = lua_newthread(L);
+ if (thread == NULL)
+ return luaL_error(L, "%s", "lua_newthread failed");
+ clua_store_thread(L, -1);
+ lua_pop(L, 1);
+
+ clua_callback_data_t *cb = calloc(1, sizeof(*cb));
+ if (cb == NULL)
+ return luaL_error(L, "%s", "calloc failed");
+
+ cb->lua_state = thread;
+ cb->callback_id = callback_id;
+ cb->lua_function_name = strdup(function_name);
+ pthread_mutex_init(&cb->lock, NULL);
+
+ user_data_t ud = {
+ .data = cb
+ };
+
+ int status = plugin_register_write(/* name = */ function_name,
+ /* callback = */ clua_write,
+ /* user_data = */ &ud);
+
+ if (status != 0)
+ return luaL_error(L, "%s", "plugin_register_write failed");
+ return 0;
+} /* }}} int lua_cb_register_write */
+
+static const luaL_Reg collectdlib[] = {
+ {"log_debug", lua_cb_log_debug},
+ {"log_error", lua_cb_log_error},
+ {"log_info", lua_cb_log_info},
+ {"log_notice", lua_cb_log_notice},
+ {"log_warning", lua_cb_log_warning},
+ {"dispatch_values", lua_cb_dispatch_values},
+ {"register_read", lua_cb_register_read},
+ {"register_write", lua_cb_register_write},
+ {NULL, NULL}
+};
+
+static int open_collectd(lua_State *L) /* {{{ */
+{
+#if LUA_VERSION_NUM < 502
+ luaL_register(L, "collectd", collectdlib);
+#else
+ luaL_newlib(L, collectdlib);
+#endif
+ return 1;
+} /* }}} */
+
+static void lua_script_free(lua_script_t *script) /* {{{ */
+{
+ if (script == NULL)
+ return;
+
+ lua_script_t *next = script->next;
+
+ if (script->lua_state != NULL) {
+ lua_close(script->lua_state);
+ script->lua_state = NULL;
+ }
+
+ sfree(script->script_path);
+ sfree(script);
+
+ lua_script_free(next);
+} /* }}} void lua_script_free */
+
+static int lua_script_init(lua_script_t *script) /* {{{ */
+{
+ memset(script, 0, sizeof(*script));
+
+ /* initialize the lua context */
+ script->lua_state = luaL_newstate();
+ if (script->lua_state == NULL) {
+ ERROR("Lua plugin: luaL_newstate() failed.");
+ return (-1);
+ }
+
+ /* Open up all the standard Lua libraries. */
+ luaL_openlibs(script->lua_state);
+
+ /* Load the 'collectd' library */
+#if LUA_VERSION_NUM < 502
+ lua_pushcfunction(script->lua_state, open_collectd);
+ lua_pushstring(script->lua_state, "collectd");
+ lua_call(script->lua_state, 1, 0);
+#else
+ luaL_requiref(script->lua_state, "collectd", open_collectd, 1);
+ lua_pop(script->lua_state, 1);
+#endif
+
+ /* Prepend BasePath to package.path */
+ if (base_path[0] != '\0') {
+ lua_getglobal(script->lua_state, "package");
+ lua_getfield(script->lua_state, -1, "path");
+
+ const char *cur_path = lua_tostring(script->lua_state, -1);
+ char *new_path = ssnprintf_alloc("%s/?.lua;%s", base_path, cur_path);
+
+ lua_pop(script->lua_state, 1);
+ lua_pushstring(script->lua_state, new_path);
+
+ free(new_path);
+
+ lua_setfield(script->lua_state, -2, "path");
+ lua_pop(script->lua_state, 1);
+ }
+
+ return (0);
+} /* }}} int lua_script_init */
+
+static int lua_script_load(const char *script_path) /* {{{ */
+{
+ lua_script_t *script = malloc(sizeof(*script));
+ if (script == NULL) {
+ ERROR("Lua plugin: malloc failed.");
+ return (-1);
+ }
+
+ int status = lua_script_init(script);
+ if (status != 0) {
+ lua_script_free(script);
+ return (status);
+ }
+
+ script->script_path = strdup(script_path);
+ if (script->script_path == NULL) {
+ ERROR("Lua plugin: strdup failed.");
+ lua_script_free(script);
+ return (-1);
+ }
+
+ status = luaL_loadfile(script->lua_state, script->script_path);
+ if (status != 0) {
+ ERROR("Lua plugin: luaL_loadfile failed: %s",
+ lua_tostring(script->lua_state, -1));
+ lua_pop(script->lua_state, 1);
+ lua_script_free(script);
+ return (-1);
+ }
+
+ status = lua_pcall(script->lua_state,
+ /* nargs = */ 0,
+ /* nresults = */ LUA_MULTRET,
+ /* errfunc = */ 0);
+ if (status != 0) {
+ const char *errmsg = lua_tostring(script->lua_state, -1);
+
+ if (errmsg == NULL)
+ ERROR("Lua plugin: lua_pcall failed with status %i. "
+ "In addition, no error message could be retrieved from the stack.",
+ status);
+ else
+ ERROR("Lua plugin: Executing script \"%s\" failed:\n%s",
+ script->script_path, errmsg);
+
+ lua_script_free(script);
+ return (-1);
+ }
+
+ /* Append this script to the global list of scripts. */
+ if (scripts) {
+ lua_script_t *last = scripts;
+ while (last->next)
+ last = last->next;
+
+ last->next = script;
+ } else {
+ scripts = script;
+ }
+
+ return (0);
+} /* }}} int lua_script_load */
+
+static int lua_config_base_path(const oconfig_item_t *ci) /* {{{ */
+{
+ int status = cf_util_get_string_buffer(ci, base_path, sizeof(base_path));
+ if (status != 0)
+ return (status);
+
+ size_t len = strlen(base_path);
+ while ((len > 0) && (base_path[len - 1] == '/')) {
+ len--;
+ base_path[len] = '\0';
+ }
+
+ DEBUG("Lua plugin: base_path = \"%s\";", base_path);
+
+ return (0);
+} /* }}} int lua_config_base_path */
+
+static int lua_config_script(const oconfig_item_t *ci) /* {{{ */
+{
+ char rel_path[PATH_MAX];
+
+ int status = cf_util_get_string_buffer(ci, rel_path, sizeof(rel_path));
+ if (status != 0)
+ return (status);
+
+ char abs_path[PATH_MAX];
+
+ if (base_path[0] == '\0')
+ sstrncpy(abs_path, rel_path, sizeof(abs_path));
+ else
+ ssnprintf(abs_path, sizeof(abs_path), "%s/%s", base_path, rel_path);
+
+ DEBUG("Lua plugin: abs_path = \"%s\";", abs_path);
+
+ status = lua_script_load(abs_path);
+ if (status != 0)
+ return (status);
+
+ INFO("Lua plugin: File \"%s\" loaded succesfully", abs_path);
+
+ return 0;
+} /* }}} int lua_config_script */
+
+/*
+ * <Plugin lua>
+ * BasePath "/"
+ * Script "script1.lua"
+ * Script "script2.lua"
+ * </Plugin>
+ */
+static int lua_config(oconfig_item_t *ci) /* {{{ */
+{
+ int status = 0;
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp("BasePath", child->key) == 0) {
+ status = lua_config_base_path(child);
+ } else if (strcasecmp("Script", child->key) == 0) {
+ status = lua_config_script(child);
+ } else {
+ ERROR("Lua plugin: Option `%s' is not allowed here.", child->key);
+ status = 1;
+ }
+ }
+
+ return status;
+} /* }}} int lua_config */
+
+static int lua_shutdown(void) /* {{{ */
+{
+ lua_script_free(scripts);
+
+ return (0);
+} /* }}} int lua_shutdown */
+
+void module_register(void) {
+ plugin_register_complex_config("lua", lua_config);
+ plugin_register_shutdown("lua", lua_shutdown);
+}
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_ignorelist.h"
#include <dirent.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <netdb.h>
#include <netinet/in.h>
#include <linux/major.h>
#include <linux/raid/md_u.h>
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
+
#define PROC_DISKSTATS "/proc/diskstats"
#define DEV_DIR "/dev"
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_match.h"
#include <libmemcached/memcached.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <netdb.h>
#include <sys/un.h>
static int memcached_add_read_callback (memcached_t *st)
{
- user_data_t ud = { 0 };
char callback_name[3*DATA_MAX_NAME_LEN];
int status;
- ud.data = st;
- ud.free_func = memcached_free;
-
assert (st->name != NULL);
ssnprintf (callback_name, sizeof (callback_name), "memcached/%s", st->name);
+ user_data_t ud = {
+ .data = st,
+ .free_func = memcached_free
+ };
+
status = plugin_register_complex_read (/* group = */ "memcached",
/* name = */ callback_name,
/* callback = */ memcached_read,
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <netdb.h>
{
mqtt_client_conf_t *conf;
char cb_name[1024];
- user_data_t user_data = { 0 };
int status;
conf = calloc (1, sizeof (*conf));
}
ssnprintf (cb_name, sizeof (cb_name), "mqtt/%s", conf->name);
- user_data.data = conf;
+ user_data_t user_data = {
+ .data = conf
+ };
plugin_register_write (cb_name, mqtt_write, &user_data);
return (0);
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#ifdef HAVE_MYSQL_H
#include <mysql.h>
char *user;
char *pass;
char *database;
+
+ /* mysql_ssl_set params */
+ char *key;
+ char *cert;
+ char *ca;
+ char *capath;
+ char *cipher;
+
char *socket;
int port;
int timeout;
sfree (db->socket);
sfree (db->instance);
sfree (db->database);
+ sfree (db->key);
+ sfree (db->cert);
+ sfree (db->ca);
+ sfree (db->capath);
+ sfree (db->cipher);
sfree (db);
} /* }}} void mysql_database_free */
db->user = NULL;
db->pass = NULL;
db->database = NULL;
+ db->key = NULL;
+ db->cert = NULL;
+ db->ca = NULL;
+ db->capath = NULL;
+ db->cipher = NULL;
+
db->socket = NULL;
db->con = NULL;
db->timeout = 0;
status = cf_util_get_string (child, &db->socket);
else if (strcasecmp ("Database", child->key) == 0)
status = cf_util_get_string (child, &db->database);
+ else if (strcasecmp ("SSLKey", child->key) == 0)
+ status = cf_util_get_string (child, &db->key);
+ else if (strcasecmp ("SSLCert", child->key) == 0)
+ status = cf_util_get_string (child, &db->cert);
+ else if (strcasecmp ("SSLCA", child->key) == 0)
+ status = cf_util_get_string (child, &db->ca);
+ else if (strcasecmp ("SSLCAPath", child->key) == 0)
+ status = cf_util_get_string (child, &db->capath);
+ else if (strcasecmp ("SSLCipher", child->key) == 0)
+ status = cf_util_get_string (child, &db->cipher);
else if (strcasecmp ("ConnectTimeout", child->key) == 0)
status = cf_util_get_int (child, &db->timeout);
else if (strcasecmp ("MasterStats", child->key) == 0)
/* If all went well, register this database for reading */
if (status == 0)
{
- user_data_t ud = { 0 };
char cb_name[DATA_MAX_NAME_LEN];
DEBUG ("mysql plugin: Registering new read callback: %s",
(db->database != NULL) ? db->database : "<default>");
- ud.data = (void *) db;
- ud.free_func = mysql_database_free;
-
if (db->instance != NULL)
ssnprintf (cb_name, sizeof (cb_name), "mysql-%s",
db->instance);
else
sstrncpy (cb_name, "mysql", sizeof (cb_name));
+ user_data_t ud = {
+ .data = db,
+ .free_func = mysql_database_free
+ };
+
plugin_register_complex_read (/* group = */ NULL, cb_name,
mysql_read,
/* interval = */ 0, &ud);
static MYSQL *getconnection (mysql_database_t *db)
{
+ const char *cipher;
+
if (db->is_connected)
{
int status;
/* Configure TCP connect timeout (default: 0) */
db->con->options.connect_timeout = db->timeout;
+ mysql_ssl_set (db->con, db->key, db->cert, db->ca, db->capath, db->cipher);
+
if (mysql_real_connect (db->con, db->host, db->user, db->pass,
db->database, db->port, db->socket, 0) == NULL)
{
return (NULL);
}
+ cipher = mysql_get_ssl_cipher (db->con);
+
INFO ("mysql plugin: Successfully connected to database %s "
- "at server %s (server version: %s, protocol version: %d)",
+ "at server %s with cipher %s "
+ "(server version: %s, protocol version: %d) ",
(db->database != NULL) ? db->database : "<none>",
mysql_get_host_info (db->con),
+ (cipher != NULL) ? cipher : "<none>",
mysql_get_server_info (db->con),
mysql_get_proto_info (db->con));
counter_submit ("mysql_sort", "scan", val, db);
}
- else if (strncmp (key, "Slow_queries", strlen ("Slow_queries")) == 0)
+ else if (strncmp (key, "Slow_queries", strlen ("Slow_queries")) == 0)
{
counter_submit ("mysql_slow_queries", NULL , val, db);
}
static int cna_register_host (host_config_t *host) /* {{{ */
{
char cb_name[256];
- user_data_t ud = { 0 };
if (host->vfiler)
ssnprintf (cb_name, sizeof (cb_name), "netapp-%s-%s",
else
ssnprintf (cb_name, sizeof (cb_name), "netapp-%s", host->name);
- ud.data = host;
- ud.free_func = (void (*) (void *)) free_host_config;
+ user_data_t ud = {
+ .data = host,
+ .free_func = (void (*) (void *)) free_host_config
+ };
plugin_register_complex_read (/* group = */ NULL, cb_name,
/* callback = */ cna_read,
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include "utils_fbhash.h"
#include "utils_cache.h"
#include "utils_complain.h"
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <curl/curl.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <glib.h>
#include <libnotify/notify.h>
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#define NAGIOS_OK 0
#define NAGIOS_WARNING 1
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#if HAVE_STDINT_H
# include <stdint.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#if defined(__APPLE__)
#pragma clang diagnostic push
}
else
{
- user_data_t ud = { 0 };
char callback_name[3*DATA_MAX_NAME_LEN] = { 0 };
databases = temp;
databases[databases_num] = st;
databases_num++;
- ud.data = st;
-
ssnprintf (callback_name, sizeof (callback_name),
"openldap/%s/%s",
(st->host != NULL) ? st->host : hostname_g,
- (st->name != NULL) ? st->name : "default"),
+ (st->name != NULL) ? st->name : "default");
+
+ user_data_t ud = {
+ .data = st
+ };
status = plugin_register_complex_read (/* group = */ NULL,
/* name = */ callback_name,
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_db_query.h"
#include <oci.h>
#undef DONT_POISON_SPRINTF_YET
-#include "configfile.h"
-
#if HAVE_STDBOOL_H
# include <stdbool.h>
#endif
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <netdb.h>
#include <poll.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_complain.h"
#include <netinet/in.h>
# include <netdb.h> /* NI_MAXHOST */
#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+# include <sys/capability.h>
+#endif
+
#include <oping.h>
#ifndef NI_MAXHOST
"Will use a timeout of %gs.", ping_timeout);
}
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_RAW)
+ if (check_capability (CAP_NET_RAW) != 0)
+ {
+ if (getuid () == 0)
+ WARNING ("ping plugin: Running collectd as root, but the CAP_NET_RAW "
+ "capability is missing. The plugin's read function will probably "
+ "fail. Is your init system dropping capabilities?");
+ else
+ WARNING ("ping plugin: collectd doesn't have the CAP_NET_RAW capability. "
+ "If you don't want to run collectd as root, try running \"setcap "
+ "cap_net_raw=ep\" on the collectd binary.");
+ }
+#endif
+
return (start_thread ());
} /* }}} int ping_init */
#include "common.h"
-#include "configfile.h"
#include "plugin.h"
#include "utils_cache.h"
c_psql_database_t *db;
char cb_name[DATA_MAX_NAME_LEN];
- user_data_t ud = { 0 };
-
static _Bool have_flush = 0;
if ((1 != ci->values_num)
}
}
- ud.data = db;
- ud.free_func = c_psql_database_delete;
-
ssnprintf (cb_name, sizeof (cb_name), "postgresql-%s", db->instance);
+ user_data_t ud = {
+ .data = db,
+ .free_func = c_psql_database_delete
+ };
+
if (db->queries_num > 0) {
++db->ref_cnt;
plugin_register_complex_read ("postgresql", cb_name, c_psql_read,
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_llist.h"
#include <sys/stat.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
/* Include header files for the mach system, if they exist.. */
#if HAVE_THREAD_INFO
* Tasks are assigned to sets of processors, so that's where you go to
* get a list.
*/
- for (int pset = 0; pset < pset_list_len; pset++)
+ for (mach_msg_type_number_t pset = 0; pset < pset_list_len; pset++)
{
if ((status = host_processor_set_priv (port_host_self,
pset_list[pset],
continue;
}
- for (int task = 0; task < task_list_len; task++)
+ for (mach_msg_type_number_t task = 0; task < task_list_len; task++)
{
ps = NULL;
if (mach_get_task_name (task_list[task],
continue; /* with next task_list */
}
- for (int thread = 0; thread < thread_list_len; thread++)
+ for (mach_msg_type_number_t thread = 0; thread < thread_list_len; thread++)
{
thread_data_len = THREAD_BASIC_INFO_COUNT;
status = thread_info (thread_list[thread],
}
dict = PyDict_New(); /* New reference. */
if (value_list->meta) {
- int num;
char **table;
meta_data_t *meta = value_list->meta;
- num = meta_data_toc(meta, &table);
- for (size_t i = 0; i < num; ++i) {
+ int num = meta_data_toc(meta, &table);
+ for (int i = 0; i < num; ++i) {
int type;
char *string;
int64_t si;
char buf[512];
reg_function_t *register_function = (reg_function_t *) reg;
cpy_callback_t *c = NULL;
- user_data_t user_data = { 0 };
char *name = NULL;
PyObject *callback = NULL, *data = NULL;
static char *kwlist[] = {"callback", "data", "name", NULL};
c->data = data;
c->next = NULL;
- user_data.free_func = cpy_destroy_user_data;
- user_data.data = c;
+ user_data_t user_data = {
+ .data = c,
+ .free_func = cpy_destroy_user_data
+ };
register_function(buf, handler, &user_data);
return cpy_string_to_unicode_or_bytes(buf);
static PyObject *cpy_register_read(PyObject *self, PyObject *args, PyObject *kwds) {
char buf[512];
cpy_callback_t *c = NULL;
- user_data_t user_data = { 0 };
double interval = 0;
char *name = NULL;
PyObject *callback = NULL, *data = NULL;
c->data = data;
c->next = NULL;
- user_data.free_func = cpy_destroy_user_data;
- user_data.data = c;
+ user_data_t user_data = {
+ .data = c,
+ .free_func = cpy_destroy_user_data
+ };
plugin_register_complex_read(/* group = */ "python", buf,
cpy_read_callback, DOUBLE_TO_CDTIME_T (interval), &user_data);
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include <sys/time.h>
#include <hiredis/hiredis.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_ignorelist.h"
#if defined(HAVE_SENSORS_SENSORS_H)
/* Registration stuff. */
char cb_name[DATA_MAX_NAME_LEN];
- user_data_t cb_data = { 0 };
hd = calloc (1, sizeof (*hd));
if (hd == NULL)
ssnprintf (cb_name, sizeof (cb_name), "snmp-%s", hd->name);
- cb_data.data = hd;
- cb_data.free_func = csnmp_host_definition_destroy;
+ user_data_t ud = {
+ .data = hd,
+ .free_func = csnmp_host_definition_destroy
+ };
status = plugin_register_complex_read (/* group = */ NULL, cb_name,
- csnmp_read_host, hd->interval, /* user_data = */ &cb_data);
+ csnmp_read_host, hd->interval, /* user_data = */ &ud);
if (status != 0)
{
ERROR ("snmp plugin: Registering complex read function failed.");
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include "utils_avltree.h"
#include "utils_latency.h"
{
ERROR ("swap plugin: Total swap space (%g) is less than used swap space (%g).",
total, used);
+ sfree (swap_entries);
return (-1);
}
#include "common.h"
-#include "configfile.h"
#include "plugin.h"
#define log_err(...) ERROR ("table plugin: " __VA_ARGS__)
static int ctail_init (void)
{
char str[255];
- user_data_t ud = { 0 };
if (tail_match_list_num == 0)
{
for (size_t i = 0; i < tail_match_list_num; i++)
{
- ud.data = (void *)tail_match_list[i];
ssnprintf(str, sizeof(str), "tail-%zu", i);
+
+ user_data_t ud = {
+ .data = tail_match_list[i]
+ };
+
plugin_register_complex_read (NULL, str, ctail_read, tail_match_list_intervals[i], &ud);
}
/* Registration variables */
char cb_name[DATA_MAX_NAME_LEN];
- user_data_t cb_data = { 0 };
id = calloc(1, sizeof(*id));
if (id == NULL)
}
ssnprintf (cb_name, sizeof (cb_name), "tail_csv/%s", id->path);
- cb_data.data = id;
- cb_data.free_func = tcsv_instance_definition_destroy;
- status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval, &cb_data);
+
+ user_data_t ud = {
+ .data = id,
+ .free_func = tcsv_instance_definition_destroy
+ };
+
+ status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval, &ud);
if (status != 0){
ERROR("tail_csv plugin: Registering complex read function failed.");
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#if HAVE_TERMIOS_H && HAVE_SYS_IOCTL_H && HAVE_MATH_H
# include <termios.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_ignorelist.h"
#if !KERNEL_LINUX
static int
check_permissions(void)
{
-#ifdef HAVE_SYS_CAPABILITY_H
- struct __user_cap_header_struct cap_header_data;
- cap_user_header_t cap_header = &cap_header_data;
- struct __user_cap_data_struct cap_data_data;
- cap_user_data_t cap_data = &cap_data_data;
- int ret = 0;
-#endif /* HAVE_SYS_CAPABILITY_H */
if (getuid() == 0) {
/* We have everything we need */
return 0;
-#ifndef HAVE_SYS_CAPABILITY_H
+#if !defined(HAVE_SYS_CAPABILITY_H) && !defined(CAP_SYS_RAWIO)
} else {
ERROR("turbostat plugin: Initialization failed: this plugin "
"requires collectd to run as root");
return -1;
}
-#else /* HAVE_SYS_CAPABILITY_H */
+#else /* HAVE_SYS_CAPABILITY_H && CAP_SYS_RAWIO */
}
- /* check for CAP_SYS_RAWIO */
- cap_header->pid = getpid();
- cap_header->version = _LINUX_CAPABILITY_VERSION;
- if (capget(cap_header, cap_data) < 0) {
- ERROR("turbostat plugin: capget failed");
- return -1;
- }
+ int ret = 0;
- if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
+ if (check_capability(CAP_SYS_RAWIO) != 0) {
WARNING("turbostat plugin: Collectd doesn't have the "
"CAP_SYS_RAWIO capability. If you don't want to run "
"collectd as root, try running \"setcap "
"collectd a special capability (CAP_SYS_RAWIO) and read "
"access to /dev/cpu/*/msr (see previous warnings)");
return ret;
-#endif /* HAVE_SYS_CAPABILITY_H */
+#endif /* HAVE_SYS_CAPABILITY_H && CAP_SYS_RAWIO */
}
static int
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_cmd_flush.h"
#include "utils_cmd_getval.h"
#ifndef UTILS_CURL_STATS_H
#define UTILS_CURL_STATS_H 1
-#include "configfile.h"
#include "plugin.h"
#include <curl/curl.h>
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_db_query.h"
/*
{
int status = strjoin (vl.type_instance, sizeof (vl.type_instance),
r_area->instances_buffer, r->instances_num, "-");
- if (status != 0)
+ if (status < 0)
{
ERROR ("udb_result_submit: creating type_instance failed with status %d.",
status);
int status = strjoin (tmp, sizeof (tmp), r_area->instances_buffer,
r->instances_num, "-");
- if (status != 0)
+ if (status < 0)
{
ERROR ("udb_result_submit: creating type_instance failed with status %d.",
status);
#ifndef UTILS_DB_QUERY_H
#define UTILS_DB_QUERY_H 1
-#include "configfile.h"
-
/*
* Data types
*/
* Florian octo Forster <octo at collectd.org>
*/
+/* Workaround for Solaris 10 defining label_t
+ * Issue #1301
+ */
+#if KERNEL_SOLARIS
+# ifndef _POSIX_C_SOURCE
+# define _POSIX_C_SOURCE 200112L
+# endif
+# undef __EXTENSIONS__
+#endif
+
#include "collectd.h"
#include "testing.h"
if (lc == NULL)
return (NULL);
- latency_counter_reset (lc);
lc->bin_width = HISTOGRAM_DEFAULT_BIN_WIDTH;
+ latency_counter_reset (lc);
return (lc);
} /* }}} latency_counter_t *latency_counter_create */
return;
cdtime_t bin_width = lc->bin_width;
+ cdtime_t max_bin = (lc->max - 1) / lc->bin_width;
+
+/*
+ If max latency is REDUCE_THRESHOLD times less than histogram's range,
+ then cut it in half. REDUCE_THRESHOLD must be >= 2.
+ Value of 4 is selected to reduce frequent changes of bin width.
+*/
+#define REDUCE_THRESHOLD 4
+ if ((lc->num > 0) && (lc->bin_width >= HISTOGRAM_DEFAULT_BIN_WIDTH * 2)
+ && (max_bin < HISTOGRAM_NUM_BINS / REDUCE_THRESHOLD))
+ {
+ /* new bin width will be the previous power of 2 */
+ bin_width = bin_width / 2;
+
+ DEBUG("utils_latency: latency_counter_reset: max_latency = %.3f; "
+ "max_bin = %"PRIu64"; old_bin_width = %.3f; new_bin_width = %.3f;",
+ CDTIME_T_TO_DOUBLE (lc->max),
+ max_bin,
+ CDTIME_T_TO_DOUBLE (lc->bin_width),
+ CDTIME_T_TO_DOUBLE (bin_width));
+ }
+
memset (lc, 0, sizeof (*lc));
/* preserve bin width */
--- /dev/null
+/**
+ * collectd - src/utils_lua.c
+ * Copyright (C) 2010 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <octo at collectd.org>
+ **/
+
+/* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
+ * GCC will complain about the macro definition. */
+#define DONT_POISON_SPRINTF_YET
+
+#include "utils_lua.h"
+#include "common.h"
+
+static int ltoc_values(lua_State *L, /* {{{ */
+ const data_set_t *ds, value_t *ret_values) {
+ if (!lua_istable(L, -1)) {
+ WARNING("ltoc_values: not a table");
+ return (-1);
+ }
+
+ /* Push initial key */
+ lua_pushnil(L); /* +1 = 1 */
+ size_t i = 0;
+ while (lua_next(L, -2) != 0) /* -1+2 = 2 || -1 = 0 */
+ {
+ if (i >= ds->ds_num) {
+ lua_pop(L, 2); /* -2 = 0 */
+ i++;
+ break;
+ }
+
+ ret_values[i] = luaC_tovalue(L, -1, ds->ds[i].type);
+
+ /* Pop the value */
+ lua_pop(L, 1); /* -1 = 1 */
+ i++;
+ } /* while (lua_next) */
+
+ if (i != ds->ds_num) {
+ WARNING("ltoc_values: invalid size for datasource \"%s\": expected %zu, "
+ "got %zu",
+ ds->type, ds->ds_num, i);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int ltoc_values */
+
+static int ltoc_table_values(lua_State *L, int idx, /* {{{ */
+ const data_set_t *ds, value_list_t *vl) {
+ /* We're only called from "luaC_tovaluelist", which ensures that "idx" is an
+ * absolute index (i.e. a positive number) */
+ assert(idx > 0);
+
+ lua_getfield(L, idx, "values");
+ if (!lua_istable(L, -1)) {
+ WARNING("utils_lua: ltoc_table_values: The \"values\" member is a %s "
+ "value, not a table.",
+ lua_typename(L, lua_type(L, -1)));
+ lua_pop(L, 1);
+ return (-1);
+ }
+
+ vl->values_len = ds->ds_num;
+ vl->values = calloc(vl->values_len, sizeof(*vl->values));
+ if (vl->values == NULL) {
+ ERROR("utils_lua: calloc failed.");
+ vl->values_len = 0;
+ lua_pop(L, 1);
+ return (-1);
+ }
+
+ int status = ltoc_values(L, ds, vl->values);
+
+ lua_pop(L, 1);
+
+ if (status != 0) {
+ vl->values_len = 0;
+ sfree(vl->values);
+ }
+
+ return (status);
+} /* }}} int ltoc_table_values */
+
+static int luaC_pushvalues(lua_State *L, const data_set_t *ds,
+ const value_list_t *vl) /* {{{ */
+{
+ assert(vl->values_len == ds->ds_num);
+
+ lua_newtable(L);
+ for (size_t i = 0; i < vl->values_len; i++) {
+ lua_pushinteger(L, (lua_Integer)i + 1);
+ luaC_pushvalue(L, vl->values[i], ds->ds[i].type);
+ lua_settable(L, -3);
+ }
+
+ return (0);
+} /* }}} int luaC_pushvalues */
+
+static int luaC_pushdstypes(lua_State *L, const data_set_t *ds) /* {{{ */
+{
+ lua_newtable(L);
+ for (size_t i = 0; i < ds->ds_num; i++) {
+ lua_pushinteger(L, (lua_Integer)i);
+ lua_pushstring(L, DS_TYPE_TO_STRING(ds->ds[i].type));
+ lua_settable(L, -3);
+ }
+
+ return (0);
+} /* }}} int luaC_pushdstypes */
+
+static int luaC_pushdsnames(lua_State *L, const data_set_t *ds) /* {{{ */
+{
+ lua_newtable(L);
+ for (size_t i = 0; i < ds->ds_num; i++) {
+ lua_pushinteger(L, (lua_Integer)i);
+ lua_pushstring(L, ds->ds[i].name);
+ lua_settable(L, -3);
+ }
+
+ return (0);
+} /* }}} int luaC_pushdsnames */
+
+/*
+ * Public functions
+ */
+cdtime_t luaC_tocdtime(lua_State *L, int idx) /* {{{ */
+{
+ if (!lua_isnumber(L, /* stack pos = */ idx))
+ return (0);
+
+ double d = lua_tonumber(L, idx);
+
+ return (DOUBLE_TO_CDTIME_T(d));
+} /* }}} int ltoc_table_cdtime */
+
+int luaC_tostringbuffer(lua_State *L, int idx, /* {{{ */
+ char *buffer, size_t buffer_size) {
+ const char *str = lua_tostring(L, idx);
+ if (str == NULL)
+ return (-1);
+
+ sstrncpy(buffer, str, buffer_size);
+ return (0);
+} /* }}} int luaC_tostringbuffer */
+
+value_t luaC_tovalue(lua_State *L, int idx, int ds_type) /* {{{ */
+{
+ value_t v = { 0 };
+
+ if (!lua_isnumber(L, idx))
+ return (v);
+
+ if (ds_type == DS_TYPE_GAUGE)
+ v.gauge = (gauge_t)lua_tonumber(L, /* stack pos = */ -1);
+ else if (ds_type == DS_TYPE_DERIVE)
+ v.derive = (derive_t)lua_tointeger(L, /* stack pos = */ -1);
+ else if (ds_type == DS_TYPE_COUNTER)
+ v.counter = (counter_t)lua_tointeger(L, /* stack pos = */ -1);
+ else if (ds_type == DS_TYPE_ABSOLUTE)
+ v.absolute = (absolute_t)lua_tointeger(L, /* stack pos = */ -1);
+
+ return (v);
+} /* }}} value_t luaC_tovalue */
+
+value_list_t *luaC_tovaluelist(lua_State *L, int idx) /* {{{ */
+{
+#if COLLECT_DEBUG
+ int stack_top_before = lua_gettop(L);
+#endif
+
+ /* Convert relative indexes to absolute indexes, so it doesn't change when we
+ * push / pop stuff. */
+ if (idx < 1)
+ idx += lua_gettop(L) + 1;
+
+ /* Check that idx is in the valid range */
+ if ((idx < 1) || (idx > lua_gettop(L))) {
+ DEBUG("luaC_tovaluelist: idx(%d), top(%d)", idx, stack_top_before);
+ return (NULL);
+ }
+
+ value_list_t *vl = calloc(1, sizeof(*vl));
+ if (vl == NULL) {
+ DEBUG("luaC_tovaluelist: calloc failed");
+ return (NULL);
+ }
+
+ /* Push initial key */
+ lua_pushnil(L);
+ while (lua_next(L, idx) != 0) {
+ const char *key = lua_tostring(L, -2);
+
+ if (key == NULL) {
+ DEBUG("luaC_tovaluelist: Ignoring non-string key.");
+ } else if (strcasecmp("host", key) == 0)
+ luaC_tostringbuffer(L, -1, vl->host, sizeof(vl->host));
+ else if (strcasecmp("plugin", key) == 0)
+ luaC_tostringbuffer(L, -1, vl->plugin, sizeof(vl->plugin));
+ else if (strcasecmp("plugin_instance", key) == 0)
+ luaC_tostringbuffer(L, -1, vl->plugin_instance,
+ sizeof(vl->plugin_instance));
+ else if (strcasecmp("type", key) == 0)
+ luaC_tostringbuffer(L, -1, vl->type, sizeof(vl->type));
+ else if (strcasecmp("type_instance", key) == 0)
+ luaC_tostringbuffer(L, -1, vl->type_instance,
+ sizeof(vl->type_instance));
+ else if (strcasecmp("time", key) == 0)
+ vl->time = luaC_tocdtime(L, -1);
+ else if (strcasecmp("interval", key) == 0)
+ vl->interval = luaC_tocdtime(L, -1);
+ else if (strcasecmp("values", key) == 0) {
+ /* This key is not handled here, because we have to assure "type" is read
+ * first. */
+ } else {
+ DEBUG("luaC_tovaluelist: Ignoring unknown key \"%s\".", key);
+ }
+
+ /* Pop the value */
+ lua_pop(L, 1);
+ }
+
+ const data_set_t *ds = plugin_get_ds(vl->type);
+ if (ds == NULL) {
+ INFO("utils_lua: Unable to lookup type \"%s\".", vl->type);
+ sfree(vl);
+ return (NULL);
+ }
+
+ int status = ltoc_table_values(L, idx, ds, vl);
+ if (status != 0) {
+ WARNING("utils_lua: ltoc_table_values failed.");
+ sfree(vl);
+ return (NULL);
+ }
+
+#if COLLECT_DEBUG
+ assert(stack_top_before == lua_gettop(L));
+#endif
+ return (vl);
+} /* }}} value_list_t *luaC_tovaluelist */
+
+int luaC_pushcdtime(lua_State *L, cdtime_t t) /* {{{ */
+{
+ double d = CDTIME_T_TO_DOUBLE(t);
+
+ lua_pushnumber(L, (lua_Number)d);
+ return (0);
+} /* }}} int luaC_pushcdtime */
+
+int luaC_pushvalue(lua_State *L, value_t v, int ds_type) /* {{{ */
+{
+ if (ds_type == DS_TYPE_GAUGE)
+ lua_pushnumber(L, (lua_Number)v.gauge);
+ else if (ds_type == DS_TYPE_DERIVE)
+ lua_pushinteger(L, (lua_Integer)v.derive);
+ else if (ds_type == DS_TYPE_COUNTER)
+ lua_pushinteger(L, (lua_Integer)v.counter);
+ else if (ds_type == DS_TYPE_ABSOLUTE)
+ lua_pushinteger(L, (lua_Integer)v.absolute);
+ else
+ return (-1);
+ return (0);
+} /* }}} int luaC_pushvalue */
+
+int luaC_pushvaluelist(lua_State *L, const data_set_t *ds,
+ const value_list_t *vl) /* {{{ */
+{
+ lua_newtable(L);
+
+ lua_pushstring(L, vl->host);
+ lua_setfield(L, -2, "host");
+
+ lua_pushstring(L, vl->plugin);
+ lua_setfield(L, -2, "plugin");
+ lua_pushstring(L, vl->plugin_instance);
+ lua_setfield(L, -2, "plugin_instance");
+
+ lua_pushstring(L, vl->type);
+ lua_setfield(L, -2, "type");
+ lua_pushstring(L, vl->type_instance);
+ lua_setfield(L, -2, "type_instance");
+
+ luaC_pushvalues(L, ds, vl);
+ lua_setfield(L, -2, "values");
+
+ luaC_pushdstypes(L, ds);
+ lua_setfield(L, -2, "dstypes");
+
+ luaC_pushdsnames(L, ds);
+ lua_setfield(L, -2, "dsnames");
+
+ luaC_pushcdtime(L, vl->time);
+ lua_setfield(L, -2, "time");
+
+ luaC_pushcdtime(L, vl->interval);
+ lua_setfield(L, -2, "interval");
+
+ return (0);
+} /* }}} int luaC_pushvaluelist */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
--- /dev/null
+/**
+ * collectd - src/utils_lua.h
+ * Copyright (C) 2010 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Florian Forster <octo at collectd.org>
+ **/
+
+#ifndef UTILS_LUA_H
+#define UTILS_LUA_H 1
+
+#include "collectd.h"
+#include "plugin.h"
+
+#ifndef DONT_POISON_SPRINTF_YET
+#error "Files including utils_lua.h need to define DONT_POISON_SPRINTF_YET."
+#endif
+#include <lua.h>
+
+/*
+ * access functions (stack -> C)
+ */
+cdtime_t luaC_tocdtime(lua_State *L, int idx);
+int luaC_tostringbuffer(lua_State *L, int idx, char *buffer,
+ size_t buffer_size);
+value_t luaC_tovalue(lua_State *L, int idx, int ds_type);
+value_list_t *luaC_tovaluelist(lua_State *L, int idx);
+
+/*
+ * push functions (C -> stack)
+ */
+int luaC_pushcdtime(lua_State *L, cdtime_t t);
+int luaC_pushvalue(lua_State *L, value_t v, int ds_type);
+int luaC_pushvaluelist(lua_State *L, const data_set_t *ds,
+ const value_list_t *vl);
+
+#endif /* UTILS_LUA_H */
+/* vim: set sw=2 sts=2 et fdm=marker : */
#include "collectd.h"
#include "common.h"
-#include "configfile.h"
#include "plugin.h"
#if HAVE_SYS_SYSCTL_H
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#if HAVE_VARNISH_V4
#include <vapi/vsm.h>
static int varnish_init (void) /* {{{ */
{
user_config_t *conf;
- user_data_t ud;
if (have_instance)
return (0);
varnish_config_apply_default (conf);
- ud.data = conf;
- ud.free_func = varnish_config_free;
+ user_data_t ud = {
+ .data = conf,
+ .free_func = varnish_config_free
+ };
plugin_register_complex_read (/* group = */ "varnish",
/* name = */ "varnish/localhost",
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_ignorelist.h"
#include "utils_complain.h"
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_complain.h"
#include "utils_format_graphite.h"
continue;
}
+ set_sock_opts (cb->sock_fd);
+
status = connect (cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0)
{
static int wg_config_node (oconfig_item_t *ci)
{
struct wg_callback *cb;
- user_data_t user_data = { 0 };
char callback_name[DATA_MAX_NAME_LEN];
int status = 0;
ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
cb->name);
- user_data.data = cb;
- user_data.free_func = wg_callback_free;
- plugin_register_write (callback_name, wg_write, &user_data);
+ user_data_t ud = {
+ .data = cb,
+ .free_func = wg_callback_free
+ };
+
+ plugin_register_write (callback_name, wg_write, &ud);
- user_data.free_func = NULL;
- plugin_register_flush (callback_name, wg_flush, &user_data);
+ ud.free_func = NULL;
+ plugin_register_flush (callback_name, wg_flush, &ud);
return (0);
}
int status;
- if (0 != strcmp (ds->type, vl->type)) {
+ /* sanity checks, primarily to make static analyzers happy. */
+ if ((cb == NULL) || (cb->send_buffer == NULL))
+ return -1;
+
+ if (strcmp (ds->type, vl->type) == 0) {
ERROR ("write_http plugin: DS type does not match "
"value list type");
return -1;
{
wh_callback_t *cb;
int buffer_size = 0;
- user_data_t user_data = { 0 };
char callback_name[DATA_MAX_NAME_LEN];
int status = 0;
DEBUG ("write_http: Registering write callback '%s' with URL '%s'",
callback_name, cb->location);
- user_data.data = cb;
+ user_data_t user_data = {
+ .data = cb
+ };
+
plugin_register_flush (callback_name, wh_flush, &user_data);
user_data.free_func = wh_callback_free;
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include "utils_cmd_putval.h"
#include "utils_format_graphite.h"
#include "utils_format_json.h"
char *val;
char callback_name[DATA_MAX_NAME_LEN];
char errbuf[1024];
- user_data_t ud;
oconfig_item_t *child;
rd_kafka_conf_res_t ret;
ssnprintf(callback_name, sizeof(callback_name),
"write_kafka/%s", tctx->topic_name);
- ud.data = tctx;
- ud.free_func = kafka_topic_context_free;
+ user_data_t ud = {
+ .data = tctx,
+ .free_func = kafka_topic_context_free
+ };
status = plugin_register_write (callback_name, kafka_write, &ud);
if (status != 0) {
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_format_graphite.h"
} /* int wl_write_messages */
static int wl_write (const data_set_t *ds, const value_list_t *vl,
- user_data_t *user_data)
+ __attribute__ ((unused)) user_data_t *user_data)
{
int status;
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include "utils_cache.h"
#if HAVE_STDINT_H
if (status == 0)
{
char cb_name[DATA_MAX_NAME_LEN];
- user_data_t ud;
ssnprintf (cb_name, sizeof (cb_name), "write_mongodb/%s", node->name);
- ud.data = node;
- ud.free_func = wm_config_free;
+ user_data_t ud = {
+ .data = node,
+ .free_func = wm_config_free
+ };
status = plugin_register_write (cb_name, wm_write, &ud);
INFO ("write_mongodb plugin: registered write plugin %s %d",cb_name,status);
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include <sys/time.h>
#include <hiredis/hiredis.h>
if (status == 0)
{
char cb_name[DATA_MAX_NAME_LEN];
- user_data_t ud;
ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name);
- ud.data = node;
- ud.free_func = wr_config_free;
+ user_data_t ud = {
+ .data = node,
+ .free_func = wr_config_free
+ };
status = plugin_register_write (cb_name, wr_write, &ud);
}
#include "collectd.h"
#include "common.h"
-#include "configfile.h"
#include "plugin.h"
#include "utils_cache.h"
#include "utils_complain.h"
}
}
+ set_sock_opts(riemann_client_get_fd(host->client));
+
c_release(LOG_INFO, &host->init_complaint,
"write_riemann plugin: Successfully connected to %s:%d", node,
port);
int i;
oconfig_item_t *child;
char callback_name[DATA_MAX_NAME_LEN];
- user_data_t ud;
if ((host = calloc(1, sizeof(*host))) == NULL) {
ERROR("write_riemann plugin: calloc failed.");
ssnprintf(callback_name, sizeof(callback_name), "write_riemann/%s",
host->name);
- ud.data = host;
- ud.free_func = wrr_free;
+
+ user_data_t ud = {
+ .data = host,
+ .free_func = wrr_free
+ };
pthread_mutex_lock(&host->lock);
#include "plugin.h"
#include "common.h"
-#include "configfile.h"
#include "utils_cache.h"
#include <arpa/inet.h>
#include <errno.h>
if (setsockopt(host->s, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger) != 0)
WARNING("write_sensu plugin: failed to set socket close() lingering");
+ set_sock_opts(host->s);
+
// connect the socket
if (connect(host->s, ai->ai_addr, ai->ai_addrlen) != 0) {
close(host->s);
in_place_replace_sensu_name_reserved(service_buffer);
// finalize the buffer by setting the output and closing curly bracket
- res = my_asprintf(&temp_str, "%s, \"output\": \"%s %s %ld\"}\n", ret_str, service_buffer, value_str, CDTIME_T_TO_TIME_T(vl->time));
+ res = my_asprintf(&temp_str, "%s, \"output\": \"%s %s %lld\"}\n",ret_str, service_buffer, value_str, (long long)CDTIME_T_TO_TIME_T(vl->time));
free(ret_str);
free(value_str);
if (res == -1) {
ret_str = temp_str;
// incorporate the timestamp
- res = my_asprintf(&temp_str, "%s, \"timestamp\": %ld", ret_str, CDTIME_T_TO_TIME_T(n->time));
+ res = my_asprintf(&temp_str, "%s, \"timestamp\": %lld", ret_str, (long long)CDTIME_T_TO_TIME_T(n->time));
free(ret_str);
if (res == -1) {
ERROR("write_sensu plugin: Unable to alloc memory");
int status = 0;
oconfig_item_t *child;
char callback_name[DATA_MAX_NAME_LEN];
- user_data_t ud;
if ((host = calloc(1, sizeof(*host))) == NULL) {
ERROR("write_sensu plugin: calloc failed.");
}
ssnprintf(callback_name, sizeof(callback_name), "write_sensu/%s", host->name);
- ud.data = host;
- ud.free_func = sensu_free;
+
+ user_data_t ud = {
+ .data = host,
+ .free_func = sensu_free
+ };
pthread_mutex_lock(&host->lock);
#include "common.h"
#include "plugin.h"
-#include "configfile.h"
#include "utils_cache.h"
if (cb->sock_fd < 0)
continue;
+ set_sock_opts(cb->sock_fd);
+
status = connect(cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0)
{
static int wt_config_tsd(oconfig_item_t *ci)
{
struct wt_callback *cb;
- user_data_t user_data = { 0 };
char callback_name[DATA_MAX_NAME_LEN];
cb = calloc(1, sizeof(*cb));
cb->node != NULL ? cb->node : WT_DEFAULT_NODE,
cb->service != NULL ? cb->service : WT_DEFAULT_SERVICE);
- user_data.data = cb;
- user_data.free_func = wt_callback_free;
+ user_data_t user_data = {
+ .data = cb,
+ .free_func = wt_callback_free
+ };
+
plugin_register_write(callback_name, wt_write, &user_data);
user_data.free_func = NULL;
while (c_avl_pick (tree, (void **)&zoneid, (void **)&stats) == 0)
{
if (getzonenamebyid(*zoneid, zonename, sizeof( zonename )) == -1) {
- WARNING("zone plugin: error retreiving zonename");
+ WARNING("zone plugin: error retrieving zonename");
} else {
zone_submit_value(zonename, (gauge_t)FRC2PCT(stats->pctcpu));
}