- hddtemp
Hard disk temperatures using hddtempd.
+ - hugepages
+ Report the number of used and free hugepages. More info on
+ hugepages can be found here:
+ https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt.
+
- interface
Interface traffic: Number of octets, packets and errors for each
interface.
+++ /dev/null
-* Finalize the onewire plugin.
-* Custom notification messages?
-* Implement moving-average calculation for the threshold stuff.
-
-src/battery.c: commend not working code.
-
-Wishlist:
-* Port nfs module to solaris
-* Port tape module to Linux
-* Port the apple_sensors plugin to Linux/PPC.
-* Maybe look into porting the serial module
-* Build Darwin package
-* Maybe let the network plugin configure whether or not notifications should be
- sent/received.
-* Maybe find a way for processes connected to the unixsock plugin to receive
- notifications, too.
-
-http://developer.apple.com/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_IOKitLib_API/chapter_5_section_1.html
-http://developer.apple.com/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/index.html#//apple_ref/doc/uid/TP0000011
-http://www.gauchosoft.com/Software/X%20Resource%20Graph/
-http://johannes.sipsolutions.net/PowerBook/Apple_Motion_Sensor_Specification/
plugin_fscache="no"
plugin_gps="no"
plugin_grpc="no"
+plugin_hugepages="no"
plugin_interface="no"
plugin_ipmi="no"
plugin_ipvs="no"
plugin_entropy="yes"
plugin_fhcount="yes"
plugin_fscache="yes"
+ plugin_hugepages="yes"
plugin_interface="yes"
plugin_ipc="yes"
plugin_irq="yes"
AC_PLUGIN([gps], [$plugin_gps], [GPS plugin])
AC_PLUGIN([grpc], [$plugin_grpc], [gRPC plugin])
AC_PLUGIN([hddtemp], [yes], [Query hddtempd])
+AC_PLUGIN([hugepages], [$plugin_hugepages], [Hugepages statistics])
AC_PLUGIN([interface], [$plugin_interface], [Interface traffic statistics])
AC_PLUGIN([ipc], [$plugin_ipc], [IPC statistics])
AC_PLUGIN([ipmi], [$plugin_ipmi], [IPMI sensor statistics])
AC_MSG_RESULT([ gps . . . . . . . . . $enable_gps])
AC_MSG_RESULT([ grpc . . . . . . . . $enable_grpc])
AC_MSG_RESULT([ hddtemp . . . . . . . $enable_hddtemp])
+AC_MSG_RESULT([ hugepages . . . . . . $enable_hugepages])
AC_MSG_RESULT([ interface . . . . . . $enable_interface])
AC_MSG_RESULT([ ipc . . . . . . . . . $enable_ipc])
AC_MSG_RESULT([ ipmi . . . . . . . . $enable_ipmi])
%define with_gmond 0%{!?_without_gmond:1}
%define with_gps 0%{!?_without_gps:1}
%define with_hddtemp 0%{!?_without_hddtemp:1}
+%define with_hugepages 0%{!?_without_hugepages:1}
%define with_interface 0%{!?_without_interface:1}
%define with_ipc 0%{!?_without_ipc:1}
%define with_ipmi 0%{!?_without_ipmi:1}
Summary: Statistics collection and monitoring daemon
Name: collectd
-Version: 5.6.0
+Version: 5.7.0
Release: 2%{?dist}
URL: https://collectd.org
Source: https://collectd.org/files/%{name}-%{version}.tar.bz2
%define _with_hddtemp --disable-hddtemp
%endif
+%if %{with_hugepages}
+%define _with_hugepages --enable-hugepages
+%else
+%define _with_hugepages --disable-hugepages
+%endif
+
%if %{with_interface}
%define _with_interface --enable-interface
%else
%{?_with_gps} \
%{?_with_grpc} \
%{?_with_hddtemp} \
+ %{?_with_hugepages} \
%{?_with_interface} \
%{?_with_ipc} \
%{?_with_ipmi} \
%if %{with_fscache}
%{_libdir}/%{name}/fscache.so
%endif
+%if %{with_hugepages}
+%{_libdir}/%{name}/hugepages.so
+%endif
%if %{with_interface}
%{_libdir}/%{name}/interface.so
%endif
%doc contrib/
%changelog
+* Tue Aug 23 2016 Marc Fournier <marc.fournier@camptocamp.com> - 5.7.0-1
+- New PRE-RELEASE version
+- New plugins enabled by default: hugepages
+
* Sun Aug 14 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.6.0-1
- New PRE-RELEASE version
- New plugins enabled by default: chrony, cpusleep, gps, lua, mqtt, notify_nagios
import "types.proto";
service Collectd {
- // DispatchValues reads the value lists from the DispatchValuesRequest stream.
+ // PutValues reads the value lists from the PutValuesRequest stream.
// The gRPC server embedded into collectd will inject them into the system
// just like the network plugin.
- rpc DispatchValues(stream DispatchValuesRequest)
- returns (DispatchValuesResponse);
+ rpc PutValues(stream PutValuesRequest)
+ returns (PutValuesResponse);
// 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 {
+// The arguments to PutValues.
+message PutValuesRequest {
// value_list is the metric to be sent to the server.
collectd.types.ValueList value_list = 1;
}
-// The response from DispatchValues.
-message DispatchValuesResponse {}
+// The response from PutValues.
+message PutValuesResponse {}
// The arguments to QueryValues.
message QueryValuesRequest {
endif
endif
+if BUILD_PLUGIN_HUGEPAGES
+pkglib_LTLIBRARIES += hugepages.la
+hugepages_la_SOURCES = hugepages.c
+hugepages_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
if BUILD_PLUGIN_INTERFACE
pkglib_LTLIBRARIES += interface.la
interface_la_SOURCES = interface.c
struct timeval end_tv;
struct cconn io_array[g_num_daemons];
- DEBUG("ceph plugin: entering cconn_main_loop(request_type = %d)", request_type);
+ DEBUG ("ceph plugin: entering cconn_main_loop(request_type = %"PRIu32")", request_type);
+
+ if (g_num_daemons < 1)
+ {
+ ERROR ("ceph plugin: No daemons configured. See the \"Daemon\" config option.");
+ return ENOENT;
+ }
/* create cconn array */
- memset(io_array, 0, sizeof(io_array));
- for(size_t 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;
- io_array[i].state = CSTATE_UNCONNECTED;
+ io_array[i] = (struct cconn) {
+ .d = g_daemons[i],
+ .request_type = request_type,
+ .state = CSTATE_UNCONNECTED,
+ };
}
/** Calculate the time at which we should give up */
#@BUILD_PLUGIN_GPS_TRUE@LoadPlugin gps
#@BUILD_PLUGIN_GRPC_TRUE@LoadPlugin grpc
#@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
+#@BUILD_PLUGIN_HUGEPAGES_TRUE@LoadPlugin hugepages
@BUILD_PLUGIN_INTERFACE_TRUE@@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
#@BUILD_PLUGIN_IPC_TRUE@LoadPlugin ipc
#@BUILD_PLUGIN_IPMI_TRUE@LoadPlugin ipmi
# Port "7634"
#</Plugin>
+#<Plugin hugepages>
+# ReportPerNodeHP "true"
+# ReportRootHP "true"
+#</Plugin>
+
#<Plugin interface>
# Interface "eth0"
# IgnoreSelected false
=back
+=head2 Plugin C<hugepages>
+
+To collect B<hugepages> information, collectd reads directories
+"/sys/devices/system/node/*/hugepages" and
+"/sys/kernel/mm/hugepages".
+Reading of these directories can be disabled by the following
+options (default is enabled).
+
+=over 4
+
+=item B<ReportPerNodeHP> I<true>|I<false>
+
+If enabled, information will be collected from the hugepage
+counters in "/sys/devices/system/node/*/hugepages".
+This is used to check the per-node hugepage statistics on
+a NUMA system.
+
+=item B<ReportRootHP> I<true>|I<false>
+
+If enabled, information will be collected from the hugepage
+counters in "/sys/kernel/mm/hugepages".
+This can be used on both NUMA and non-NUMA systems to check
+the overall hugepage statistics.
+
+=back
+
=head2 Plugin C<interface>
=over 4
if (queries_num == 0)
{
ERROR ("dbi plugin: No <Query> blocks have been found. Without them, "
- "this plugin can't do anything useful, so we will returns an error.");
+ "this plugin can't do anything useful, so we will return an error.");
return (-1);
}
if (databases_num == 0)
{
ERROR ("dbi plugin: No <Database> blocks have been found. Without them, "
- "this plugin can't do anything useful, so we will returns an error.");
+ "this plugin can't do anything useful, so we will return an error.");
return (-1);
}
}
/* Duplicate found: leave non-NULL dup_ptr. */
- if (by_device && (strcmp (mnt_ptr->spec_device, dup_ptr->spec_device) == 0))
+ if (by_device
+ && (mnt_ptr->spec_device != NULL)
+ && (dup_ptr->spec_device != NULL)
+ && (strcmp (mnt_ptr->spec_device, dup_ptr->spec_device) == 0))
break;
else if (!by_device && (strcmp (mnt_ptr->dir, dup_ptr->dir) == 0))
break;
/* #endif HAVE_LIBKSTAT */
#elif defined(HAVE_LIBSTATGRAB)
-/* #endif HAVE_LIBKSTATGRAB */
+/* #endif HAVE_LIBSTATGRAB */
#elif HAVE_PERFSTAT
static perfstat_disk_t * stat_disk;
using collectd::Collectd;
-using collectd::DispatchValuesRequest;
-using collectd::DispatchValuesResponse;
+using collectd::PutValuesRequest;
+using collectd::PutValuesResponse;
using collectd::QueryValuesRequest;
using collectd::QueryValuesResponse;
return status;
}
- grpc::Status DispatchValues(grpc::ServerContext *ctx,
- grpc::ServerReader<DispatchValuesRequest> *reader,
- DispatchValuesResponse *res) override {
- DispatchValuesRequest req;
+ grpc::Status PutValues(grpc::ServerContext *ctx,
+ grpc::ServerReader<PutValuesRequest> *reader,
+ PutValuesResponse *res) override {
+ PutValuesRequest req;
while (reader->Read(&req)) {
value_list_t vl = VALUE_LIST_INIT;
CollectdClient(std::shared_ptr<grpc::ChannelInterface> channel) : stub_(Collectd::NewStub(channel)) {
}
- int DispatchValues(value_list_t const *vl) {
+ int PutValues(value_list_t const *vl) {
grpc::ClientContext ctx;
- DispatchValuesRequest req;
+ PutValuesRequest 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);
+ PutValuesResponse res;
+ auto stream = stub_->PutValues(&ctx, &res);
if (!stream->Write(req)) {
NOTICE("grpc: Broken stream.");
/* intentionally not returning. */
}
return 0;
- } /* int DispatchValues */
+ } /* int PutValues */
private:
std::unique_ptr<Collectd::Stub> stub_;
value_list_t const *vl,
user_data_t *ud) {
CollectdClient *c = (CollectdClient *) ud->data;
- return c->DispatchValues(vl);
+ return c->PutValues(vl);
}
static int c_grpc_config_listen(oconfig_item_t *ci)
--- /dev/null
+/*-
+ * collectd - src/hugepages.c
+ * MIT License
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * 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:
+ * Jaroslav Safka <jaroslavx.safka@intel.com>
+ * Kim-Marie Jones <kim-marie.jones@intel.com>
+ */
+
+#include "collectd.h"
+#include "common.h" /* auxiliary functions */
+#include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
+
+static const char g_plugin_name[] = "hugepages";
+static const char g_cfg_rpt_numa[] = "ReportPerNodeHP";
+static const char g_cfg_rpt_mm[] = "ReportRootHP";
+
+static const char *g_config_keys[] = {
+ g_cfg_rpt_numa,
+ g_cfg_rpt_mm,
+};
+static size_t g_config_keys_num = STATIC_ARRAY_SIZE(g_config_keys);
+static int g_flag_rpt_numa = 1;
+static int g_flag_rpt_mm = 1;
+
+struct entry_info {
+ char *d_name;
+ const char *node;
+};
+
+static int huge_config_callback(const char *key, const char *val)
+{
+ DEBUG("%s: HugePages config key='%s', val='%s'", g_plugin_name, key, val);
+
+ if (strcasecmp(key, g_cfg_rpt_numa) == 0) {
+ g_flag_rpt_numa = IS_TRUE(val);
+ return 0;
+ }
+ if (strcasecmp(key, g_cfg_rpt_mm) == 0) {
+ g_flag_rpt_mm = IS_TRUE(val);
+ return 0;
+ }
+
+ return -1;
+}
+
+static void submit_hp(const char *plug_inst, const char *type,
+ const char *type_instance, gauge_t free_value, gauge_t used_value)
+{
+ value_t values[2];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = free_value;
+ values[1].gauge = used_value;
+
+ vl.values = values;
+ vl.values_len = 2;
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, g_plugin_name, sizeof (vl.plugin));
+ sstrncpy (vl.plugin_instance, plug_inst, sizeof (vl.plugin_instance));
+ sstrncpy (vl.type, type, sizeof (vl.type));
+
+ if (type_instance != NULL) {
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+ }
+
+ DEBUG("submit_hp pl_inst:%s, inst_type %s, type %s, free=%lf, used=%lf",
+ plug_inst, type_instance, type, free_value, used_value);
+
+ plugin_dispatch_values (&vl);
+}
+
+static int read_hugepage_entry(const char *path, const char *entry,
+ void *e_info)
+{
+ char path2[PATH_MAX];
+ static const char type[] = "hugepages";
+ static const char partial_type_inst[] = "free_used";
+ char type_instance[PATH_MAX];
+ char *strin;
+ struct entry_info *hpsize_plinst = e_info;
+ static int flag = 0;
+ static double used_hp = 0;
+ static double free_hp = 0;
+ double value;
+
+ ssnprintf(path2, sizeof(path2), "%s/%s", path, entry);
+
+ FILE *fh = fopen(path2, "rt");
+ if (fh == NULL) {
+ ERROR("%s: cannot open %s", g_plugin_name, path2);
+ return -1;
+ }
+
+ if (fscanf(fh, "%lf", &value) !=1) {
+ ERROR("%s: cannot parse file %s", g_plugin_name, path2);
+ fclose(fh);
+ return -1;
+ }
+
+ if (strcmp(entry, "nr_hugepages") == 0) {
+ used_hp += value;
+ flag++;
+ } else if (strcmp(entry, "surplus_hugepages") == 0) {
+ used_hp += value;
+ flag++;
+ } else if (strcmp(entry, "free_hugepages") == 0) {
+ used_hp -= value;
+ free_hp = value;
+ flag++;
+ }
+
+ if (flag == 3) {
+ /* Can now submit "used" and "free" values.
+ * 0x2D is the ASCII "-" character, after which the string
+ * contains "<size>kB"
+ * The string passed as param 3 to submit_hp is of the format:
+ * <type>-<partial_type_inst>-<size>kB
+ */
+ strin = strchr(hpsize_plinst->d_name, 0x2D);
+ if (strin != NULL) {
+ ssnprintf(type_instance, sizeof(type_instance), "%s%s", partial_type_inst, strin);
+ } else {
+ ssnprintf(type_instance, sizeof(type_instance), "%s%s", partial_type_inst,
+ hpsize_plinst->d_name);
+ }
+ submit_hp(hpsize_plinst->node, type, type_instance, free_hp, used_hp);
+
+ /* Reset for next time */
+ flag = 0;
+ used_hp = 0;
+ free_hp = 0;
+ }
+
+ fclose(fh);
+ return 0;
+}
+
+static int read_syshugepages(const char* path, const char* node)
+{
+ static const char hugepages_dir[] = "hugepages";
+ DIR *dir;
+ struct dirent *result;
+ char path2[PATH_MAX];
+ struct entry_info e_info;
+ long lim;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ ERROR("%s: cannot open directory %s", g_plugin_name, path);
+ return -1;
+ }
+
+ errno = 0;
+ if ((lim = pathconf(path, _PC_NAME_MAX)) == -1) {
+ /* Limit not defined if errno == 0, otherwise error */
+ if (errno != 0) {
+ ERROR("%s: pathconf failed", g_plugin_name);
+ closedir(dir);
+ return -1;
+ } else {
+ lim = PATH_MAX;
+ }
+ }
+
+ /* read "hugepages-XXXXXkB" entries */
+ while ((result = readdir(dir)) != NULL) {
+ if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir)-1)) {
+ /* not node dir */
+ errno = 0;
+ continue;
+ }
+
+ /* /sys/devices/system/node/node?/hugepages/ */
+ ssnprintf(path2, (size_t) lim, "%s/%s", path, result->d_name);
+
+ e_info.d_name = result->d_name;
+ e_info.node = node;
+ walk_directory(path2, read_hugepage_entry, &e_info, 0);
+ errno = 0;
+ }
+
+ /* Check if NULL return from readdir() was an error */
+ if (errno != 0) {
+ ERROR("%s: readdir failed", g_plugin_name);
+ closedir(dir);
+ return -1;
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+static int read_nodes(void)
+{
+ static const char sys_node[] = "/sys/devices/system/node";
+ static const char node_string[] = "node";
+ static const char sys_node_hugepages[] = "/sys/devices/system/node/%s/hugepages";
+ DIR *dir;
+ struct dirent *result;
+ char path[PATH_MAX];
+ long lim;
+
+ dir = opendir(sys_node);
+ if (dir == NULL) {
+ ERROR("%s: cannot open directory %s", g_plugin_name, sys_node);
+ return -1;
+ }
+
+ errno = 0;
+ if ((lim = pathconf(sys_node, _PC_NAME_MAX)) == -1) {
+ /* Limit not defined if errno == 0, otherwise error */
+ if (errno != 0) {
+ ERROR("%s: pathconf failed", g_plugin_name);
+ closedir(dir);
+ return -1;
+ } else {
+ lim = PATH_MAX;
+ }
+ }
+
+ while ((result = readdir(dir)) != NULL) {
+ if (strncmp(result->d_name, node_string, sizeof(node_string)-1)) {
+ /* not node dir */
+ errno = 0;
+ continue;
+ }
+
+ ssnprintf(path, (size_t) lim, sys_node_hugepages, result->d_name);
+ read_syshugepages(path, result->d_name);
+ errno = 0;
+ }
+
+ /* Check if NULL return from readdir() was an error */
+ if (errno != 0) {
+ ERROR("%s: readdir failed", g_plugin_name);
+ closedir(dir);
+ return -1;
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+
+static int huge_read(void)
+{
+ static const char sys_mm_hugepages[] = "/sys/kernel/mm/hugepages";
+
+ if (g_flag_rpt_mm) {
+ if (read_syshugepages(sys_mm_hugepages, "mm") != 0) {
+ return -1;
+ }
+ }
+ if (g_flag_rpt_numa) {
+ if (read_nodes() != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void module_register(void)
+{
+ plugin_register_config(g_plugin_name, huge_config_callback, g_config_keys,
+ g_config_keys_num);
+ plugin_register_read(g_plugin_name, huge_read);
+}
+
http_request_methods value:DERIVE:0:U
http_requests value:DERIVE:0:U
http_response_codes value:DERIVE:0:U
+hugepages free:GAUGE:0:4294967295, used:GAUGE:0:4294967295
humidity value:GAUGE:0:100
if_collisions value:DERIVE:0:U
if_dropped rx:DERIVE:0:U, tx:DERIVE:0:U
}
assert (command_len < cb->send_buffer_free);
+ /* Make scan-build happy. */
+ assert (cb->send_buffer != NULL);
+
/* `command_len + 1' because `command_len' does not include the
* trailing null byte. Neither does `send_buffer_fill'. */
memcpy (cb->send_buffer + cb->send_buffer_fill,