- 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 {
if BUILD_PLUGIN_BATTERY
pkglib_LTLIBRARIES += battery.la
-battery_la_SOURCES = battery.c
+battery_la_SOURCES = battery.c battery_statefs.c
battery_la_LDFLAGS = $(PLUGIN_LDFLAGS)
if BUILD_WITH_LIBIOKIT
battery_la_LDFLAGS += -framework IOKit
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
write_log_la_SOURCES = write_log.c \
utils_format_graphite.c utils_format_graphite.h
write_log_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+write_log_la_LIBADD = libformat_json.la
endif
if BUILD_PLUGIN_WRITE_MONGODB
if (publish)
{
char cbname[128];
- user_data_t ud = { conf, camqp_config_free };
-
ssnprintf (cbname, sizeof (cbname), "amqp/%s", conf->name);
- status = plugin_register_write (cbname, camqp_write, &ud);
+ status = plugin_register_write (cbname, camqp_write,
+ &(user_data_t) {
+ .data = conf,
+ .free_func = camqp_config_free,
+ });
if (status != 0)
{
camqp_config_free (conf);
if (status == 0)
{
- user_data_t ud = {
- .data = st,
- .free_func = apache_free
- };
-
char callback_name[3*DATA_MAX_NAME_LEN];
ssnprintf (callback_name, sizeof (callback_name),
/* name = */ callback_name,
/* callback = */ apache_read_host,
/* interval = */ 0,
- /* user_data = */ &ud);
+ &(user_data_t) {
+ .data = st,
+ .free_func = apache_free,
+ });
+
}
if (status != 0)
# define SYSFS_FACTOR 0.000001
#endif /* KERNEL_LINUX */
+int battery_read_statefs (void); /* defined in battery_statefs; used by StateFS backend */
+
static _Bool report_percent = 0;
static _Bool report_degraded = 0;
+static _Bool query_statefs = 0;
static void battery_submit2 (char const *plugin_instance, /* {{{ */
char const *type, char const *type_instance, gauge_t value)
gauge_t capacity_full = NAN; /* Total capacity */
gauge_t capacity_design = NAN; /* Full design capacity */
+ if (query_statefs)
+ return battery_read_statefs ();
+
#if HAVE_IOKIT_PS_IOPOWERSOURCES_H
get_via_io_power_sources (&charge_rel, ¤t, &voltage);
#endif
char const *basename,
char *buffer, size_t buffer_size)
{
- int status;
- FILE *fp;
char filename[PATH_MAX];
+ int status;
ssnprintf (filename, sizeof (filename), "%s/%s/%s",
dir, power_supply, basename);
- /* No file isn't the end of the world -- not every system will be
- * reporting the same set of statistics */
- if (access (filename, R_OK) != 0)
- return ENOENT;
-
- fp = fopen (filename, "r");
- if (fp == NULL)
- {
- status = errno;
- if (status != ENOENT)
- {
- char errbuf[1024];
- WARNING ("battery plugin: fopen (%s) failed: %s", filename,
- sstrerror (status, errbuf, sizeof (errbuf)));
- }
+ status = (int) read_file_contents (filename, buffer, buffer_size);
+ if (status < 0)
return status;
- }
-
- if (fgets (buffer, buffer_size, fp) == NULL)
- {
- status = errno;
- if (status != ENODEV)
- {
- char errbuf[1024];
- WARNING ("battery plugin: fgets (%s) failed: %s", filename,
- sstrerror (status, errbuf, sizeof (errbuf)));
- }
- fclose (fp);
- return status;
- }
strstripnewline (buffer);
-
- fclose (fp);
return 0;
} /* }}} int sysfs_file_to_buffer */
{
int status;
+ if (query_statefs)
+ return battery_read_statefs ();
+
DEBUG ("battery plugin: Trying sysfs ...");
status = read_sysfs ();
if (status == 0)
cf_util_get_boolean (child, &report_percent);
else if (strcasecmp ("ReportDegraded", child->key) == 0)
cf_util_get_boolean (child, &report_degraded);
+ else if (strcasecmp ("QueryStateFS", child->key) == 0)
+ cf_util_get_boolean (child, &query_statefs);
else
WARNING ("battery plugin: Ignoring unknown "
"configuration option \"%s\".",
--- /dev/null
+/**
+ * collectd - src/statefs_battery.c
+ * Copyright (C) 2016 rinigus
+ *
+ *
+The MIT License (MIT)
+
+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:
+ * rinigus <http://github.com/rinigus>
+
+ Battery stats are collected from StateFS Battery namespace. Reported
+ units are as follows:
+
+ capacity %
+ charge %
+ current A
+ energy Wh
+ power W
+ temperature C
+ timefull and timelow seconds
+ voltage V
+
+ Provider at
+ https://git.merproject.org/mer-core/statefs-providers/blob/master/src/power_udev/provider_power_udev.cpp
+
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+
+#include <stdio.h>
+
+#define STATEFS_ROOT "/run/state/namespaces/Battery/"
+
+static void battery_submit(const char *type, gauge_t value,
+ const char *type_instance) {
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ values[0].gauge = value;
+
+ vl.values = values;
+ vl.values_len = 1;
+ sstrncpy(vl.host, hostname_g, sizeof(vl.host));
+ sstrncpy(vl.plugin, "battery", sizeof(vl.plugin));
+ /* statefs supports 1 battery at present */
+ sstrncpy(vl.plugin_instance, "0", sizeof(vl.plugin_instance));
+ sstrncpy(vl.type, type, sizeof(vl.type));
+ if (type_instance != NULL)
+ sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
+ plugin_dispatch_values(&vl);
+}
+
+/* cannot be static, is referred to from battery.c */
+int battery_read_statefs(void) {
+ value_t v;
+ int success = 0;
+
+ if (parse_value_file(STATEFS_ROOT "ChargePercentage", &v, DS_TYPE_GAUGE) == 0) {
+ battery_submit("charge", v.gauge, NULL);
+ success++;
+ } else if (parse_value_file(STATEFS_ROOT "Capacity", &v, DS_TYPE_GAUGE) == 0) {
+ // Use capacity as a charge estimate if ChargePercentage is not available
+ battery_submit("charge", v.gauge, NULL);
+ success++;
+ } else {
+ WARNING("battery plugin: Neither \""STATEFS_ROOT"ChargePercentage\" "
+ "nor \""STATEFS_ROOT"Capacity\" could be read.");
+ }
+
+ struct {
+ char *path;
+ char *type;
+ char *type_instance;
+ gauge_t factor;
+ } metrics[] = {
+ {STATEFS_ROOT "Current", "current", NULL, 1e-6}, // from uA to A
+ {STATEFS_ROOT "Energy", "energy_wh", NULL, 1e-6}, // from uWh to Wh
+ {STATEFS_ROOT "Power", "power", NULL, 1e-6}, // from uW to W
+ {STATEFS_ROOT "Temperature", "temperature", NULL, 0.1}, // from 10xC to C
+ {STATEFS_ROOT "TimeUntilFull", "duration", "full", 1.0},
+ {STATEFS_ROOT "TimeUntilLow", "duration", "low", 1.0},
+ {STATEFS_ROOT "Voltage", "voltage", NULL, 1e-6}, // from uV to V
+ };
+
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(metrics); i++) {
+ if (parse_value_file(metrics[i].path, &v, DS_TYPE_GAUGE) != 0) {
+ WARNING("battery plugin: Reading \"%s\" failed.", metrics[i].path);
+ continue;
+ }
+
+ battery_submit(metrics[i].type, v.gauge * metrics[i].factor, metrics[i].type_instance);
+ success++;
+ }
+
+ if (success == 0) {
+ ERROR("battery plugin: statefs backend: none of the statistics are available");
+ return (-1);
+ }
+
+ return (0);
+}
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
#<Plugin "battery">
# ValuesPercentage false
# ReportDegraded false
+# QueryStateFS false
#</Plugin>
#<Plugin "bind">
# Port "7634"
#</Plugin>
+#<Plugin hugepages>
+# ReportPerNodeHP "true"
+# ReportRootHP "true"
+#</Plugin>
+
#<Plugin interface>
# Interface "eth0"
# IgnoreSelected false
# AlwaysAppendDS false
# EscapeCharacter "_"
# SeparateInstances false
+# DropDuplicateFields false
# </Node>
#</Plugin>
and "remaining capacity") and B<degraded> (difference between "design capacity"
and "last full capacity").
+=item B<QueryStateFS> B<false>|B<true>
+
+When set to B<true>, the battery plugin will only read statistics
+related to battery performance as exposed by StateFS at
+/run/state. StateFS is used in Mer-based Sailfish OS, for
+example.
+
=back
=head2 Plugin C<bind>
=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
identifier. If set to B<false> (the default), this is only done when there is
more than one DS.
+=item B<DropDuplicateFields> B<false>|B<true>
+
+If set to B<true>, detect and remove duplicate components in Graphite metric
+names. For example, the metric name C<host.load.load.shortterm> will
+be shortened to C<host.load.shortterm>.
+
+=back
+
+=head2 Plugin C<write_log>
+
+The C<write_log> plugin writes metrics as INFO log messages.
+
+This plugin supports two output formats: I<Graphite> and I<JSON>.
+
+Synopsis:
+
+ <Plugin write_log>
+ Format Graphite
+ </Plugin>
+
+=over 4
+
+=item B<Format> I<Format>
+
+The output format to use. Can be one of C<Graphite> or C<JSON>.
+
=back
=head2 Plugin C<write_tsdb>
=item B<TypeInstance> I<Regex>
+=item B<MetaData> I<String> I<Regex>
+
Match values where the given regular expressions match the various fields of
the identifier of a value. If multiple regular expressions are given, B<all>
regexen must match for a value to match.
=item B<TypeInstance> I<Regex> I<Replacement>
+=item B<MetaData> I<String> I<Regex> I<Replacement>
+
+=item B<DeleteMetaData> I<String> I<Regex>
+
Match the appropriate field with the given regular expression I<Regex>. If the
regular expression matches, that part that matches is replaced with
I<Replacement>. If multiple places of the input buffer match a given regular
=item B<MetaData> I<String> I<String>
-Set the appropriate field to the given string. The strings for plugin instance
-and type instance may be empty, the strings for host and plugin may not be
-empty. It's currently not possible to set the type of a value this way.
+Set the appropriate field to the given string. The strings for plugin instance,
+type instance, and meta data may be empty, the strings for host and plugin may
+not be empty. It's currently not possible to set the type of a value this way.
+
+The following placeholders will be replaced by an appropriate value:
+
+=over 4
+
+=item B<%{host}>
+
+=item B<%{plugin}>
+
+=item B<%{plugin_instance}>
+
+=item B<%{type}>
+
+=item B<%{type_instance}>
+
+These placeholders are replaced by the identifier field of the same name.
+
+=item B<%{meta:>I<name>B<}>
+
+These placeholders are replaced by the meta data value with the given name.
+
+=back
+
+Please note that these placeholders are B<case sensitive>!
+
+=item B<DeleteMetaData> I<String>
+
+Delete the named meta data field.
=back
static int conntrack_read (void)
{
value_t conntrack, conntrack_max, conntrack_pct;
- FILE *fh;
- char buffer[64] = { 0 };
- size_t buffer_len;
- fh = fopen (old_files?CONNTRACK_FILE_OLD:CONNTRACK_FILE, "r");
- if (fh == NULL)
- return (-1);
-
- if (fgets (buffer, sizeof (buffer), fh) == NULL)
+ char const *path = old_files ? CONNTRACK_FILE_OLD : CONNTRACK_FILE;
+ if (parse_value_file (path, &conntrack, DS_TYPE_GAUGE) != 0)
{
- fclose (fh);
+ ERROR ("conntrack plugin: Reading \"%s\" failed.", path);
return (-1);
}
- fclose (fh);
- /* strip trailing newline. */
- buffer_len = strlen (buffer);
- while ((buffer_len > 0) && isspace ((int) buffer[buffer_len - 1]))
+ path = old_files ? CONNTRACK_MAX_FILE_OLD : CONNTRACK_MAX_FILE;
+ if (parse_value_file (path, &conntrack_max, DS_TYPE_GAUGE) != 0)
{
- buffer[buffer_len - 1] = 0;
- buffer_len--;
- }
-
- if (parse_value (buffer, &conntrack, DS_TYPE_GAUGE) != 0)
- return (-1);
-
- conntrack_submit ("conntrack", NULL, conntrack);
-
- fh = fopen (old_files?CONNTRACK_MAX_FILE_OLD:CONNTRACK_MAX_FILE, "r");
- if (fh == NULL)
- return (-1);
-
- memset (buffer, 0, sizeof (buffer));
- if (fgets (buffer, sizeof (buffer), fh) == NULL)
- {
- fclose (fh);
+ ERROR ("conntrack plugin: Reading \"%s\" failed.", path);
return (-1);
}
- fclose (fh);
-
- /* strip trailing newline. */
- buffer_len = strlen (buffer);
- while ((buffer_len > 0) && isspace ((int) buffer[buffer_len - 1]))
- {
- buffer[buffer_len - 1] = 0;
- buffer_len--;
- }
-
- if (parse_value (buffer, &conntrack_max, DS_TYPE_GAUGE) != 0)
- return (-1);
- conntrack_submit ("conntrack", "max", conntrack_max);
conntrack_pct.gauge = (conntrack.gauge / conntrack_max.gauge) * 100;
- conntrack_submit ("percent", "used", conntrack_pct);
+ conntrack_submit ("conntrack", NULL, conntrack);
+ conntrack_submit ("conntrack", "max", conntrack_max);
+ conntrack_submit ("percent", "used", conntrack_pct);
return (0);
} /* static int conntrack_read */
#include "common.h"
#include "plugin.h"
-#define MODULE_NAME "cpufreq"
-
static int num_cpu = 0;
static int cpufreq_init (void)
return (0);
} /* int cpufreq_init */
-static void cpufreq_submit (int cpu_num, double value)
+static void cpufreq_submit (int cpu_num, value_t value)
{
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].gauge = value;
-
- vl.values = values;
+ vl.values = &value;
vl.values_len = 1;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "cpufreq", sizeof (vl.plugin));
sstrncpy (vl.type, "cpufreq", sizeof (vl.type));
- ssnprintf (vl.type_instance, sizeof (vl.type_instance),
- "%i", cpu_num);
+ ssnprintf (vl.type_instance, sizeof (vl.type_instance), "%i", cpu_num);
plugin_dispatch_values (&vl);
}
static int cpufreq_read (void)
{
- int status;
- unsigned long long val;
- FILE *fp;
- char filename[256];
- char buffer[16];
-
for (int i = 0; i < num_cpu; i++)
{
- status = ssnprintf (filename, sizeof (filename),
- "/sys/devices/system/cpu/cpu%d/cpufreq/"
- "scaling_cur_freq", i);
- if ((status < 1) || ((unsigned int)status >= sizeof (filename)))
- return (-1);
+ char filename[PATH_MAX];
+ ssnprintf (filename, sizeof (filename),
+ "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
- if ((fp = fopen (filename, "r")) == NULL)
+ value_t v;
+ if (parse_value_file (filename, &v, DS_TYPE_GAUGE) != 0)
{
- char errbuf[1024];
- WARNING ("cpufreq: fopen (%s): %s", filename,
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- return (-1);
+ WARNING ("cpufreq plugin: Reading \"%s\" failed.", filename);
+ continue;
}
- if (fgets (buffer, 16, fp) == NULL)
- {
- char errbuf[1024];
- WARNING ("cpufreq: fgets: %s",
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- fclose (fp);
- return (-1);
- }
-
- if (fclose (fp))
- {
- char errbuf[1024];
- WARNING ("cpufreq: fclose: %s",
- sstrerror (errno, errbuf,
- sizeof (errbuf)));
- }
-
-
- /* You're seeing correctly: The file is reporting kHz values.. */
- val = atoll (buffer) * 1000;
+ /* convert kHz to Hz */
+ v.gauge *= 1000.0;
- cpufreq_submit (i, val);
+ cpufreq_submit (i, v);
}
return (0);
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);
+ &(user_data_t) {
+ .data = db,
+ .free_func = cj_free,
+ });
sfree (cb_name);
}
else
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);
+ /* interval = */ 0,
+ &(user_data_t) {
+ .data = db,
+ .free_func = cx_free,
+ });
sfree (cb_name);
}
else
return (0);
} /* int parse_values */
+int parse_value_file (char const *path, value_t *ret_value, int ds_type)
+{
+ char buffer[256];
+
+ if (read_file_contents (path, buffer, sizeof (buffer)) < 0)
+ return errno;
+
+ strstripnewline (buffer);
+
+ return parse_value (buffer, ret_value, ds_type);
+} /* int parse_value_file */
+
#if !HAVE_GETPWNAM_R
int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
size_t buflen, struct passwd **pwbufp)
int parse_value (const char *value, value_t *ret_value, int ds_type);
int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds);
+/* parse_value_file reads "path" and parses its content as an integer or
+ * floating point, depending on "ds_type". On success, the value is stored in
+ * "ret_value" and zero is returned. On failure, a non-zero value is returned. */
+int parse_value_file (char const *path, value_t *ret_value, int ds_type);
+
#if !HAVE_GETPWNAM_R
int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf,
size_t buflen, struct passwd **pwbufp);
#include "collectd.h"
+#include "common.h"
#include "plugin.h"
#include "meta_data.h"
+#define MD_MAX_NONSTRING_CHARS 128
+
/*
* Data types
*/
return (0);
} /* }}} int meta_data_get_boolean */
+int meta_data_as_string (meta_data_t *md, /* {{{ */
+ const char *key, char **value)
+{
+ meta_entry_t *e;
+ char *actual;
+ char buffer[MD_MAX_NONSTRING_CHARS]; /* For non-string types. */
+ char *temp;
+ int type;
+
+ if ((md == NULL) || (key == NULL) || (value == NULL))
+ return (-EINVAL);
+
+ pthread_mutex_lock (&md->lock);
+
+ e = md_entry_lookup (md, key);
+ if (e == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ return (-ENOENT);
+ }
+
+ type = e->type;
+
+ switch (type)
+ {
+ case MD_TYPE_STRING:
+ actual = e->value.mv_string;
+ break;
+ case MD_TYPE_SIGNED_INT:
+ ssnprintf (buffer, sizeof (buffer), "%"PRIi64, e->value.mv_signed_int);
+ actual = buffer;
+ break;
+ case MD_TYPE_UNSIGNED_INT:
+ ssnprintf (buffer, sizeof (buffer), "%"PRIu64, e->value.mv_unsigned_int);
+ actual = buffer;
+ break;
+ case MD_TYPE_DOUBLE:
+ ssnprintf (buffer, sizeof (buffer), GAUGE_FORMAT, e->value.mv_double);
+ actual = buffer;
+ break;
+ case MD_TYPE_BOOLEAN:
+ actual = e->value.mv_boolean ? "true" : "false";
+ break;
+ default:
+ pthread_mutex_unlock (&md->lock);
+ ERROR ("meta_data_as_string: unknown type %d for key `%s'", type, key);
+ return (-ENOENT);
+ }
+
+ pthread_mutex_unlock (&md->lock);
+
+ temp = md_strdup (actual);
+ if (temp == NULL)
+ {
+ pthread_mutex_unlock (&md->lock);
+ ERROR ("meta_data_as_string: md_strdup failed for key `%s'.", key);
+ return (-ENOMEM);
+ }
+
+ *value = temp;
+
+ return (0);
+} /* }}} int meta_data_as_string */
+
/* vim: set sw=2 sts=2 et fdm=marker : */
const char *key,
_Bool *value);
+/* Returns the value as a string, regardless of the type. */
+int meta_data_as_string (meta_data_t *md,
+ const char *key,
+ char **value);
+
#endif /* META_DATA_H */
/* vim: set sw=2 sts=2 et : */
}
else
{
- char *name = NULL;
-
databases = temp;
databases[databases_num] = db;
databases_num++;
- name = ssnprintf_alloc("dbi:%s", db->name);
-
- user_data_t ud = {
- .data = db
- };
-
+ char *name = ssnprintf_alloc("dbi:%s", db->name);
plugin_register_complex_read (/* group = */ NULL,
/* name = */ name ? name : db->name,
/* callback = */ cdbi_read_database,
/* interval = */ (db->interval > 0) ? db->interval : 0,
- /* user_data = */ &ud);
- free (name);
+ &(user_data_t) {
+ .data = db,
+ });
+ sfree (name);
}
}
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;
#define ENTROPY_FILE "/proc/sys/kernel/random/entropy_avail"
-static void entropy_submit (double entropy)
+static void entropy_submit (value_t value)
{
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].gauge = entropy;
-
- vl.values = values;
+ vl.values = &value;
vl.values_len = 1;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
sstrncpy (vl.plugin, "entropy", sizeof (vl.plugin));
static int entropy_read (void)
{
- double entropy;
- FILE *fh;
- char buffer[64];
-
- fh = fopen (ENTROPY_FILE, "r");
- if (fh == NULL)
- return (-1);
-
- if (fgets (buffer, sizeof (buffer), fh) == NULL)
+ value_t v;
+ if (parse_value_file (ENTROPY_FILE, &v, DS_TYPE_GAUGE) != 0)
{
- fclose (fh);
+ ERROR ("entropy plugin: Reading \""ENTROPY_FILE"\" failed.");
return (-1);
}
- fclose (fh);
-
- entropy = atof (buffer);
-
- if (entropy > 0.0)
- entropy_submit (entropy);
+ entropy_submit (v);
return (0);
}
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);
+}
+
DEBUG ("java plugin: Registering new read callback: %s", cbi->name);
- 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);
+ /* interval = */ 0, &(user_data_t) {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef (jvm_env, o_read);
DEBUG ("java plugin: Registering new write callback: %s", cbi->name);
- user_data_t ud = {
- .data = cbi,
- .free_func = cjni_callback_info_destroy
- };
-
- plugin_register_write (cbi->name, cjni_write, &ud);
+ plugin_register_write (cbi->name, cjni_write, &(user_data_t) {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef (jvm_env, o_write);
DEBUG ("java plugin: Registering new flush callback: %s", cbi->name);
- user_data_t ud = {
- .data = cbi,
- .free_func = cjni_callback_info_destroy
- };
-
- plugin_register_flush (cbi->name, cjni_flush, &ud);
+ plugin_register_flush (cbi->name, cjni_flush, &(user_data_t) {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef (jvm_env, o_flush);
DEBUG ("java plugin: Registering new log callback: %s", cbi->name);
- user_data_t ud = {
- .data = cbi,
- .free_func = cjni_callback_info_destroy
- };
-
- plugin_register_log (cbi->name, cjni_log, &ud);
+ plugin_register_log (cbi->name, cjni_log, &(user_data_t) {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef (jvm_env, o_log);
DEBUG ("java plugin: Registering new notification callback: %s", cbi->name);
- user_data_t ud = {
- .data = cbi,
- .free_func = cjni_callback_info_destroy
- };
-
- plugin_register_notification (cbi->name, cjni_notification, &ud);
+ plugin_register_notification (cbi->name, cjni_notification, &(user_data_t) {
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef (jvm_env, o_notification);
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);
+ &(user_data_t) {
+ .data = cb,
+ });
if (status != 0)
return luaL_error(L, "%s", "plugin_register_complex_read failed");
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);
+ &(user_data_t) {
+ .data = cb,
+ });
if (status != 0)
return luaL_error(L, "%s", "plugin_register_write failed");
#include "collectd.h"
+#include "common.h"
#include "filter_chain.h"
+#include "meta_data.h"
+#include "utils_llist.h"
#include <sys/types.h>
#include <regex.h>
mr_regex_t *plugin_instance;
mr_regex_t *type;
mr_regex_t *type_instance;
+ llist_t *meta; /* Maps each meta key into mr_regex_t* */
_Bool invert;
};
regfree (&r->re);
memset (&r->re, 0, sizeof (r->re));
- free (r->re_str);
+ sfree (r->re_str);
if (r->next != NULL)
mr_free_regex (r->next);
mr_free_regex (m->plugin_instance);
mr_free_regex (m->type);
mr_free_regex (m->type_instance);
+ for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next)
+ {
+ sfree (e->key);
+ mr_free_regex ((mr_regex_t *) e->value);
+ }
+ llist_destroy (m->meta);
- free (m);
+ sfree (m);
} /* }}} void mr_free_match */
static int mr_match_regexen (mr_regex_t *re_head, /* {{{ */
return (FC_MATCH_MATCHES);
} /* }}} int mr_match_regexen */
-static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
- oconfig_item_t *ci)
+static int mr_add_regex (mr_regex_t **re_head, const char *re_str, /* {{{ */
+ const char *option)
{
mr_regex_t *re;
int status;
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
- {
- log_warn ("`%s' needs exactly one string argument.", ci->key);
- return (-1);
- }
-
re = calloc (1, sizeof (*re));
if (re == NULL)
{
- log_err ("mr_config_add_regex: calloc failed.");
+ log_err ("mr_add_regex: calloc failed.");
return (-1);
}
re->next = NULL;
- re->re_str = strdup (ci->values[0].value.string);
+ re->re_str = strdup (re_str);
if (re->re_str == NULL)
{
- free (re);
- log_err ("mr_config_add_regex: strdup failed.");
+ sfree (re);
+ log_err ("mr_add_regex: strdup failed.");
return (-1);
}
regerror (status, &re->re, errmsg, sizeof (errmsg));
errmsg[sizeof (errmsg) - 1] = 0;
log_err ("Compiling regex `%s' for `%s' failed: %s.",
- re->re_str, ci->key, errmsg);
- free (re->re_str);
- free (re);
+ re->re_str, option, errmsg);
+ sfree (re->re_str);
+ sfree (re);
return (-1);
}
}
return (0);
+} /* }}} int mr_add_regex */
+
+static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
+ oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ log_warn ("`%s' needs exactly one string argument.", ci->key);
+ return (-1);
+ }
+
+ return mr_add_regex (re_head, ci->values[0].value.string, ci->key);
} /* }}} int mr_config_add_regex */
+static int mr_config_add_meta_regex (llist_t **meta, /* {{{ */
+ oconfig_item_t *ci)
+{
+ char *meta_key;
+ llentry_t *entry;
+ mr_regex_t *re_head;
+ int status;
+ char buffer[1024];
+
+ if ((ci->values_num != 2)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || (ci->values[1].type != OCONFIG_TYPE_STRING))
+ {
+ log_warn ("`%s' needs exactly two string arguments.", ci->key);
+ return (-1);
+ }
+
+ if (*meta == NULL)
+ {
+ *meta = llist_create();
+ if (*meta == NULL)
+ {
+ log_err ("mr_config_add_meta_regex: llist_create failed.");
+ return (-1);
+ }
+ }
+
+ meta_key = ci->values[0].value.string;
+ entry = llist_search (*meta, meta_key);
+ if (entry == NULL)
+ {
+ meta_key = strdup (meta_key);
+ if (meta_key == NULL)
+ {
+ log_err ("mr_config_add_meta_regex: strdup failed.");
+ return (-1);
+ }
+ entry = llentry_create (meta_key, NULL);
+ if (entry == NULL)
+ {
+ log_err ("mr_config_add_meta_regex: llentry_create failed.");
+ sfree (meta_key);
+ return (-1);
+ }
+ /* meta_key and entry will now be freed by mr_free_match(). */
+ llist_append (*meta, entry);
+ }
+
+ ssnprintf (buffer, sizeof (buffer), "%s `%s'", ci->key, meta_key);
+ /* Can't pass &entry->value into mr_add_regex, so copy in/out. */
+ re_head = entry->value;
+ status = mr_add_regex (&re_head, ci->values[1].value.string, buffer);
+ if (status == 0) {
+ entry->value = re_head;
+ }
+ return status;
+} /* }}} int mr_config_add_meta_regex */
+
static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
{
mr_match_t *m;
status = mr_config_add_regex (&m->type, child);
else if (strcasecmp ("TypeInstance", child->key) == 0)
status = mr_config_add_regex (&m->type_instance, child);
+ else if (strcasecmp ("MetaData", child->key) == 0)
+ status = mr_config_add_meta_regex (&m->meta, child);
else if (strcasecmp ("Invert", child->key) == 0)
status = cf_util_get_boolean(child, &m->invert);
else
&& (m->plugin == NULL)
&& (m->plugin_instance == NULL)
&& (m->type == NULL)
- && (m->type_instance == NULL))
+ && (m->type_instance == NULL)
+ && (m->meta == NULL))
{
log_err ("No (valid) regular expressions have been configured. "
"This match will be ignored.");
if (mr_match_regexen (m->type_instance,
vl->type_instance) == FC_MATCH_NO_MATCH)
return (nomatch_value);
+ if (vl->meta != NULL)
+ {
+ for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next)
+ {
+ mr_regex_t *meta_re = (mr_regex_t *) e->value;
+ char *value;
+ int status = meta_data_get_string (vl->meta, e->key, &value);
+ if (status == (-ENOENT)) /* key is not present */
+ return (nomatch_value);
+ if (status != 0) /* some other problem */
+ continue; /* error will have already been printed. */
+ if (mr_match_regexen (meta_re, value) == FC_MATCH_NO_MATCH)
+ {
+ sfree (value);
+ return (nomatch_value);
+ }
+ sfree (value);
+ }
+ }
return (match_value);
} /* }}} int mr_match */
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,
/* interval = */ 0,
- /* user_data = */ &ud);
+ &(user_data_t) {
+ .data = st,
+ .free_func = memcached_free,
+ });
+
return (status);
} /* int memcached_add_read_callback */
}
else if (host->conntype == MBCONN_TCP)
{
- struct sockaddr sockaddr;
- socklen_t saddrlen = sizeof (sockaddr);
-
+ /* getpeername() is used only to determine if the socket is connected, not
+ * because we're really interested in the peer's IP address. */
status = getpeername (modbus_get_socket (host->connection),
- &sockaddr, &saddrlen);
+ (struct sockaddr *) &(struct sockaddr_storage) { 0 },
+ &(socklen_t) { sizeof (struct sockaddr_storage) });
if (status != 0)
status = errno;
}
if (status == 0)
{
- user_data_t ud;
char name[1024];
- ud.data = host;
- ud.free_func = host_free;
-
ssnprintf (name, sizeof (name), "modbus-%s", host->host);
plugin_register_complex_read (/* group = */ NULL, name,
/* callback = */ mb_read,
/* interval = */ host->interval,
- &ud);
+ &(user_data_t) {
+ .data = host,
+ .free_func = host_free,
+ });
}
else
{
}
ssnprintf (cb_name, sizeof (cb_name), "mqtt/%s", conf->name);
- user_data_t user_data = {
- .data = conf
- };
-
- plugin_register_write (cb_name, mqtt_write, &user_data);
+ plugin_register_write (cb_name, mqtt_write, &(user_data_t) {
+ .data = conf,
+ });
return (0);
} /* mqtt_config_publisher */
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);
+ mysql_read, /* interval = */ 0, &(user_data_t) {
+ .data = db,
+ .free_func = mysql_database_free,
+ });
}
else
{
else
ssnprintf (cb_name, sizeof (cb_name), "netapp-%s", host->name);
- user_data_t ud = {
- .data = host,
- .free_func = (void (*) (void *)) free_host_config
- };
-
plugin_register_complex_read (/* group = */ NULL, cb_name,
/* callback = */ cna_read,
/* interval = */ host->interval,
- /* user data = */ &ud);
+ &(user_data_t) {
+ .data = host,
+ .free_func = (void *) free_host_config,
+ });
return (0);
} /* }}} int cna_register_host */
char *buffer;
size_t buffer_size;
int status;
+ char errbuf[1024];
char file[4096];
char *endptr;
status = OW_get (file, &buffer, &buffer_size);
if (status < 0)
{
- ERROR ("onewire plugin: OW_get (%s/%s) failed. status = %#x;",
- path, family_info->features[i].filename, status);
+ ERROR ("onewire plugin: OW_get (%s/%s) failed. error = %s;",
+ path, family_info->features[i].filename, sstrerror(errno, errbuf, sizeof (errbuf)));
return (-1);
}
DEBUG ("Read onewire device %s as %s", file, buffer);
char *buffer;
size_t buffer_size;
int status;
+ char errbuf[1024];
char *buffer_ptr;
char *dummy;
status = OW_get (path, &buffer, &buffer_size);
if (status < 0)
{
- ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;",
- path, status);
+ ERROR ("onewire plugin: OW_get (%s) failed. error = %s;",
+ path, sstrerror(errno, errbuf, sizeof (errbuf)));
return (-1);
}
DEBUG ("onewire plugin: OW_get (%s) returned: %s",
char *buffer;
size_t buffer_size;
int status;
+ char errbuf[1024];
char *endptr;
direct_access_element_t *traverse;
status = OW_get (traverse->path, &buffer, &buffer_size);
if (status < 0)
{
- ERROR ("onewire plugin: OW_get (%s) failed. status = %#x;",
+ ERROR ("onewire plugin: OW_get (%s) failed. status = %s;",
traverse->path,
- status);
+ sstrerror(errno, errbuf, sizeof (errbuf)));
return (-1);
}
DEBUG ("onewire plugin: Read onewire device %s as %s", traverse->path, buffer);
static int cow_init (void)
{
int status;
+ char errbuf[1024];
if (device_g == NULL)
{
status = (int) OW_init (device_g);
if (status != 0)
{
- ERROR ("onewire plugin: OW_init(%s) failed: %i.", device_g, status);
+ ERROR ("onewire plugin: OW_init(%s) failed: %s.", device_g, sstrerror(errno, errbuf, sizeof (errbuf)));
return (1);
}
(st->host != NULL) ? st->host : hostname_g,
(st->name != NULL) ? st->name : "default");
- user_data_t ud = {
- .data = st
- };
-
status = plugin_register_complex_read (/* group = */ NULL,
/* name = */ callback_name,
/* callback = */ cldap_read_host,
/* interval = */ 0,
- /* user_data = */ &ud);
+ &(user_data_t) {
+ .data = st,
+ });
}
}
c->data = data;
c->next = NULL;
- user_data_t user_data = {
- .data = c,
- .free_func = cpy_destroy_user_data
- };
+ register_function(buf, handler, &(user_data_t) {
+ .data = c,
+ .free_func = cpy_destroy_user_data,
+ });
- register_function(buf, handler, &user_data);
++cpy_num_callbacks;
return cpy_string_to_unicode_or_bytes(buf);
}
c->data = data;
c->next = NULL;
- 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);
+ cpy_read_callback, DOUBLE_TO_CDTIME_T (interval),
+ &(user_data_t) {
+ .data = c,
+ .free_func = cpy_destroy_user_data,
+ });
++cpy_num_callbacks;
return cpy_string_to_unicode_or_bytes(buf);
}
{
cr_data_t *router_data;
char read_name[128];
- user_data_t user_data;
int status;
router_data = calloc (1, sizeof (*router_data));
}
ssnprintf (read_name, sizeof (read_name), "routeros/%s", router_data->node);
- user_data.data = router_data;
- user_data.free_func = (void *) cr_free_data;
if (status == 0)
status = plugin_register_complex_read (/* group = */ NULL, read_name,
- cr_read, /* interval = */ 0, &user_data);
+ cr_read, /* interval = */ 0, &(user_data_t) {
+ .data = router_data,
+ .free_func = (void *) cr_free_data,
+ });
if (status != 0)
cr_free_data (router_data);
ssnprintf (cb_name, sizeof (cb_name), "snmp-%s", hd->name);
- 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 = */ &ud);
+ csnmp_read_host, hd->interval, &(user_data_t) {
+ .data = hd,
+ .free_func = csnmp_host_definition_destroy,
+ });
if (status != 0)
{
ERROR ("snmp plugin: Registering complex read function failed.");
{
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);
+ plugin_register_complex_read (NULL, str, ctail_read, tail_match_list_intervals[i],
+ &(user_data_t) {
+ .data = tail_match_list[i],
+ });
}
return (0);
ssnprintf (cb_name, sizeof (cb_name), "tail_csv/%s", id->path);
- 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);
-
+ status = plugin_register_complex_read(NULL, cb_name, tcsv_read, id->interval,
+ &(user_data_t) {
+ .data = id,
+ .free_func = tcsv_instance_definition_destroy,
+ });
if (status != 0){
ERROR("tail_csv plugin: Registering complex read function failed.");
tcsv_instance_definition_destroy(id);
{
regex_t re;
char *replacement;
- int may_be_empty;
+ _Bool may_be_empty;
tr_action_t *next;
};
+struct tr_meta_data_action_s;
+typedef struct tr_meta_data_action_s tr_meta_data_action_t;
+struct tr_meta_data_action_s
+{
+ char *key;
+ regex_t re;
+ char *replacement;
+
+ tr_meta_data_action_t *next;
+};
+
struct tr_data_s
{
tr_action_t *host;
tr_action_t *plugin_instance;
/* tr_action_t *type; */
tr_action_t *type_instance;
+ tr_meta_data_action_t *meta;
};
typedef struct tr_data_s tr_data_t;
sfree (act);
} /* }}} void tr_action_destroy */
+static void tr_meta_data_action_destroy (tr_meta_data_action_t *act) /* {{{ */
+{
+ if (act == NULL)
+ return;
+
+ sfree (act->key);
+ regfree (&act->re);
+ sfree (act->replacement);
+
+ if (act->next != NULL)
+ tr_meta_data_action_destroy (act->next);
+
+ sfree (act);
+} /* }}} void tr_meta_data_action_destroy */
+
static int tr_config_add_action (tr_action_t **dest, /* {{{ */
- const oconfig_item_t *ci, int may_be_empty)
+ const oconfig_item_t *ci, _Bool may_be_empty)
{
tr_action_t *act;
int status;
if (act->replacement == NULL)
{
ERROR ("tr_config_add_action: tr_strdup failed.");
- regfree (&act->re);
- sfree (act);
+ tr_action_destroy (act);
return (-ENOMEM);
}
return (0);
} /* }}} int tr_config_add_action */
+static int tr_config_add_meta_action (tr_meta_data_action_t **dest, /* {{{ */
+ const oconfig_item_t *ci, _Bool should_delete)
+{
+ tr_meta_data_action_t *act;
+ int status;
+
+ if (dest == NULL)
+ return (-EINVAL);
+
+ if (should_delete)
+ {
+ if ((ci->values_num != 2)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || (ci->values[1].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("Target `replace': The `%s' option requires exactly two string "
+ "arguments.", ci->key);
+ return (-1);
+ }
+ }
+ else
+ {
+ if ((ci->values_num != 3)
+ || (ci->values[0].type != OCONFIG_TYPE_STRING)
+ || (ci->values[1].type != OCONFIG_TYPE_STRING)
+ || (ci->values[2].type != OCONFIG_TYPE_STRING))
+ {
+ ERROR ("Target `replace': The `%s' option requires exactly three string "
+ "arguments.", ci->key);
+ return (-1);
+ }
+ }
+
+ if (strlen (ci->values[0].value.string) == 0)
+ {
+ ERROR ("Target `replace': The `%s' option does not accept empty string as "
+ "first argument.", ci->key);
+ return (-1);
+ }
+
+ act = calloc (1, sizeof (*act));
+ if (act == NULL)
+ {
+ ERROR ("tr_config_add_meta_action: calloc failed.");
+ return (-ENOMEM);
+ }
+
+ act->key = NULL;
+ act->replacement = NULL;
+
+ status = regcomp (&act->re, ci->values[1].value.string, REG_EXTENDED);
+ if (status != 0)
+ {
+ char errbuf[1024] = "";
+
+ /* regerror assures null termination. */
+ regerror (status, &act->re, errbuf, sizeof (errbuf));
+ ERROR ("Target `replace': Compiling the regular expression `%s' "
+ "failed: %s.",
+ ci->values[1].value.string, errbuf);
+ sfree (act->key);
+ sfree (act);
+ return (-EINVAL);
+ }
+
+ act->key = tr_strdup (ci->values[0].value.string);
+ if (act->key == NULL)
+ {
+ ERROR ("tr_config_add_meta_action: tr_strdup failed.");
+ tr_meta_data_action_destroy (act);
+ return (-ENOMEM);
+ }
+
+ if (!should_delete) {
+ act->replacement = tr_strdup (ci->values[2].value.string);
+ if (act->replacement == NULL)
+ {
+ ERROR ("tr_config_add_meta_action: tr_strdup failed.");
+ tr_meta_data_action_destroy (act);
+ return (-ENOMEM);
+ }
+ }
+
+ /* Insert action at end of list. */
+ if (*dest == NULL)
+ *dest = act;
+ else
+ {
+ tr_meta_data_action_t *prev;
+
+ prev = *dest;
+ while (prev->next != NULL)
+ prev = prev->next;
+
+ prev->next = act;
+ }
+
+ return (0);
+} /* }}} int tr_config_add_meta_action */
+
static int tr_action_invoke (tr_action_t *act_head, /* {{{ */
- char *buffer_in, size_t buffer_in_size, int may_be_empty)
+ char *buffer_in, size_t buffer_in_size, _Bool may_be_empty)
{
int status;
char buffer[DATA_MAX_NAME_LEN];
return (0);
} /* }}} int tr_action_invoke */
+static int tr_meta_data_action_invoke ( /* {{{ */
+ tr_meta_data_action_t *act_head, meta_data_t **dest)
+{
+ int status;
+ regmatch_t matches[8] = { [0] = { 0 } };
+
+ if (act_head == NULL)
+ return (-EINVAL);
+
+ if ((*dest) == NULL) /* nothing to do */
+ return (0);
+
+ for (tr_meta_data_action_t *act = act_head; act != NULL; act = act->next)
+ {
+ char temp[DATA_MAX_NAME_LEN];
+ char *subst_status;
+ int value_type;
+ int meta_data_status;
+ char *value;
+ meta_data_t *result;
+
+ value_type = meta_data_type (*dest, act->key);
+ if (value_type == 0) /* not found */
+ continue;
+ if (value_type != MD_TYPE_STRING)
+ {
+ WARNING ("Target `replace': Attempting replace on metadata key `%s', "
+ "which isn't a string.",
+ act->key);
+ continue;
+ }
+
+ meta_data_status = meta_data_get_string (*dest, act->key, &value);
+ if (meta_data_status != 0)
+ {
+ ERROR ("Target `replace': Unable to retrieve metadata value for `%s'.",
+ act->key);
+ return (meta_data_status);
+ }
+
+ DEBUG ("target_replace plugin: tr_meta_data_action_invoke: `%s' "
+ "old value = `%s'", act->key, value);
+
+ status = regexec (&act->re, value,
+ STATIC_ARRAY_SIZE (matches), matches,
+ /* flags = */ 0);
+ if (status == REG_NOMATCH)
+ {
+ sfree (value);
+ continue;
+ }
+ else if (status != 0)
+ {
+ char errbuf[1024] = "";
+
+ regerror (status, &act->re, errbuf, sizeof (errbuf));
+ ERROR ("Target `replace': Executing a regular expression failed: %s.",
+ errbuf);
+ sfree (value);
+ continue;
+ }
+
+ if (act->replacement == NULL)
+ {
+ /* no replacement; delete the key */
+ DEBUG ("target_replace plugin: tr_meta_data_action_invoke: "
+ "deleting `%s'", act->key);
+ meta_data_delete (*dest, act->key);
+ sfree (value);
+ continue;
+ }
+
+ subst_status = subst (temp, sizeof (temp), value,
+ (size_t) matches[0].rm_so, (size_t) matches[0].rm_eo, act->replacement);
+ if (subst_status == NULL)
+ {
+ ERROR ("Target `replace': subst (value = %s, start = %zu, end = %zu, "
+ "replacement = %s) failed.",
+ value, (size_t) matches[0].rm_so, (size_t) matches[0].rm_eo,
+ act->replacement);
+ sfree (value);
+ continue;
+ }
+
+ DEBUG ("target_replace plugin: tr_meta_data_action_invoke: `%s' "
+ "value `%s' -> `%s'", act->key, value, temp);
+
+ if ((result = meta_data_create()) == NULL)
+ {
+ ERROR ("Target `replace': failed to create metadata for `%s'.",
+ act->key);
+ sfree (value);
+ return (-ENOMEM);
+ }
+
+ meta_data_status = meta_data_add_string (result, act->key, temp);
+ if (meta_data_status != 0)
+ {
+ ERROR ("Target `replace': Unable to set metadata value for `%s'.",
+ act->key);
+ meta_data_destroy (result);
+ sfree (value);
+ return (meta_data_status);
+ }
+
+ meta_data_clone_merge (dest, result);
+ meta_data_destroy (result);
+ sfree (value);
+ } /* for (act = act_head; act != NULL; act = act->next) */
+
+ return (0);
+} /* }}} int tr_meta_data_action_invoke */
+
static int tr_destroy (void **user_data) /* {{{ */
{
tr_data_t *data;
tr_action_destroy (data->plugin_instance);
/* tr_action_destroy (data->type); */
tr_action_destroy (data->type_instance);
+ tr_meta_data_action_destroy (data->meta);
sfree (data);
return (0);
data->plugin_instance = NULL;
/* data->type = NULL; */
data->type_instance = NULL;
+ data->meta = NULL;
status = 0;
for (int i = 0; i < ci->children_num; i++)
else if (strcasecmp ("TypeInstance", child->key) == 0)
status = tr_config_add_action (&data->type_instance, child,
/* may be empty = */ 1);
+ else if (strcasecmp ("MetaData", child->key) == 0)
+ status = tr_config_add_meta_action (&data->meta, child,
+ /* should delete = */ 0);
+ else if (strcasecmp ("DeleteMetaData", child->key) == 0)
+ status = tr_config_add_meta_action (&data->meta, child,
+ /* should delete = */ 1);
else
{
ERROR ("Target `replace': The `%s' configuration option is not understood "
&& (data->plugin == NULL)
&& (data->plugin_instance == NULL)
/* && (data->type == NULL) */
- && (data->type_instance == NULL))
+ && (data->type_instance == NULL)
+ && (data->meta == NULL))
{
ERROR ("Target `replace': You need to set at least one of `Host', "
"`Plugin', `PluginInstance' or `TypeInstance'.");
return (-EINVAL);
}
+ if (data->meta != NULL)
+ {
+ tr_meta_data_action_invoke (data->meta, &(vl->meta));
+ }
+
#define HANDLE_FIELD(f,e) \
if (data->f != NULL) \
tr_action_invoke (data->f, vl->f, sizeof (vl->f), e)
HANDLE_FIELD (host, 0);
HANDLE_FIELD (plugin, 0);
HANDLE_FIELD (plugin_instance, 1);
- /* HANDLE_FIELD (type); */
+ /* HANDLE_FIELD (type, 0); */
HANDLE_FIELD (type_instance, 1);
return (FC_TARGET_CONTINUE);
#include "common.h"
#include "filter_chain.h"
+#include "meta_data.h"
+#include "utils_subst.h"
+
+struct ts_key_list_s
+{
+ char *key;
+ struct ts_key_list_s *next;
+};
+typedef struct ts_key_list_s ts_key_list_t;
+
+static void ts_key_list_free (ts_key_list_t *l) /* {{{ */
+{
+ if (l == NULL)
+ return;
+
+ sfree (l->key);
+
+ if (l->next != NULL)
+ ts_key_list_free (l->next);
+
+ sfree (l);
+} /* }}} void ts_name_list_free */
struct ts_data_s
{
/* char *type; */
char *type_instance;
meta_data_t *meta;
+ ts_key_list_t *meta_delete;
};
typedef struct ts_data_s ts_data_t;
|| (ci->values[1].type != OCONFIG_TYPE_STRING))
{
ERROR ("ts_util_get_key_and_string_wo_strdup: The %s option requires "
- "exactly two string argument.", ci->key);
+ "exactly two string arguments.", ci->key);
return (-1);
}
if (strlen (key) == 0)
{
- ERROR ("Target `set': The `%s' option does not accept empty string as first argument.",
- ci->key);
+ ERROR ("Target `set': The `%s' option does not accept empty string as "
+ "first argument.", ci->key);
return (-1);
}
if (!may_be_empty && (strlen (string) == 0))
{
- ERROR ("Target `set': The `%s' option does not accept empty string as second argument.",
- ci->key);
+ ERROR ("Target `set': The `%s' option does not accept empty string as "
+ "second argument.", ci->key);
return (-1);
}
if ((*dest) == NULL)
{
- // Create a new meta_data_t
+ /* Create a new meta_data_t */
if ((*dest = meta_data_create()) == NULL)
{
ERROR ("Target `set': failed to create a meta data for `%s'.", ci->key);
- return (-1);
+ return (-ENOMEM);
}
}
return (meta_data_add_string (*dest, key, string));
} /* }}} int ts_config_add_meta */
+static int ts_config_add_meta_delete (ts_key_list_t **dest, /* {{{ */
+ const oconfig_item_t *ci)
+{
+ ts_key_list_t *entry = NULL;
+
+ entry = calloc (1, sizeof (*entry));
+ if (entry == NULL)
+ {
+ ERROR ("ts_config_add_meta_delete: calloc failed.");
+ return (-ENOMEM);
+ }
+
+ if (cf_util_get_string (ci, &entry->key) != 0)
+ {
+ ts_key_list_free (entry);
+ return (-1); /* An error has already been reported. */
+ }
+
+ if (strlen (entry->key) == 0)
+ {
+ ERROR ("Target `set': The `%s' option does not accept empty string as "
+ "first argument.", ci->key);
+ ts_key_list_free (entry);
+ return (-1);
+ }
+
+ entry->next = *dest;
+ *dest = entry;
+
+ return (0);
+} /* }}} int ts_config_add_meta_delete */
+
+static void ts_subst (char *dest, size_t size, const char *string, /* {{{ */
+ const value_list_t *vl)
+{
+ char temp[DATA_MAX_NAME_LEN];
+
+ /* Initialize the field with the template. */
+ sstrncpy (dest, string, size);
+
+ if (strchr (dest, '%') == NULL)
+ return;
+
+#define REPLACE_FIELD(t, v) \
+ if (subst_string (temp, sizeof (temp), dest, t, v) != NULL) \
+ sstrncpy (dest, temp, size);
+ REPLACE_FIELD ("%{host}", vl->host);
+ REPLACE_FIELD ("%{plugin}", vl->plugin);
+ REPLACE_FIELD ("%{plugin_instance}", vl->plugin_instance);
+ REPLACE_FIELD ("%{type}", vl->type);
+ REPLACE_FIELD ("%{type_instance}", vl->type_instance);
+
+ if (vl->meta != NULL)
+ {
+ char **meta_toc;
+ int meta_entries = meta_data_toc (vl->meta, &meta_toc);
+ for (int i = 0; i < meta_entries; i++)
+ {
+ char meta_name[DATA_MAX_NAME_LEN];
+ char *value_str;
+ const char *key = meta_toc[i];
+
+ ssnprintf (meta_name, sizeof (meta_name), "%%{meta:%s}", key);
+ if (meta_data_as_string (vl->meta, key, &value_str) != 0)
+ continue;
+
+ REPLACE_FIELD (meta_name, value_str);
+ sfree (value_str);
+ }
+
+ strarray_free (meta_toc, (size_t) meta_entries);
+ }
+} /* }}} int ts_subst */
+
static int ts_destroy (void **user_data) /* {{{ */
{
ts_data_t *data;
/* free (data->type); */
free (data->type_instance);
meta_data_destroy(data->meta);
+ ts_key_list_free (data->meta_delete);
free (data);
return (0);
/* data->type = NULL; */
data->type_instance = NULL;
data->meta = NULL;
+ data->meta_delete = NULL;
status = 0;
for (int i = 0; i < ci->children_num; i++)
else if (strcasecmp ("MetaData", child->key) == 0)
status = ts_config_add_meta (&data->meta, child,
/* may be empty = */ 1);
+ else if (strcasecmp ("DeleteMetaData", child->key) == 0)
+ status = ts_config_add_meta_delete (&data->meta_delete, child);
else
{
ERROR ("Target `set': The `%s' configuration option is not understood "
&& (data->plugin_instance == NULL)
/* && (data->type == NULL) */
&& (data->type_instance == NULL)
- && (data->meta == NULL))
+ && (data->meta == NULL)
+ && (data->meta_delete == NULL))
{
ERROR ("Target `set': You need to set at least one of `Host', "
- "`Plugin', `PluginInstance', `TypeInstance', `MetaData'.");
+ "`Plugin', `PluginInstance', `TypeInstance', "
+ "`MetaData', or `DeleteMetaData'.");
status = -1;
}
+ if (data->meta != NULL)
+ {
+ /* If data->meta_delete is NULL, this loop is a no-op. */
+ for (ts_key_list_t *l=data->meta_delete; l != NULL; l = l->next)
+ {
+ if (meta_data_type (data->meta, l->key) != 0)
+ {
+ /* MetaData and DeleteMetaData for the same key. */
+ ERROR ("Target `set': Can only have one of `MetaData' or "
+ "`DeleteMetaData' for any given key.");
+ status = -1;
+ }
+ }
+ }
+
break;
}
notification_meta_t __attribute__((unused)) **meta, void **user_data)
{
ts_data_t *data;
+ value_list_t orig;
+ meta_data_t *new_meta = NULL;
if ((ds == NULL) || (vl == NULL) || (user_data == NULL))
return (-EINVAL);
return (-EINVAL);
}
+ orig = *vl;
+
if (data->meta != NULL)
{
- meta_data_clone_merge(&(vl->meta), data->meta);
+ char temp[DATA_MAX_NAME_LEN*2];
+ int meta_entries;
+ char **meta_toc;
+
+ if ((new_meta = meta_data_create()) == NULL)
+ {
+ ERROR ("Target `set': failed to create replacement metadata.");
+ return (-ENOMEM);
+ }
+
+ meta_entries = meta_data_toc (data->meta, &meta_toc);
+ for (int i = 0; i < meta_entries; i++)
+ {
+ const char *key = meta_toc[i];
+ char *string;
+ int status;
+
+ status = meta_data_get_string (data->meta, key, &string);
+ if (status)
+ {
+ ERROR ("Target `set': Unable to get replacement metadata value `%s'.",
+ key);
+ strarray_free (meta_toc, (size_t) meta_entries);
+ return (status);
+ }
+
+ ts_subst (temp, sizeof (temp), string, &orig);
+
+ DEBUG ("target_set: ts_invoke: setting metadata value for key `%s': "
+ "`%s'.", key, temp);
+
+ status = meta_data_add_string (new_meta, key, temp);
+
+ if (status)
+ {
+ ERROR ("Target `set': Unable to set metadata value `%s'.", key);
+ strarray_free (meta_toc, (size_t) meta_entries);
+ return (status);
+ }
+ }
+
+ strarray_free (meta_toc, (size_t) meta_entries);
+ }
+
+#define SUBST_FIELD(f) \
+ if (data->f != NULL) { \
+ ts_subst (vl->f, sizeof (vl->f), data->f, &orig); \
+ DEBUG ("target_set: ts_invoke: setting "#f": `%s'.", vl->f); \
+ }
+ SUBST_FIELD (host);
+ SUBST_FIELD (plugin);
+ SUBST_FIELD (plugin_instance);
+ /* SUBST_FIELD (type); */
+ SUBST_FIELD (type_instance);
+
+ /* Need to merge the metadata in now, because of the shallow copy. */
+ if (new_meta != NULL)
+ {
+ meta_data_clone_merge(&(vl->meta), new_meta);
+ meta_data_destroy(new_meta);
}
-#define SET_FIELD(f) if (data->f != NULL) { sstrncpy (vl->f, data->f, sizeof (vl->f)); }
- SET_FIELD (host);
- SET_FIELD (plugin);
- SET_FIELD (plugin_instance);
- /* SET_FIELD (type); */
- SET_FIELD (type_instance);
+ /* If data->meta_delete is NULL, this loop is a no-op. */
+ for (ts_key_list_t *l=data->meta_delete; l != NULL; l = l->next)
+ {
+ DEBUG ("target_set: ts_invoke: deleting metadata value for key `%s'.",
+ l->key);
+ meta_data_delete(vl->meta, l->key);
+ }
return (FC_TARGET_CONTINUE);
} /* }}} int ts_invoke */
};
static void thermal_submit (const char *plugin_instance, enum dev_type dt,
- gauge_t value)
+ value_t value)
{
value_list_t vl = VALUE_LIST_INIT;
- value_t v;
-
- v.gauge = value;
- vl.values = &v;
+ vl.values = &value;
vl.values_len = 1;
sstrncpy (vl.host, hostname_g, sizeof (vl.host));
static int thermal_sysfs_device_read (const char __attribute__((unused)) *dir,
const char *name, void __attribute__((unused)) *user_data)
{
- char filename[256];
- char data[1024];
- int len;
+ char filename[PATH_MAX];
_Bool success = 0;
+ value_t value;
if (device_list && ignorelist_match (device_list, name))
return -1;
- len = ssnprintf (filename, sizeof (filename),
- "%s/%s/temp", dirname_sysfs, name);
- if ((len < 0) || ((size_t) len >= sizeof (filename)))
- return -1;
-
- len = (ssize_t) read_file_contents (filename, data, sizeof(data));
- if (len > 1 && data[--len] == '\n') {
- char *endptr = NULL;
- double temp;
-
- data[len] = 0;
- errno = 0;
- temp = strtod (data, &endptr) / 1000.0;
-
- if (endptr == data + len && errno == 0) {
- thermal_submit(name, TEMP, temp);
- success = 1;
- }
+ ssnprintf (filename, sizeof (filename), "%s/%s/temp", dirname_sysfs, name);
+ if (parse_value_file (filename, &value, DS_TYPE_GAUGE) == 0)
+ {
+ value.gauge /= 1000.0;
+ thermal_submit(name, TEMP, value);
+ success = 1;
}
- len = ssnprintf (filename, sizeof (filename),
- "%s/%s/cur_state", dirname_sysfs, name);
- if ((len < 0) || ((size_t) len >= sizeof (filename)))
- return -1;
-
- len = (ssize_t) read_file_contents (filename, data, sizeof(data));
- if (len > 1 && data[--len] == '\n') {
- char *endptr = NULL;
- double state;
-
- data[len] = 0;
- errno = 0;
- state = strtod (data, &endptr);
-
- if (endptr == data + len && errno == 0) {
- thermal_submit(name, COOLING_DEV, state);
- success = 1;
- }
+ ssnprintf (filename, sizeof (filename), "%s/%s/cur_state", dirname_sysfs, name);
+ if (parse_value_file (filename, &value, DS_TYPE_GAUGE) == 0)
+ {
+ thermal_submit(name, COOLING_DEV, value);
+ success = 1;
}
return (success ? 0 : -1);
temp = (strtod (data + len, &endptr) + add) * factor;
if (endptr != data + len && errno == 0) {
- thermal_submit(name, TEMP, temp);
+ thermal_submit(name, TEMP, (value_t) { .gauge = temp });
return 0;
}
}
{
va_list args;
char path[PATH_MAX];
- FILE *filep;
- int len, value;
+ int len;
va_start(args, fmt);
len = vsnprintf(path, sizeof(path), fmt, args);
return -1;
}
- filep = fopen(path, "r");
- if (!filep) {
- ERROR("turbostat plugin: Failed to open '%s'", path);
- return -1;
- }
- if (fscanf(filep, "%d", &value) != 1) {
- ERROR("turbostat plugin: Failed to parse number from '%s'", path);
- fclose(filep);
+ value_t v;
+ if (parse_value_file (path, &v, DS_TYPE_DERIVE) != 0) {
+ ERROR ("turbostat plugin: Parsing \"%s\" failed.", path);
return -1;
}
- fclose(filep);
- return value;
+
+ return (int) v.derive;
}
static int
email_check value:GAUGE:0:U
email_count value:GAUGE:0:U
email_size value:GAUGE:0:U
+energy value:GAUGE:U:U
+energy_wh value:GAUGE:U:U
entropy value:GAUGE:0:4294967295
evicted_keys value:DERIVE:0:U
expired_keys value:DERIVE:0:U
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
sstrncpy (tmp_plugin, n_plugin, sizeof (tmp_plugin));
if (n_type_instance[0] != '\0')
- ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
- n_type,
- (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-',
- n_type_instance);
+ {
+ if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(n_plugin, n_type) == 0)
+ sstrncpy (tmp_type, n_type_instance, sizeof (tmp_type));
+ else
+ ssnprintf (tmp_type, sizeof (tmp_type), "%s%c%s",
+ n_type,
+ (flags & GRAPHITE_SEPARATE_INSTANCES) ? '.' : '-',
+ n_type_instance);
+ }
else
sstrncpy (tmp_type, n_type, sizeof (tmp_type));
/* Assert always_append_ds -> ds_name */
assert (!(flags & GRAPHITE_ALWAYS_APPEND_DS) || (ds_name != NULL));
if (ds_name != NULL)
- ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
- prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
+ {
+ if ((flags & GRAPHITE_DROP_DUPE_FIELDS) && strcmp(tmp_plugin, tmp_type) == 0)
+ ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
+ prefix, n_host, postfix, tmp_plugin, ds_name);
+ else
+ ssnprintf (ret, ret_len, "%s%s%s.%s.%s.%s",
+ prefix, n_host, postfix, tmp_plugin, tmp_type, ds_name);
+ }
else
ssnprintf (ret, ret_len, "%s%s%s.%s.%s",
prefix, n_host, postfix, tmp_plugin, tmp_type);
#define GRAPHITE_STORE_RATES 0x01
#define GRAPHITE_SEPARATE_INSTANCES 0x02
#define GRAPHITE_ALWAYS_APPEND_DS 0x04
+#define GRAPHITE_DROP_DUPE_FIELDS 0x08
int format_graphite (char *buffer,
size_t buffer_size, const data_set_t *ds,
varnish_config_apply_default (conf);
- user_data_t ud = {
- .data = conf,
- .free_func = varnish_config_free
- };
-
plugin_register_complex_read (/* group = */ "varnish",
/* name = */ "varnish/localhost",
/* callback = */ varnish_read,
/* interval = */ 0,
- /* user data = */ &ud);
+ &(user_data_t) {
+ .data = conf,
+ .free_func = varnish_config_free,
+ });
return (0);
} /* }}} int varnish_init */
static int varnish_config_instance (const oconfig_item_t *ci) /* {{{ */
{
user_config_t *conf;
- user_data_t ud;
char callback_name[DATA_MAX_NAME_LEN];
conf = calloc (1, sizeof (*conf));
ssnprintf (callback_name, sizeof (callback_name), "varnish/%s",
(conf->instance == NULL) ? "localhost" : conf->instance);
- ud.data = conf;
- ud.free_func = varnish_config_free;
-
plugin_register_complex_read (/* group = */ "varnish",
/* name = */ callback_name,
/* callback = */ varnish_read,
/* interval = */ 0,
- /* user data = */ &ud);
+ &(user_data_t) {
+ .data = conf,
+ .free_func = varnish_config_free,
+ });
have_instance = 1;
else if (strcasecmp ("AlwaysAppendDS", child->key) == 0)
cf_util_get_flag (child, &cb->format_flags,
GRAPHITE_ALWAYS_APPEND_DS);
+ else if (strcasecmp ("DropDuplicateFields", child->key) == 0)
+ cf_util_get_flag (child, &cb->format_flags,
+ GRAPHITE_DROP_DUPE_FIELDS);
else if (strcasecmp ("EscapeCharacter", child->key) == 0)
config_set_char (&cb->escape_char, child);
else
ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
cb->name);
- user_data_t ud = {
- .data = cb,
- .free_func = wg_callback_free
- };
-
- plugin_register_write (callback_name, wg_write, &ud);
+ plugin_register_write (callback_name, wg_write,
+ &(user_data_t) {
+ .data = cb,
+ .free_func = wg_callback_free,
+ });
- ud.free_func = NULL;
- plugin_register_flush (callback_name, wg_flush, &ud);
+ plugin_register_flush (callback_name, wg_flush, &(user_data_t) { .data = cb });
return (0);
}
}
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,
ssnprintf(callback_name, sizeof(callback_name),
"write_kafka/%s", tctx->topic_name);
- user_data_t ud = {
- .data = tctx,
- .free_func = kafka_topic_context_free
- };
-
- status = plugin_register_write (callback_name, kafka_write, &ud);
+ status = plugin_register_write (callback_name, kafka_write,
+ &(user_data_t) {
+ .data = tctx,
+ .free_func = kafka_topic_context_free,
+ });
if (status != 0) {
WARNING ("write_kafka plugin: plugin_register_write (\"%s\") "
"failed with status %i.",
#include "plugin.h"
#include "utils_format_graphite.h"
+#include "utils_format_json.h"
#include <netdb.h>
-#define WL_BUF_SIZE 8192
+#define WL_BUF_SIZE 16384
-static int wl_write_messages (const data_set_t *ds, const value_list_t *vl)
+#define WL_FORMAT_GRAPHITE 1
+#define WL_FORMAT_JSON 2
+
+/* Plugin:WriteLog has to also operate without a config, so use a global. */
+int wl_format = WL_FORMAT_GRAPHITE;
+
+static int wl_write_graphite (const data_set_t *ds, const value_list_t *vl)
{
char buffer[WL_BUF_SIZE] = { 0 };
int status;
if (0 != strcmp (ds->type, vl->type))
{
- ERROR ("write_log plugin: DS type does not match "
- "value list type");
+ ERROR ("write_log plugin: DS type does not match value list type");
return -1;
}
INFO ("write_log values:\n%s", buffer);
return (0);
-} /* int wl_write_messages */
+} /* int wl_write_graphite */
+
+static int wl_write_json (const data_set_t *ds, const value_list_t *vl)
+{
+ char buffer[WL_BUF_SIZE] = { 0 };
+ size_t bfree = sizeof(buffer);
+ size_t bfill = 0;
+
+ if (0 != strcmp (ds->type, vl->type))
+ {
+ ERROR ("write_log plugin: DS type does not match value list type");
+ return -1;
+ }
+
+ format_json_initialize(buffer, &bfill, &bfree);
+ format_json_value_list(buffer, &bfill, &bfree, ds, vl,
+ /* store rates = */ 0);
+ format_json_finalize(buffer, &bfill, &bfree);
+
+ INFO ("write_log values:\n%s", buffer);
+
+ return (0);
+} /* int wl_write_json */
static int wl_write (const data_set_t *ds, const value_list_t *vl,
__attribute__ ((unused)) user_data_t *user_data)
{
- int status;
+ int status = 0;
- status = wl_write_messages (ds, vl);
+ if (wl_format == WL_FORMAT_GRAPHITE)
+ {
+ status = wl_write_graphite (ds, vl);
+ }
+ else if (wl_format == WL_FORMAT_JSON)
+ {
+ status = wl_write_json (ds, vl);
+ }
return (status);
}
+static int wl_config (oconfig_item_t *ci) /* {{{ */
+{
+ _Bool format_seen = 0;
+
+ for (int i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Format", child->key) == 0)
+ {
+ char str[16];
+
+ if (cf_util_get_string_buffer (child, str, sizeof (str)) != 0)
+ continue;
+
+ if (format_seen)
+ {
+ WARNING ("write_log plugin: Redefining option `%s'.",
+ child->key);
+ }
+ format_seen = 1;
+
+ if (strcasecmp ("Graphite", str) == 0)
+ wl_format = WL_FORMAT_GRAPHITE;
+ else if (strcasecmp ("JSON", str) == 0)
+ wl_format = WL_FORMAT_JSON;
+ else
+ {
+ ERROR ("write_log plugin: Unknown format `%s' for option `%s'.",
+ str, child->key);
+ return (-EINVAL);
+ }
+ }
+ else
+ {
+ ERROR ("write_log plugin: Invalid configuration option: `%s'.",
+ child->key);
+ return (-EINVAL);
+ }
+ }
+
+ return (0);
+} /* }}} int wl_config */
+
void module_register (void)
{
+ plugin_register_complex_config ("write_log", wl_config);
+ /* If config is supplied, the global wl_format will be set. */
plugin_register_write ("write_log", wl_write, NULL);
}
ssnprintf (cb_name, sizeof (cb_name), "write_mongodb/%s", node->name);
- user_data_t ud = {
- .data = node,
- .free_func = wm_config_free
- };
-
- status = plugin_register_write (cb_name, wm_write, &ud);
+ status = plugin_register_write (cb_name, wm_write,
+ &(user_data_t) {
+ .data = node,
+ .free_func = wm_config_free,
+ });
INFO ("write_mongodb plugin: registered write plugin %s %d",cb_name,status);
}
ssnprintf (cb_name, sizeof (cb_name), "write_redis/%s", node->name);
- user_data_t ud = {
- .data = node,
- .free_func = wr_config_free
- };
-
- status = plugin_register_write (cb_name, wr_write, &ud);
+ status = plugin_register_write (cb_name, wr_write,
+ &(user_data_t) {
+ .data = node,
+ .free_func = wr_config_free,
+ });
}
if (status != 0)