+env:
+ global:
+ # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
+ # via the "travis encrypt" command using the project repo's public key
+ - secure: "ZdWWp0XX3C4sLIp4lqeQTWC7vt+GsWjmyRiD17T9833NBAW4dddz310I6iyeXe6oX09ZFFiVIN4ogx9ANcNBx9jriGXI2/82nBhpxOJBebet8JCNS5VeTr4rDSfQOKP+Oc+ko5KbbghTuAtO2CFYiH3jZUcn4TdsYbVanf+TwUs="
+
sudo: required
dist: trusty
compiler:
- clang
language: c
before_install:
+ # When building the coverity_scan branch, allow only the first job to continue to avoid travis-ci/travis-ci#1975.
+ - if [[ "${TRAVIS_BRANCH}" == "coverity_scan" && ! "${TRAVIS_JOB_NUMBER}" =~ \.1$ ]]; then exit 0; fi
- sudo apt-get update -qq
- sudo apt-get install -qq --no-install-recommends
+ autotools-dev
iptables-dev
libatasmart-dev
libcap-dev
libi2c-dev
libldap2-dev
libltdl-dev
+ liblua50-dev
+ liblua5.1-0-dev
liblua5.2-dev
liblvm2-dev
libmemcached-dev
libprotobuf-c0-dev
librabbitmq-dev
librdkafka-dev
+ libriemann-client-dev
librrd-dev
libsensors4-dev
libsigrok-dev
libupsclient-dev
libvarnish-dev
libvirt-dev
+ libxen-dev
libxml2-dev
libyajl-dev
linux-libc-dev
perl
protobuf-c-compiler
+ python3-dev
python-dev
-script: sh build.sh && ./configure && make distcheck
+ xfslibs-dev
+before_script: autoreconf -fi
+script:
+ - if [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]; then exit 0; fi
+ - ./configure
+ - make -j 4
+ - make check
+
+addons:
+ coverity_scan:
+ project:
+ name: "collectd/collectd"
+ description: "Build submitted via Travis CI"
+ notification_email: collectd-changes@verplant.org
+ build_command_prepend: "./configure; make clean"
+ build_command: "make -j 4"
+ branch_pattern: coverity_scan
David Bacher <drbacher at gmail.com>
- serial plugin.
+Denis Pompilio <denis.pompilio at gmail.com>
+ - Improvements to the write_http plugin.
+
Doug MacEachern <dougm at hyperic.com>
- The `-T' option (config testing mode).
- OpenVPN plugin.
* *Focus:* Fix *one thing* in your PR. The smaller your change, the faster it
will be reviewed and merged.
-* *Coding style:* Please run `clang-format -style=file -i $FILE` on new files.
- For existing files, please blend into surrounding code, i.e. mimic the
- coding style of the code around your changes.
+* *Coding style:* Please run `clang-format -style=file -i $FILE` after editing
+ `.c`, `.h` and `.proto` files. If you don't want to install *clang-format*
+ locally or your version produces a different result than the formatting
+ check on Github, use `contrib/format.sh` to format files using the same web
+ service used by our check.
* *Documentation:* New config options need to be documented in two places: the
manpage (`src/collectd.conf.pod`) and the example config
(`src/collectd.conf.in`). New plugins need to be added to the `README` file.
+2017-11-17, Version 5.8.0
+ * collectd: The core daemon is now completely licensed under the MIT
+ license.
+ * collectd: Added daemon option to avoid making BaseDir. Thanks to
+ Nathaniel Wesley Filardo and Florian Forster. #2422
+ * collectd: Global variables have been moved to their own module to make
+ porting collectd easier. Thanks to Sean Campbell. #2467
+ * collectd as well as Apache, memcached, OpenLDAP, Perl, RouterOS, SNMP,
+ Tail-CSV plugins: Free userdata for "plugin_register_complex_read()".
+ Thanks to Pavel Rochnyack. #2349
+ * Collectd client library: Added parsing and server code. Thanks to
+ Florian Forster. #2258
+ * Build system: Dependency on libltdl has been removed, support for
+ libtool 1 has been dropped. Thanks to Ruben Kerkhof. #1898
+ * Build system: The build system has been switched to non-recursive
+ make. Thanks to Ruben Kerkhof. #2085
+ * APC UPS plugin: The plugin's configuration is now optional. Without a
+ "<Plugin />" block reasonable defaults will be used. Thanks to Pavel
+ Rochnyack. #2351
+ * Chrony plugin: Several issues found when working with a stratum-1
+ server have been fixed. Thanks to Miroslav Lichvar. #2190
+ * Ceph plugin: Support for the Ceph version "Luminous" has been added.
+ Thanks to Aleksei Zakharov. #2464
+ * CPU plugin : Linux-specific "guest" states have been added. Thanks to
+ Xavier G. #2439
+ * cURL plugin, cURL-JSON, cURL-XML, DBI, FileCount, memcachec, Oracle,
+ PostgreSQL, Table, Tail, Tail CSV plugins: The ability to configure
+ the "plugin" field of generated metrics has been added. Thanks to
+ Pavel Rochnyack. #1944, #1681, #1558
+ * cURL-JSON plugin: Parsing of arrays has been fixed. Thanks to Florian
+ Forster. #2281
+ * DPDKEvents plugin: This new plugin reports link status and keep alive
+ events. Thanks to Maryam Tahhan, Harry van Haaren, Serhiy Pshyk,
+ Kim-Marie Jones, Krzysztof Matczak, Przemyslaw Szczerbik, Christian
+ Ehrhardt and Luca Boccassi. #2157, #2348, #2400, #2405, #2417
+ * DPDKStat plugin: The plugin has been refactored to make DPDK related
+ utility functions reusable. Thanks to Krzysztof Matczak, Przemyslaw
+ Szczerbik, Christian Ehrhardt and Luca Boccassi. #2130, #2348, #2400,
+ #2405, #2417
+ * DPDKStat plugin: The "LogLevel" and "RteDriverLibPath" config options
+ have been added. Thanks to Jiri Prokes. #2505
+ * Email plugin as well as Exec and Unixsock plugins: Use
+ "_SC_GETPW_R_SIZE_MAX". Thanks to Florian Forster. #2451
+ * FileCount plugin: Custom values for reported plugin, type and type
+ instance. Thanks to Pavel Rochnyack. #1979
+ * GenericJMX plugin: Support for "AtomicInteger" and "AtomicLong" has
+ been added. Thanks to Pierre Mauduit. #2158
+ * gRPC plugin: Support for meta data has been added. Thanks to Taylor
+ Cramer. #2378
+ * IPC plugin: Fixed failed compilation on AIX. Thanks to Pavel
+ Rochnyack. #2357
+ * Intel PMU plugin: This new plugin collects CPU performance metrics
+ using Intel's Performance Monitoring Unit (PMU). Scaling information
+ added to metadata. Thanks to Serhiy Pshyk and Roman Korynkevych.
+ #2276, #2398, #2374
+ * Intel RDT plugin: Support for collectd's logging infrastructure has
+ been added. PQoS monitoring groups are being reset on start-up to fix
+ potential previous unclean shutdowns. Thanks to Roman Korynkevych.
+ #2089.
+ * IPMI plugin: Support for System Event Log (SEL) has been added. Thanks
+ to Roman Korynkevych. #2091
+ * IPMI plugin: Support for remote IPMI controllers has been added.
+ Thanks to Pavel Rochnyack. #2024
+ * LVM plugin: A check for the "CAP_SYS_ADMIN" capability has been added.
+ This will give users an informative warning when the process is not
+ running with the required privileges for this plugin. Thanks to
+ Florian Forster. #2426, #2499
+ * mcelog plugin: This new plugin subscribes to Machine Check Exceptions
+ (MCE) and dispatches notifications. Metadata reset. Thanks to Maryam
+ Tahhan, Volodymyr Mytnyk, Taras Chornyi, Krzysztof Matczak and Roman
+ Korynkevych. #2003, #2246, #2380
+ * MQTT plugin: Add support for TLS in "Subscriber" blocks. Thanks to
+ Florian Forster. #2434
+ * memcached plugin: Persistent connections have been implemented. Fix
+ hit ratio reporting, add connections rate report. Thanks to Pavel
+ Rochnyack. #2388, #2385
+ * memcached plugin: The type of the "listen_disabled" metric has been
+ changed to "total_events". Thanks to Florian Forster. #2386, #2468
+ * Netlink plugin: The dropped packets metric has been added. Thanks to
+ Denys Fedoryshchenko. #2053
+ * NFS plugin: Support for NFS 4.2 metrics has been added. Thanks to
+ Marek Becka. #2369
+ * NFS plugin: Config options to ignore specified NFS versions have been
+ added. Thanks to Christian Bartolomäus. #2430
+ * NUT plugin: The "ConnectTimeout", "ForceSSL", "VerifyPeer" and
+ "CAPath" options have been added. Thanks to Pavel Rochnyack and Steven
+ Bell. #2145, #2354
+ * OpenLDAP plugin: A segfault after a connection failure has been fixed.
+ Thanks to Pavel Rochnyack. #2377
+ * Openvpn plugin: Added support for status files from latest OpenVPN-2.4
+ and possible from future versions. Thanks to Pavel Rochnyack. #2352
+ * OVS Events plugin: This new plugin reports link state changes from
+ Open vSwitch (OVS). Thanks to Volodymyr Mytnyk. #1971
+ * OVS Stats plugin: This new plugin reports bridge / interface
+ statistics from Open vSwitch (OVS). Thanks to Volodymyr Mytnyk and
+ Taras Chornyi. #2137
+ * Perl plugin: Bugfix, added check of proper interpreter initialization.
+ Thanks to Pavel Rochnyack. #2391
+ * PostgreSQL plugin: The plugin now sets the "application_name"
+ parameter when connecting to the database. Thanks to daniacs. #2497
+ * Processes plugin: The I/O operations reported for selected processes
+ has been fixed. The metric "ps_disk_octets" has been renamed to
+ "io_octets" because it actually contains the number of I/O operation
+ by the process, not just disk related I/O. Same for "io_ops"
+ (previously "ps_disk_ops"). The new metric "disk_octets" has been
+ added and is reporting disk I/O only. Add option to collect the count
+ of active memory maps for Linux processes. The "CollectFileDescriptor"
+ and "CollectContextSwitch" options have been added. Thanks to Pavel
+ Rochnyack and to Wilfried Goesgens. #2232, #2454, #1989
+ * Processes and TCPConns plugins: The OpenBSD implementation has been
+ changed to use "kvm_openfiles" with "KVM_NO_FILES". Thanks to Jeremie
+ Courreges-Anglas. #2061
+ * Python plugin: Extend Notification class to include metadata. Thanks
+ to Volodymyr Mytnyk. #2135
+ * Python plugin: The "CollectdException" class has been added. This
+ allows to throw an exception without a stack trace being logged.
+ Thanks to Sven Trenkel. #2330, #2346
+ * Sensors plugin: Support for (electrical) current has been added.
+ Thanks to Clemens Gruber. #2255
+ * SNMP plugin: Error handling has been improved: a potential double-free
+ is now avoided (potentially leaking memory) and handling of
+ non-failing subtrees has been fixed. Thanks to Pavel Rochnyack. #2449
+ * SNMP plugin: The "Timeout" and "Retries" config options have been
+ added. Thanks to Carlos Vicente. #1472, #2488
+ * SNMP Agent plugin: This new plugin implements an SNMP AgentX subagent
+ that receives and handles queries from SNMP master agent and returns
+ configured metrics. Thanks to Roman Korynkevych, Serhiy Pshyk and
+ Pavel Rochnyack. #2105, #2362
+ * Synproxy plugin: This new plugin provides statistics for Linux
+ SYNPROXY. Thanks to Marek Bečka. #2381
+ * Tail plugin: Allow the calculation of several distributions in one
+ "tail" instance through a "bucket" type. Thanks to Pavel Rochnyack.
+ #2442
+ * Turbostat plugin: Import "msr-index.h" header from Linux and better
+ support for mutliple packages. Thanks to Vincent Brillault. #2445,
+ #2446
+ * Uptime plugin: Changed implementation to read from "/proc/uptime"
+ instead of "/proc/stat". Update for Linux and AIX, uptime is read
+ directly using a system call. Update for BSD and Solaris, uptime is
+ calculated by subtracting boot time from current time. Thanks to Ivan
+ Kurnosov and Marcin Jurkowski. #2431, #2034
+ * UUID plugin: Support for libhal has been removed. Thanks to Ruben
+ Kerkhof. #2080
+ * Varnish plugin: Extended the varnish plugin with varnish-plus
+ counters. Fixed invalid data source type. Thanks to Denes Matetelki.
+ #2453, #2463
+ * virt plugin: The plugin has been updated to use
+ "virConnectListAllDomains()". Thanks to Denis Silakov. #2051
+ * virt plugin: Support for domain tags has been added. Thanks to
+ Francesco Romani. #2048
+ * virt plugin: Connection handling has been improved. Thanks to
+ Francesco Romani. #2100, #2101
+ * virt plugin: Many metrics have been added, including disk, hypervisor
+ CPU usage, performance monitoring events, domain state, CPU pinning
+ (affinity), file system, and job statistics. Thanks to Francesco
+ Romani and Przemyslaw Szczerbik. #2103, #2175, #2168
+ * Write Graphite plugin: Additional tests have been added. Thanks to
+ Florian Forster.
+ * Write HTTP plugin: The "Attribute" and "TTL" options for the KairosDB
+ format have been added. Implementation of "Prefix" option. Thanks to
+ jaroug, Denis Pompilio and Pavel Rochnyack. #2199, #2252, #2482
+ * Write MongoDB plugin: Memory leaks have been fixed. Thanks to
+ Saikrishna Arcot. #2307
+ * Write Prometheus plugin: Label values are now properly escaped. Thanks
+ to Florian Forster. #2035
+ * Write Redis plugin: Add "max_set_duration" to set duration for value.
+ Thanks to Tomofumi Hayashi. #2440
+ * Write Riemann plugin: Export times with microsecond resolution. Thanks
+ to mcorbin. #2315
+ * Write TSDB plugin: The options "ResolveInterval" and "ResolveJitter"
+ have been added to control DNS lookup behavior. This prevents DNS
+ flooding in case TSDB is not available. Thanks to Yves Mettier and
+ Florian Forster. #2059
+ * ZFS ARC plugin: Header lines are now ignored in the Linux
+ implementation. Thanks to YmrDtnJu. #2097
+
2017-06-06, Version 5.7.2
* Build system: The Notify Email plugin is no longer linked with
indirect dependencies. Thanks to Marc Fournier.
embedded HTTP server, in a format compatible with Prometheus'
collectd_exporter. Thanks to Florian Forster. #1967
+2017-10-06, Version 5.6.3
+ * collectd: support for boolean string config values has been
+ reintroduced. Thanks to Sebastian Harl. #2083, #2098
+ * collectd: The capability checking has been changed to use
+ "cap_get_proc()". Thanks to Marc Fournier. #2151
+ * Documentation: A section documenting ignore lists has been added to
+ collectd.conf(5). Thanks to Florian Forster.
+ * AMQP plugin: The "ExchangeType" option is now also valid for
+ publishers. Thanks to Florian Forster. #2286
+ * Apache, Ascent, BIND, cURL, cURL-JSON, cURL-XML, nginx, Write HTTP
+ plugins: Handling of URLs that redirect elsewhere has been fixed.
+ Thanks to Pavel Rochnyack. #2328
+ * BIND plugin: Fix parsing of the sample time provided by BIND.
+ Previously, the time was assumed to be in the local time zone when in
+ fact it was in UTC. Thanks to Ed Ravin. #1268
+ * BIND plugin: Memory leaks have been fixed. Thanks to Ruben Kerkhof.
+ #2303
+ * Chrony plugin: Build flags have been fixed. Thanks to Thomas Jost and
+ Marc Fournier. #2133
+ * cURL-JSON plugin: The timeout value has been changed to default to the
+ collection interval. This fixes a regression. Thanks to Marc Fournier.
+ * cURL-JSON plugin: Handling of arrays has been fixed. Thanks to Florian
+ Forster. #2266
+ * DBI plugin: Memory leaks at shutdown have been fixes. Thanks to Pavel
+ Rochnyack and Florian Forster.
+ * E-Mail, Exec, UnixSock plugins: Group ID lookup on systems with many
+ groups has been fixed. Thanks to Ruben Kerkhof and Florian Forster.
+ #2208
+ * IPC plugin: A compilation error on AIX has been fixed. Thanks to Pavel
+ Rochnyack. #2305
+ * LogFile plugin: If writing to the file fails, print log messages on
+ "STDERR" instead. Thanks to Marc Fournier.
+ * Log Logstash plugin: If writing the log entry fails, print it to
+ "STDERR" instead. Thanks to Marc Fournier.
+ * memcachec, Tail plugins: A resource leak in the matching
+ infrastructure has been fixed. Thanks to Krzysztof Matczak. #2192
+ * MQTT plugin: Invalid symbols in topic names are now replaced and a
+ resource leak has been fixed. Thanks to Denys Fedoryshchenko. #2123
+ * Network plugin: A potential endless-loop has been fixed. This can be
+ triggered remotely by sending a signed network packet to a server
+ which is not set up to check signatures. Thanks to Marcin Kozlowski
+ and Pavel Rochnyack. #2174, #2233, CVE-2017-7401
+ * Network plugin: A use-after-free has been fixed. Thanks to Pavel
+ Rochnyack. #2375
+ * Notify Email plugin: The plugin is no longer explicitly linked against
+ libssl and libcrypto, relies on libesmtp being linked correctly.
+ Thanks to Marc Fournier. Debian#852924
+ * NTPd plugin: Calculation of loop offset and error has been fixed.
+ Thanks to Neil Wilson. #2188
+ * OpenLDAP plugin: An incorrect use of the ldap library, leading to a
+ crash, has been fixed. Thanks to Marc Fournier. #2331
+ * Perl plugin: A potential double-free has been fixed. Thanks to Florian
+ Forster. #2278
+ * Perl plugin: Print an error when an incorrect configuration is
+ encountered. Thanks to Pavel Rochnyack. #927
+ * RRDtool plugin: Incorrect handling of the flushes timeout option has
+ been fixed. Handling of the "RandomTimeout" has been fixed. Thanks to
+ Pavel Rochnyack. #2363
+ * SMART plugin: Some warning messages have been removed and the code has
+ been cleaned up. Thanks to Florian Forster. #2062
+ * SMART plugin: A check for the "CAP_SYS_RAWIO" capability has been
+ added. Thanks to Marc Fournier.
+ * SNMP plugin: A double free has been fixed. Thanks to Pavel Rochnyack.
+ #2291
+ * Write Graphite plugin: Error handling in the case that calculating a
+ metric's rate fails has been improved. Previously, the raw counter
+ values were sent to Graphite. Thanks to Iain Buclaw. #2209
+ * Write Kafka plugin: A 32 bit random number is now used when formatting
+ a random key. Thanks to Florian Forster. #2074
+
+
2016-11-30, Version 5.6.2
* collectd: A compile error on AIX has been fixed: "MSG_DONTWAIT" is not
available on AIX. Thanks to Chao Yang.
pkginclude_HEADERS = \
src/libcollectdclient/collectd/client.h \
- src/libcollectdclient/collectd/network.h \
+ src/libcollectdclient/collectd/lcc_features.h \
src/libcollectdclient/collectd/network_buffer.h \
- src/libcollectdclient/collectd/lcc_features.h
+ src/libcollectdclient/collectd/network.h \
+ src/libcollectdclient/collectd/network_parse.h \
+ src/libcollectdclient/collectd/server.h \
+ src/libcollectdclient/collectd/types.h
lib_LTLIBRARIES = libcollectdclient.la
test_utils_mount \
test_utils_subst \
test_utils_time \
- test_utils_vl_lookup
+ test_utils_vl_lookup \
+ test_libcollectd_network_parse
TESTS = $(check_PROGRAMS)
src/daemon/configfile.h \
src/daemon/filter_chain.c \
src/daemon/filter_chain.h \
+ src/daemon/globals.c \
+ src/daemon/globals.h \
src/daemon/meta_data.c \
src/daemon/meta_data.h \
src/daemon/plugin.c \
collectd_nagios_SOURCES = src/collectd-nagios.c
collectd_nagios_CPPFLAGS = $(AM_CPPFLAGS) \
- -I$(srcdir)/src/libcollectdclient/collectd \
- -I$(top_builddir)/src/libcollectdclient/collectd
+ -I$(srcdir)/src/libcollectdclient \
+ -I$(top_builddir)/src/libcollectdclient
collectd_nagios_LDADD = libcollectdclient.la
if BUILD_WITH_LIBSOCKET
collectd_nagios_LDADD += -lsocket
collectdctl_SOURCES = src/collectdctl.c
collectdctl_CPPFLAGS = $(AM_CPPFLAGS) \
- -I$(srcdir)/src/libcollectdclient/collectd \
- -I$(top_builddir)/src/libcollectdclient/collectd
+ -I$(srcdir)/src/libcollectdclient \
+ -I$(top_builddir)/src/libcollectdclient
collectdctl_LDADD = libcollectdclient.la
if BUILD_WITH_LIBSOCKET
collectdctl_LDADD += -lsocket
collectd_tg_SOURCES = src/collectd-tg.c
collectd_tg_CPPFLAGS = $(AM_CPPFLAGS) \
- -I$(srcdir)/src/libcollectdclient/collectd \
- -I$(top_builddir)/src/libcollectdclient/collectd
+ -I$(srcdir)/src/libcollectdclient \
+ -I$(top_builddir)/src/libcollectdclient
collectd_tg_LDADD = \
$(PTHREAD_LIBS) \
libheap.la \
libcollectdclient_la_SOURCES = \
src/libcollectdclient/client.c \
src/libcollectdclient/network.c \
- src/libcollectdclient/network_buffer.c
+ src/libcollectdclient/network_buffer.c \
+ src/libcollectdclient/network_parse.c \
+ src/libcollectdclient/server.c
libcollectdclient_la_CPPFLAGS = \
$(AM_CPPFLAGS) \
- -I$(srcdir)/src/libcollectdclient/collectd \
- -I$(top_builddir)/src/libcollectdclient/collectd \
+ -I$(srcdir)/src/libcollectdclient \
+ -I$(top_builddir)/src/libcollectdclient \
-I$(srcdir)/src/daemon
-libcollectdclient_la_LDFLAGS = -version-info 1:0:0
-libcollectdclient_la_LIBADD =
+libcollectdclient_la_LDFLAGS = -version-info 2:0:1
+libcollectdclient_la_LIBADD = -lm
if BUILD_WITH_LIBGCRYPT
libcollectdclient_la_CPPFLAGS += $(GCRYPT_CPPFLAGS)
libcollectdclient_la_LDFLAGS += $(GCRYPT_LDFLAGS)
libcollectdclient_la_LIBADD += $(GCRYPT_LIBS)
endif
+# network_parse_test.c includes network_parse.c, so no need to link with
+# libcollectdclient.so.
+test_libcollectd_network_parse_SOURCES = src/libcollectdclient/network_parse_test.c
+test_libcollectd_network_parse_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(srcdir)/src/libcollectdclient \
+ -I$(top_builddir)/src/libcollectdclient
+if BUILD_WITH_LIBGCRYPT
+test_libcollectd_network_parse_CPPFLAGS += $(GCRYPT_CPPFLAGS)
+test_libcollectd_network_parse_LDFLAGS = $(GCRYPT_LDFLAGS)
+test_libcollectd_network_parse_LDADD = $(GCRYPT_LIBS)
+endif
liboconfig_la_SOURCES = \
src/liboconfig/oconfig.c \
src/liboconfig/aux_types.h \
src/liboconfig/scanner.l \
src/liboconfig/parser.y
+liboconfig_la_CPPFLAGS = -I$(srcdir)/src/liboconfig $(AM_CPPFLAGS)
liboconfig_la_LDFLAGS = -avoid-version $(LEXLIB)
pkglib_LTLIBRARIES += dpdkevents.la
dpdkevents_la_SOURCES = src/dpdkevents.c src/utils_dpdk.c src/utils_dpdk.h
dpdkevents_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBDPDK_CPPFLAGS)
+dpdkevents_la_CFLAGS = $(AM_CFLAGS) $(LIBDPDK_CFLAGS)
dpdkevents_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBDPDK_LDFLAGS)
-dpdkevents_la_LIBADD = -ldpdk
+dpdkevents_la_LIBADD = $(LIBDPDK_LIBS)
endif
if BUILD_PLUGIN_DPDKSTAT
pkglib_LTLIBRARIES += dpdkstat.la
dpdkstat_la_SOURCES = src/dpdkstat.c src/utils_dpdk.c src/utils_dpdk.h
dpdkstat_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBDPDK_CPPFLAGS)
+dpdkstat_la_CFLAGS = $(AM_CFLAGS) $(LIBDPDK_CFLAGS)
dpdkstat_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBDPDK_LDFLAGS)
-dpdkstat_la_LIBADD = -ldpdk
+dpdkstat_la_LIBADD = $(LIBDPDK_LIBS)
endif
if BUILD_PLUGIN_DRBD
python_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBPYTHON_LDFLAGS)
endif
+if HAVE_LIBMNL
+noinst_LTLIBRARIES += libtaskstats.la
+libtaskstats_la_SOURCES = \
+ src/utils_taskstats.c \
+ src/utils_taskstats.h
+libtaskstats_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMNL_CFLAGS)
+libtaskstats_la_LIBADD = $(BUILD_WITH_LIBMNL_LIBS)
+endif
+
if BUILD_PLUGIN_PROCESSES
pkglib_LTLIBRARIES += processes.la
processes_la_SOURCES = src/processes.c
+processes_la_CPPFLAGS = $(AM_CPPFLAGS)
processes_la_LDFLAGS = $(PLUGIN_LDFLAGS)
processes_la_LIBADD =
if BUILD_WITH_LIBKVM_GETPROCS
processes_la_LIBADD += -lkvm
endif
+if HAVE_LIBMNL
+processes_la_CPPFLAGS += -DHAVE_LIBTASKSTATS=1
+processes_la_LIBADD += libtaskstats.la
+endif
endif
if BUILD_PLUGIN_PROTOCOLS
endif
+if BUILD_PLUGIN_SYNPROXY
+pkglib_LTLIBRARIES += synproxy.la
+synproxy_la_SOURCES = src/synproxy.c
+synproxy_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
if BUILD_PLUGIN_SYSLOG
pkglib_LTLIBRARIES += syslog.la
syslog_la_SOURCES = src/syslog.c
if BUILD_PLUGIN_TURBOSTAT
pkglib_LTLIBRARIES += turbostat.la
-turbostat_la_SOURCES = src/turbostat.c
+turbostat_la_SOURCES = \
+ src/turbostat.c \
+ src/msr-index.h
turbostat_la_LDFLAGS = $(PLUGIN_LDFLAGS)
endif
Collect DPDK interface statistics.
See docs/BUILD.dpdkstat.md for detailed build instructions.
+ This plugin should be compiled with compiler defenses enabled, for
+ example -fstack-protector.
+
- drbd
Collect individual drbd resource statistics.
hugepages can be found here:
https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt.
+ This plugin should be compiled with compiler defenses enabled, for
+ example -fstack-protector.
+
- intel_pmu
The intel_pmu plugin reads performance counters provided by the Linux
kernel perf interface. The plugin uses jevents library to resolve named
plugin of choice for that.
- nfs
- NFS Procedures: Which NFS command were called how often. Only NFSv2 and
- NFSv3 right now.
+ NFS Procedures: Which NFS command were called how often.
- nginx
Collects statistics from `nginx' (speak: engine X), a HTTP and mail
------------------------------------
To configure, build and install collectd with the default settings, run
- `./configure && make && make install'. For detailed, generic instructions
- see INSTALL. For a complete list of configure options and their description,
- run `./configure --help'.
+ `./configure && make && make install'. For a complete list of configure
+ options and their description, run `./configure --help'.
By default, the configure script will check for all build dependencies and
disable all plugins whose requirements cannot be fulfilled (any other plugin
-#! /bin/sh
+#!/bin/sh
GLOBAL_ERROR_INDICATOR=0
-check_for_application ()
+check_for_application()
{
- for PROG in "$@"
- do
- which "$PROG" >/dev/null 2>&1
- if test $? -ne 0; then
- cat >&2 <<EOF
+ for PROG in "$@"
+ do
+ which "$PROG" >/dev/null 2>&1
+ if test $? -ne 0; then
+ cat >&2 <<EOF
WARNING: \`$PROG' not found!
Please make sure that \`$PROG' is installed and is in one of the
directories listed in the PATH environment variable.
EOF
- GLOBAL_ERROR_INDICATOR=1
- fi
- done
+ GLOBAL_ERROR_INDICATOR=1
+ fi
+ done
}
check_for_application lex bison autoheader aclocal automake autoconf pkg-config
libtoolize=""
libtoolize --version >/dev/null 2>/dev/null
-if test $? -eq 0
-then
- libtoolize=libtoolize
+if test $? -eq 0; then
+ libtoolize=libtoolize
else
- glibtoolize --version >/dev/null 2>/dev/null
- if test $? -eq 0
- then
- libtoolize=glibtoolize
- else
- cat >&2 <<EOF
+ glibtoolize --version >/dev/null 2>/dev/null
+ if test $? -eq 0; then
+ libtoolize=glibtoolize
+ else
+ cat >&2 <<EOF
WARNING: Neither \`libtoolize' nor \`glibtoolize' have been found!
Please make sure that one of them is installed and is in one of the
directories listed in the PATH environment variable.
EOF
- GLOBAL_ERROR_INDICATOR=1
- fi
+ GLOBAL_ERROR_INDICATOR=1
+ fi
fi
-if test "$GLOBAL_ERROR_INDICATOR" != "0"
-then
- exit 1
+if test "$GLOBAL_ERROR_INDICATOR" != "0"; then
+ exit 1
fi
set -x
autoheader \
-&& aclocal \
+&& aclocal -I m4 \
&& $libtoolize --copy --force \
&& automake --add-missing --copy \
&& autoconf
pthread_np.h \
pwd.h \
regex.h \
+ sys/endian.h \
sys/fs_types.h \
sys/fstyp.h \
sys/ioctl.h \
]]
)
# For the turbostat plugin
- AC_CHECK_HEADERS([asm/msr-index.h],
- [have_asm_msrindex_h="yes"],
- [have_asm_msrindex_h="no"]
- )
-
- if test "x$have_asm_msrindex_h" = "xyes"; then
- AC_CACHE_CHECK([whether asm/msr-index.h has MSR_PKG_C10_RESIDENCY],
- [c_cv_have_usable_asm_msrindex_h],
- [
- AC_COMPILE_IFELSE(
- [
- AC_LANG_PROGRAM(
- [[#include<asm/msr-index.h>]],
- [[
- int y = MSR_PKG_C10_RESIDENCY;
- return(y);
- ]]
- )
- ],
- [c_cv_have_usable_asm_msrindex_h="yes"],
- [c_cv_have_usable_asm_msrindex_h="no"],
- )
- ]
- )
- fi
-
AC_CHECK_HEADERS([cpuid.h],
[have_cpuid_h="yes"],
[have_cpuid_h="no (cpuid.h not found)"]
# --with-libdpdk {{{
AC_ARG_VAR([LIBDPDK_CPPFLAGS], [Preprocessor flags for libdpdk])
+AC_ARG_VAR([LIBDPDK_CFLAGS], [Compiler flags for libdpdk])
AC_ARG_VAR([LIBDPDK_LDFLAGS], [Linker flags for libdpdk])
+AC_ARG_VAR([LIBDPDK_LIBS], [Libraries to link for libdpdk])
AC_ARG_WITH([libdpdk],
[AS_HELP_STRING([--without-libdpdk], [Disable libdpdk.])],
)
if test "x$with_libdpdk" != "xno"; then
+ PKG_CHECK_MODULES([DPDK], [libdpdk], [],
+ [AC_MSG_NOTICE([no DPDK pkg-config, using defaults])])
if test "x$LIBDPDK_CPPFLAGS" = "x"; then
LIBDPDK_CPPFLAGS="-I/usr/include/dpdk"
fi
+ if test "x$LIBDPDK_CFLAGS" = "x"; then
+ LIBDPDK_CFLAGS="$DPDK_CFLAGS"
+ LIBDPDK_CPPFLAGS="$LIBDPDK_CPPFLAGS $DPDK_CFLAGS"
+ fi
+ if test "x$LIBDPDK_LIBS" = "x"; then
+ if test "x$DPDK_LIBS" != "x"; then
+ LIBDPDK_LIBS="$DPDK_LIBS"
+ else
+ LIBDPDK_LIBS="-ldpdk"
+ fi
+ fi
SAVE_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$LIBDPDK_CPPFLAGS $CPPFLAGS"
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$LIBDPDK_CFLAGS $CFLAGS"
AC_CHECK_HEADERS([rte_config.h],
[
with_libdpdk="yes"
[with_libdpdk="no (rte_config.h not found)"]
)
CPPFLAGS="$SAVE_CPPFLAGS"
+ CFLAGS="$SAVE_CFLAGS"
fi
if test "x$with_libdpdk" = "xyes"; then
if test "x$withval" != "xno" && test "x$withval" != "xyes"; then
with_libgrpcpp_cppflags="-I$withval/include"
with_libgrpcpp_ldflags="-L$withval/lib"
+ with_libgrpcpp_bin="$withval/bin"
with_libgrpcpp="yes"
fi
if test "x$withval" = "xno"; then
# }}}
AC_ARG_VAR([GRPC_CPP_PLUGIN], [path to the grpc_cpp_plugin binary])
-AC_PATH_PROG([GRPC_CPP_PLUGIN], [grpc_cpp_plugin])
+if test "x$with_libgrpcpp_bin" = "x"; then
+ AC_PATH_PROG([GRPC_CPP_PLUGIN], [grpc_cpp_plugin])
+else
+ AC_PATH_PROG([GRPC_CPP_PLUGIN], [grpc_cpp_plugin], [], "$with_libgrpcpp_bin:$PATH")
+fi
AM_CONDITIONAL([HAVE_GRPC_CPP], [test "x$GRPC_CPP_PLUGIN" != "x"])
# --with-libiptc {{{
fi
AC_SUBST([BUILD_WITH_LIBMNL_CFLAGS])
AC_SUBST([BUILD_WITH_LIBMNL_LIBS])
+AM_CONDITIONAL([HAVE_LIBMNL], [test "x$with_libmnl" = "xyes"])
# }}}
# --with-libnetapp {{{
SAVE_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $with_libvarnish_cflags"
- AC_CHECK_HEADERS([vapi/vsc.h],
- [AC_DEFINE([HAVE_VARNISH_V4], [1], [Varnish 4 API support])],
- [
- AC_CHECK_HEADERS([vsc.h],
- [AC_DEFINE([HAVE_VARNISH_V3], [1], [Varnish 3 API support]) ],
- [
- AC_CHECK_HEADERS([varnishapi.h],
- [AC_DEFINE([HAVE_VARNISH_V2], [1], [Varnish 2 API support])],
- [with_libvarnish="no (found none of the varnish header files)"]
- )
- ]
- )
- ]
- )
+ $PKG_CONFIG --atleast-version=5.2 'varnishapi' 2>/dev/null
+ if test $? -eq 0; then
+ AC_DEFINE([HAVE_VARNISH_V5], [1], [Varnish 5 API support])
+ else
+ AC_CHECK_HEADERS([vapi/vsc.h],
+ [AC_DEFINE([HAVE_VARNISH_V4], [1], [Varnish 4 API support])],
+ [
+ AC_CHECK_HEADERS([vsc.h],
+ [AC_DEFINE([HAVE_VARNISH_V3], [1], [Varnish 3 API support]) ],
+ [
+ AC_CHECK_HEADERS([varnishapi.h],
+ [AC_DEFINE([HAVE_VARNISH_V2], [1], [Varnish 2 API support])],
+ [with_libvarnish="no (found none of the varnish header files)"]
+ )
+ ]
+ )
+ ]
+ )
+ fi
CPPFLAGS="$SAVE_CPPFLAGS"
fi
plugin_serial="no"
plugin_smart="no"
plugin_swap="no"
+plugin_synproxy="no"
plugin_tape="no"
plugin_tcpconns="no"
plugin_ted="no"
plugin_protocols="yes"
plugin_serial="yes"
plugin_swap="yes"
+ plugin_synproxy="yes"
plugin_tcpconns="yes"
plugin_thermal="yes"
plugin_uptime="yes"
plugin_ipvs="yes"
fi
- if test "x$c_cv_have_usable_asm_msrindex_h" = "xyes" && test "x$have_cpuid_h" = "xyes"; then
+ if test "x$have_cpuid_h" = "xyes"; then
plugin_turbostat="yes"
fi
plugin_gps="yes"
fi
-if test "x$with_libgrpcpp" = "xyes" && test "x$with_libprotobuf" = "xyes" && test "x$have_protoc3" = "xyes" && test "x$GRPC_CPP_PLUGIN" != "x"; then
- plugin_grpc="yes"
+plugin_grpc="yes"
+if test "x$GRPC_CPP_PLUGIN" = "x"; then
+ plugin_grpc="no (grpc_cpp_plugin not found)"
+fi
+if test "x$have_protoc3" != "xyes"; then
+ plugin_grpc="no (protoc3 not found)"
+fi
+if test "x$with_libprotobuf" != "xyes"; then
+ plugin_grpc="no (libprotobuf not found)"
+fi
+if test "x$with_libgrpcpp" != "xyes"; then
+ plugin_grpc="no (libgrpc++ not found)"
fi
if test "x$have_getifaddrs" = "xyes"; then
plugin_xencpu="yes"
fi
-if test "x$with_libdpdk" = "xyes"
-then
+if test "x$with_libdpdk" = "xyes"; then
plugin_dpdkevents="$dpdk_keepalive"
plugin_dpdkstat="yes"
fi
AC_PLUGIN([snmp_agent], [$with_libnetsnmpagent], [SNMP agent plugin])
AC_PLUGIN([statsd], [yes], [StatsD plugin])
AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics])
+AC_PLUGIN([synproxy], [$plugin_synproxy], [Synproxy stats plugin])
AC_PLUGIN([syslog], [$have_syslog], [Syslog logging plugin])
AC_PLUGIN([table], [yes], [Parsing of tabular data])
AC_PLUGIN([tail], [yes], [Parsing of logfiles])
AC_MSG_RESULT([ snmp_agent . . . . . $enable_snmp_agent])
AC_MSG_RESULT([ statsd . . . . . . . $enable_statsd])
AC_MSG_RESULT([ swap . . . . . . . . $enable_swap])
+AC_MSG_RESULT([ synproxy . . . . . . $enable_synproxy])
AC_MSG_RESULT([ syslog . . . . . . . $enable_syslog])
AC_MSG_RESULT([ table . . . . . . . . $enable_table])
AC_MSG_RESULT([ tail_csv . . . . . . $enable_tail_csv])
--- /dev/null
+# Example configuration for PHP-FPM
+<Plugin "curl_json">
+ <URL "http://nginx-status/php-fpm-status?json">
+ Plugin "phpfpm"
+ Instance "main"
+ <Key "accepted conn">
+ Type "total_requests"
+ Instance "accepted"
+ </Key>
+ <Key "slow requests">
+ Type "total_requests"
+ Instance "slow"
+ </Key>
+ <Key "listen queue">
+ Type "queue_length"
+ Instance "listen"
+ </Key>
+ <Key "active processes">
+ Type "vs_processes"
+ Instance "active"
+ </Key>
+ <Key "total processes">
+ Type "vs_processes"
+ Instance "total"
+ </Key>
+ </URL>
+</Plugin>
=head1 CONFIGURATION
-This script reads it's configuration from F</etc/exec-munin.conf>. The
+This script reads its configuration from F</etc/exec-munin.conf>. The
configuration is read using C<Config::General> which understands a Apache-like
config syntax, so it's very similar to the F<collectd.conf> syntax, too.
=head1 CONFIGURATION
-This script reads it's configuration from F</etc/exec-nagios.conf>. The
+This script reads its configuration from F</etc/exec-nagios.conf>. The
configuration is read using C<Config::General> which understands a Apache-like
config syntax, so it's very similar to the F<collectd.conf> syntax, too.
--- /dev/null
+#!/bin/sh
+
+# This script sends files to a web service using POST requests and reads back
+# the correctly formatted source files. This allows to apply clang-format
+# without having to install the tool locally.
+
+if test $# -lt 1; then
+ echo "Usage $0 <file> [<file> ...]"
+ exit 1
+fi
+
+for i in "$@"; do
+ d="`dirname "${i}"`"
+ o="`TMPDIR="${d}" mktemp format.XXXXXX`"
+
+ curl --silent --data-binary "@-" https://format.collectd.org/ <"${i}" >"${o}"
+ if test $? -eq 0; then
+ cat "${o}" >"${i}"
+ fi
+ rm -f "${o}"
+done
}
/**
- * Draw RRD file based on it's structure
+ * Draw RRD file based on its structure
* @host
* @plugin
* @pinst
}
/**
- * Draw RRD file based on it's structure
+ * Draw RRD file based on its structure
* @timespan
* @host
* @plugin
#
# - fetch the desired collectd release file from https://collectd.org/files/
# and save it in your ~/rpmbuild/SOURCES/ directory (or build your own out of
-# the git repository: ./build.sh && ./configure && make-dist-bz2)
+# the git repository: ./build.sh && ./configure && make dist)
#
# - copy this file in your ~/rpmbuild/SPECS/ directory. Make sure the
# "Version:" tag matches the version from the tarball.
%define with_snmp_agent 0%{!?_without_snmp_agent:1}
%define with_statsd 0%{!?_without_statsd:1}
%define with_swap 0%{!?_without_swap:1}
+%define with_synproxy 0%{!?_without_synproxy:0}
%define with_syslog 0%{!?_without_syslog:1}
%define with_table 0%{!?_without_table:1}
%define with_tail 0%{!?_without_tail:1}
%define with_grpc 0%{!?_without_grpc:0}
# plugin lpar disabled, requires AIX
%define with_lpar 0%{!?_without_lpar:0}
+# plugin intel_pmu disabled, requires libjevents
+%define with_intel_pmu 0%{!?_without_intel_pmu:0}
# plugin intel_rdt disabled, requires intel-cmt-cat
%define with_intel_rdt 0%{!?_without_intel_rdt:0}
# plugin mic disabled, requires Mic
Summary: Statistics collection and monitoring daemon
Name: collectd
Version: 5.7.1
-Release: 6%{?dist}
+Release: 8%{?dist}
URL: https://collectd.org
Source: https://collectd.org/files/%{name}-%{version}.tar.bz2
License: GPLv2
provided via SMART and queried by the external hddtemp daemon.
%endif
+%if %{with_intel_pmu}
+%package intel_pmu
+Summary: Intel PMU plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+%description intel_pmu
+The intel_pmu plugin reads performance counters provided by the Linux
+kernel perf interface.
+%endif
+
%if %{with_intel_rdt}
%package intel_rdt
Summary: Intel RDT plugin for collectd
Summary: Java plugin for collectd
Group: System Environment/Daemons
Requires: %{name}%{?_isa} = %{version}-%{release}
-BuildRequires: java-devel, jpackage-utils
-Requires: java, jpackage-utils
+BuildRequires: java-devel >= 1.6, jpackage-utils >= 1.6
+Requires: java >= 1.6, jpackage-utils >= 1.6
%description java
This plugin for collectd allows plugins to be written in Java and executed
in an embedded JVM.
%define _with_hugepages --disable-hugepages
%endif
+%if %{with_intel_pmu}
+%define _with_intel_pmu --enable-intel_pmu
+%else
+%define _with_intel_pmu --disable-intel_pmu
+%endif
+
%if %{with_intel_rdt}
%define _with_intel_rdt --enable-intel_rdt
%else
%define _with_swap --disable-swap
%endif
+%if %{with_synproxy}
+%define _with_synproxy --enable-synproxy
+%else
+%define _with_synproxy --disable-synproxy
+%endif
+
%if %{with_syslog}
%define _with_syslog --enable-syslog
%else
%{?_with_grpc} \
%{?_with_hddtemp} \
%{?_with_hugepages} \
+ %{?_with_intel_pmu} \
%{?_with_intel_rdt} \
%{?_with_interface} \
%{?_with_ipc} \
%{?_with_snmp_agent} \
%{?_with_statsd} \
%{?_with_swap} \
+ %{?_with_synproxy} \
%{?_with_syslog} \
%{?_with_table} \
%{?_with_tail_csv} \
%if %{with_swap}
%{_libdir}/%{name}/swap.so
%endif
+%if %{with_synproxy}
+%{_libdir}/%{name}/synproxy.so
+%endif
%if %{with_syslog}
%{_libdir}/%{name}/syslog.so
%endif
%{_includedir}/collectd/network_buffer.h
%{_includedir}/collectd/lcc_features.h
%{_libdir}/pkgconfig/libcollectdclient.pc
+%{_includedir}/collectd/network_parse.h
+%{_includedir}/collectd/server.h
+%{_includedir}/collectd/types.h
%{_libdir}/libcollectdclient.so
%files -n libcollectdclient
%{_libdir}/%{name}/hddtemp.so
%endif
+%if %{with_intel_pmu}
+%files intel_pmu
+%{_libdir}/%{name}/intel_pmu.so
+%endif
+
%if %{with_intel_rdt}
%files intel_rdt
%{_libdir}/%{name}/intel_rdt.so
%doc contrib/
%changelog
+* Thu Sep 28 2017 xakru <calvinxakru@gmail.com> - 5.7.1-8
+- Add new libcollectdclient/network_parse
+- Add new libcollectdclient/server
+- Add new libcollectdclient/types
+- Add new synproxy plugin
+
+* Fri Aug 18 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-7
+- Add new intel_pmu plugin
+
* Sun Mar 05 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-6
- Move recently added plugins to subpackages
%description
collectd is a small daemon written in C for performance. It reads various
-system statistics and updates RRD files, creating them if neccessary.
+system statistics and updates RRD files, creating them if necessary.
Since the daemon doesn't need to startup every time it wants to update the
files it's very fast and easy on the system. Also, the statistics are very
fine grained since the files are updated every 10 seconds.
The C<snmp-probe-host.px> script can be used to automatically generate SNMP
configuration snippets for collectd's snmp plugin (see L<collectd-snmp(5)>).
-This script parses the collectd configuration and detecs all "data" blocks that
+This script parses the collectd configuration and detects all "data" blocks that
are defined for the SNMP plugin. It then queries the device specified on the
-command line for all OIDs and registeres which OIDs could be answered correctly
+command line for all OIDs and registers which OIDs could be answered correctly
and which resulted in an error. With that information the script figures out
which "data" blocks can be used with this hosts and prints an appropriate
"host" block to standard output.
# intel_pmu CAP_SYS_ADMIN
# iptables CAP_NET_ADMIN
# ping CAP_NET_RAW
+# processes CAP_NET_ADMIN (CollectDelayAccounting only)
# smart CAP_SYS_RAWIO
# turbostat CAP_SYS_RAWIO
#
# The dpdkstat plugin
+This plugin is optional and only has a specific use case: monitoring DPDK applications
+that don't expose stats in any other way than the DPDK xstats API.
+
**Data Plane Development Kit** (DPDK) is a set of drivers and libraries for fast
-packet processing.
+packet processing. Please note that this plugin is a polling based plugin rather
+than an events based plugin (using it will drive up core utilization on a system).
+
+**PLEASE DO NOT USE THIS PLUGIN FOR OVS-DPDK**. dpdkstat is really for DPDK
+applications that have no other way of exposing stats. For OVS or OVS-with-DPDK the
+Open vSwitch plugins available in collectd 5.8.0 should be used for
+collecting stats and events. In addition the OVS plugin is events based rather
+than polling based and will have a smaller footprint on the system.
## Summary
It is up to an external entity, like a software management system,
to attach and manage the tags to the domain.
-Please note that unless you have such tag-aware management sofware,
+Please note that unless you have such tag-aware management software,
it most likely make no sense to enable more than one reader instance on your
setup.
Whenever we query more than one VM, we should take care to avoid that one blocked VM prevent other,
well behaving VMs to be queried. We don't want one rogue VM to disrupt well-behaving VMs.
-Unfortunately, any way we enumerate VMs, either implicitely, using the libvirt bulk stats API,
-or explicitely, listing all libvirt domains and query each one in turn, we may unpredictably encounter
+Unfortunately, any way we enumerate VMs, either implicitly, using the libvirt bulk stats API,
+or explicitly, listing all libvirt domains and query each one in turn, we may unpredictably encounter
one unresponsive VM.
There are many possible approaches to deal with this issue. The virt plugin supports
All the above combined make it possible for a client to block forever waiting for one QMP
request, if QEMU itself is blocked. The most likely cause of block is I/O, and this is especially
true considering how QEMU is used in a datacenter.
-
--- /dev/null
+## Maintainer Guide
+
+This document documents best practises and guidelines for *collectd*
+maintainers.
+
+### Ideology
+
+As maintainer of an open-source project, you are one of the most knowledgable
+people of the project's structure, best practices, goals, etc. You are most
+helping the project by *facilitating change*, in other words "help contributors
+make changes to the codebase."
+
+The most common form of helping users is doing *code reviews* and (eventually)
+using your commit rights to merge the pull request.
+
+### Code reviews
+
+* Be friendly, especially with new contributors. Write "Hi" and thank them for their contribution before diving into review comments.
+* Criticize code, not people. Ideally, tell the contributor a better way to do what they need.
+* Clearly mark optional suggestions as such. Best practise, start your comment with *At your option: …*
+* Wait for a successful run of our [continuous integration system](https://ci.collectd.org/) before merging.
+
+### Repository access
+
+You have write access to the *collectd/collectd* repository. Please use it
+responsibly.
+
+#### Own work
+
+Open *pull requests* for your own changes, too:
+
+* For simple changes it's okay to self-approve and merge after a
+ successful build on the CI systems.
+* Trivial changes, cherry-picks from *master* and roll-up merges are
+ excempt and may be pushed to the version branches and *master* directly.
+* "Simple" and "trivial" are not further defined; use your best judgement.
+ We'll revisit this if and when it becomes necessary.
string type_instance = 5;
}
+message MetadataValue {
+ oneof value {
+ string string_value = 1;
+ int64 int64_value = 2;
+ uint64 uint64_value = 3;
+ double double_value = 4;
+ bool bool_value = 5;
+ };
+}
+
message Value {
oneof value {
uint64 counter = 1;
Identifier identifier = 4;
repeated string ds_names = 5;
-}
+ map<string, MetadataValue> meta_data = 6;
+}
\ No newline at end of file
READ_FUNC(average, (inst->sum / ((gauge_t)inst->num)));
READ_FUNC(min, inst->min);
READ_FUNC(max, inst->max);
- READ_FUNC(stddev, sqrt((((gauge_t)inst->num) * inst->squares_sum) -
- (inst->sum * inst->sum)) /
- ((gauge_t)inst->num));
+ READ_FUNC(stddev,
+ sqrt((((gauge_t)inst->num) * inst->squares_sum) -
+ (inst->sum * inst->sum)) /
+ ((gauge_t)inst->num));
}
/* Reset internal state. */
static int agg_config_aggregation(oconfig_item_t *ci) /* {{{ */
{
- aggregation_t *agg;
- _Bool is_valid;
- int status;
-
- agg = calloc(1, sizeof(*agg));
+ aggregation_t *agg = calloc(1, sizeof(*agg));
if (agg == NULL) {
ERROR("aggregation plugin: calloc failed.");
return -1;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
+ int status = 0;
if (strcasecmp("Host", child->key) == 0)
- cf_util_get_string_buffer(child, agg->ident.host,
- sizeof(agg->ident.host));
+ status = cf_util_get_string_buffer(child, agg->ident.host,
+ sizeof(agg->ident.host));
else if (strcasecmp("Plugin", child->key) == 0)
- cf_util_get_string_buffer(child, agg->ident.plugin,
- sizeof(agg->ident.plugin));
+ status = cf_util_get_string_buffer(child, agg->ident.plugin,
+ sizeof(agg->ident.plugin));
else if (strcasecmp("PluginInstance", child->key) == 0)
- cf_util_get_string_buffer(child, agg->ident.plugin_instance,
- sizeof(agg->ident.plugin_instance));
+ status = cf_util_get_string_buffer(child, agg->ident.plugin_instance,
+ sizeof(agg->ident.plugin_instance));
else if (strcasecmp("Type", child->key) == 0)
- cf_util_get_string_buffer(child, agg->ident.type,
- sizeof(agg->ident.type));
+ status = cf_util_get_string_buffer(child, agg->ident.type,
+ sizeof(agg->ident.type));
else if (strcasecmp("TypeInstance", child->key) == 0)
- cf_util_get_string_buffer(child, agg->ident.type_instance,
- sizeof(agg->ident.type_instance));
+ status = cf_util_get_string_buffer(child, agg->ident.type_instance,
+ sizeof(agg->ident.type_instance));
else if (strcasecmp("SetHost", child->key) == 0)
- cf_util_get_string(child, &agg->set_host);
+ status = cf_util_get_string(child, &agg->set_host);
else if (strcasecmp("SetPlugin", child->key) == 0)
- cf_util_get_string(child, &agg->set_plugin);
+ status = cf_util_get_string(child, &agg->set_plugin);
else if (strcasecmp("SetPluginInstance", child->key) == 0)
- cf_util_get_string(child, &agg->set_plugin_instance);
+ status = cf_util_get_string(child, &agg->set_plugin_instance);
else if (strcasecmp("SetTypeInstance", child->key) == 0)
- cf_util_get_string(child, &agg->set_type_instance);
+ status = cf_util_get_string(child, &agg->set_type_instance);
else if (strcasecmp("GroupBy", child->key) == 0)
- agg_config_handle_group_by(child, agg);
+ status = agg_config_handle_group_by(child, agg);
else if (strcasecmp("CalculateNum", child->key) == 0)
- cf_util_get_boolean(child, &agg->calc_num);
+ status = cf_util_get_boolean(child, &agg->calc_num);
else if (strcasecmp("CalculateSum", child->key) == 0)
- cf_util_get_boolean(child, &agg->calc_sum);
+ status = cf_util_get_boolean(child, &agg->calc_sum);
else if (strcasecmp("CalculateAverage", child->key) == 0)
- cf_util_get_boolean(child, &agg->calc_average);
+ status = cf_util_get_boolean(child, &agg->calc_average);
else if (strcasecmp("CalculateMinimum", child->key) == 0)
- cf_util_get_boolean(child, &agg->calc_min);
+ status = cf_util_get_boolean(child, &agg->calc_min);
else if (strcasecmp("CalculateMaximum", child->key) == 0)
- cf_util_get_boolean(child, &agg->calc_max);
+ status = cf_util_get_boolean(child, &agg->calc_max);
else if (strcasecmp("CalculateStddev", child->key) == 0)
- cf_util_get_boolean(child, &agg->calc_stddev);
+ status = cf_util_get_boolean(child, &agg->calc_stddev);
else
WARNING("aggregation plugin: The \"%s\" key is not allowed inside "
"<Aggregation /> blocks and will be ignored.",
child->key);
- }
+
+ if (status != 0) {
+ sfree(agg);
+ return status;
+ }
+ } /* for (int i = 0; i < ci->children_num; i++) */
if (agg_is_regex(agg->ident.host))
agg->regex_fields |= LU_GROUP_BY_HOST;
agg->regex_fields |= LU_GROUP_BY_TYPE_INSTANCE;
/* Sanity checking */
- is_valid = 1;
+ _Bool is_valid = 1;
if (strcmp("/.*/", agg->ident.type) == 0) /* {{{ */
{
ERROR("aggregation plugin: It appears you did not specify the required "
is_valid = 0;
} /* }}} */
- if (!is_valid) /* {{{ */
- {
+ if (!is_valid) { /* {{{ */
sfree(agg);
return -1;
} /* }}} */
- status = lookup_add(lookup, &agg->ident, agg->group_by, agg);
+ int status = lookup_add(lookup, &agg->ident, agg->group_by, agg);
if (status != 0) {
ERROR("aggregation plugin: lookup_add failed with status %i.", status);
sfree(agg);
status = amqp_socket_open(socket, CONF(conf, host), conf->port);
if (status < 0) {
- char errbuf[1024];
status *= -1;
- ERROR("amqp plugin: amqp_socket_open failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("amqp plugin: amqp_socket_open failed: %s", STRERROR(status));
amqp_destroy_connection(conf->connection);
conf->connection = NULL;
return status;
/* this interface is deprecated as of rabbitmq-c 0.4 */
sockfd = amqp_open_socket(CONF(conf, host), conf->port);
if (sockfd < 0) {
- char errbuf[1024];
status = (-1) * sockfd;
- ERROR("amqp plugin: amqp_open_socket failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("amqp plugin: amqp_open_socket failed: %s", STRERROR(status));
amqp_destroy_connection(conf->connection);
conf->connection = NULL;
return status;
static int camqp_shutdown(void) /* {{{ */
{
- DEBUG("amqp plugin: Shutting down %zu subscriber threads.",
+ DEBUG("amqp plugin: Shutting down %" PRIsz " subscriber threads.",
subscriber_threads_num);
subscriber_threads_running = 0;
while (received < body_size) {
status = amqp_simple_wait_frame(conf->connection, &frame);
if (status < 0) {
- char errbuf[1024];
status = (-1) * status;
- ERROR("amqp plugin: amqp_simple_wait_frame failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("amqp plugin: amqp_simple_wait_frame failed: %s", STRERROR(status));
camqp_close_connection(conf);
return status;
}
status = amqp_simple_wait_frame(conf->connection, &frame);
if (status < 0) {
- char errbuf[1024];
status = (-1) * status;
- ERROR("amqp plugin: amqp_simple_wait_frame failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("amqp plugin: amqp_simple_wait_frame failed: %s", STRERROR(status));
camqp_close_connection(conf);
return status;
}
status = plugin_thread_create(tmp, /* attr = */ NULL, camqp_subscribe_thread,
conf, "amqp subscribe");
if (status != 0) {
- char errbuf[1024];
- ERROR("amqp plugin: pthread_create failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("amqp plugin: pthread_create failed: %s", STRERROR(status));
return status;
}
char cbname[128];
snprintf(cbname, sizeof(cbname), "amqp/%s", conf->name);
- status = plugin_register_write(
- cbname, camqp_write, &(user_data_t){
- .data = conf, .free_func = camqp_config_free,
- });
+ status =
+ plugin_register_write(cbname, camqp_write,
+ &(user_data_t){
+ .data = conf, .free_func = camqp_config_free,
+ });
if (status != 0) {
camqp_config_free(conf);
return status;
status = -1;
}
- if (status == 0) {
- char callback_name[3 * DATA_MAX_NAME_LEN];
-
- snprintf(callback_name, sizeof(callback_name), "apache/%s/%s",
- (st->host != NULL) ? st->host : hostname_g,
- (st->name != NULL) ? st->name : "default");
-
- status = plugin_register_complex_read(
- /* group = */ NULL,
- /* name = */ callback_name,
- /* callback = */ apache_read_host,
- /* interval = */ 0,
- &(user_data_t){
- .data = st, .free_func = apache_free,
- });
- }
-
if (status != 0) {
apache_free(st);
return -1;
}
- return 0;
+ char callback_name[3 * DATA_MAX_NAME_LEN];
+
+ snprintf(callback_name, sizeof(callback_name), "apache/%s/%s",
+ (st->host != NULL) ? st->host : hostname_g,
+ (st->name != NULL) ? st->name : "default");
+
+ return plugin_register_complex_read(
+ /* group = */ NULL,
+ /* name = */ callback_name,
+ /* callback = */ apache_read_host,
+ /* interval = */ 0,
+ &(user_data_t){
+ .data = st, .free_func = apache_free,
+ });
} /* int config_add */
static int config(oconfig_item_t *ci) {
status = getaddrinfo(node, service, &ai_hints, &ai_return);
if (status != 0) {
- char errbuf[1024];
INFO("apcups plugin: getaddrinfo failed: %s",
- (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(status));
+ (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
return -1;
}
if (status != 0) /* `connect(2)' failed */
{
- char errbuf[1024];
- INFO("apcups plugin: connect failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ INFO("apcups plugin: connect failed: %s", STRERRNO);
close(sd);
return -1;
}
char recvline[1024];
char *tokptr;
char *toksaveptr;
- int try = 0;
+ int try
+ = 0;
int status;
#if APCMAIN
/* net_send closes the socket on error. */
assert(global_sockfd < 0);
if (try == 0) {
- try++;
+ try
+ ++;
count_retries++;
continue;
}
net_shutdown(&global_sockfd);
if (n < 0) {
- char errbuf[1024];
- ERROR("apcups plugin: Reading from socket failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("apcups plugin: Reading from socket failed: %s", STRERROR(status));
return -1;
}
int status = apc_query_server(conf_node, conf_service, &apcups_detail);
if (status != 0) {
- DEBUG("apcups plugin: apc_query_server (\"%s\", \"%s\") = %d",
- conf_node, conf_service, status);
+ DEBUG("apcups plugin: apc_query_server (\"%s\", \"%s\") = %d", conf_node,
+ conf_service, status);
return status;
}
char type_instance[DATA_MAX_NAME_LEN];
if (libaquaero5_poll(conf_device, &aq_data, &err_msg) < 0) {
- char errbuf[1024];
ERROR("aquaero plugin: Failed to poll device \"%s\": %s (%s)",
- conf_device ? conf_device : "default", err_msg,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ conf_device ? conf_device : "default", err_msg, STRERRNO);
return -1;
}
if (libaquaero5_getsettings(conf_device, &aq_sett, &err_msg) < 0) {
- char errbuf[1024];
ERROR("aquaero plugin: Failed to get settings "
"for device \"%s\": %s (%s)",
- conf_device ? conf_device : "default", err_msg,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ conf_device ? conf_device : "default", err_msg, STRERRNO);
return -1;
}
continue;
}
- DEBUG(
- "barometer: get_reference_temperature - initialize \"%s\", %zu vals",
- list->sensor_name, values_num);
+ DEBUG("barometer: get_reference_temperature - initialize \"%s\", %" PRIsz
+ " vals",
+ list->sensor_name, values_num);
list->initialized = 1;
list->num_values = values_num;
for (size_t i = 0; i < values_num; ++i) {
- DEBUG("barometer: get_reference_temperature - rate %zu: %lf **", i,
- values[i]);
+ DEBUG("barometer: get_reference_temperature - rate %" PRIsz ": %lf **",
+ i, values[i]);
if (!isnan(values[i])) {
avg_sum += values[i];
++avg_num;
}
for (size_t i = 0; i < REF_TEMP_AVG_NUM * list->num_values; ++i) {
- DEBUG("barometer: get_reference_temperature - history %zu: %lf", i,
+ DEBUG("barometer: get_reference_temperature - history %" PRIsz ": %lf", i,
values_history[i]);
if (!isnan(values_history[i])) {
avg_sum += values_history[i];
}
for (size_t i = 0; i < values_num; ++i) {
- DEBUG("barometer: get_reference_temperature - rate last %zu: %lf **", i,
- values[i]);
+ DEBUG("barometer: get_reference_temperature - rate last %" PRIsz
+ ": %lf **",
+ i, values[i]);
if (!isnan(values[i])) {
avg_sum += values[i];
++avg_num;
*/
static int MPL115_detect(void) {
__s32 res;
- char errbuf[1024];
if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL115_I2C_ADDRESS) < 0) {
ERROR("barometer: MPL115_detect problem setting i2c slave address to "
"0x%02X: %s",
- MPL115_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
+ MPL115_I2C_ADDRESS, STRERRNO);
return 0;
}
int8_t sic12MSB, sic12LSB, sic11MSB, sic11LSB, sic22MSB, sic22LSB;
int16_t sia0, sib1, sib2, sic12, sic11, sic22;
- char errbuf[1024];
-
res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL115_ADDR_COEFFS,
STATIC_ARRAY_SIZE(mpl115_coeffs),
mpl115_coeffs);
if (res < 0) {
- ERROR("barometer: MPL115_read_coeffs - problem reading data: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("barometer: MPL115_read_coeffs - problem reading data: %s", STRERRNO);
return -1;
}
int conv_temperature;
double adc_pressure;
double adc_temperature;
- char errbuf[1024];
*pressure = 0.0;
*temperature = 0.0;
if (retries > 0) {
ERROR("barometer: MPL115_read_averaged - requesting conversion: %s, "
"will retry at most %d more times",
- sstrerror(errno, errbuf, sizeof(errbuf)), retries);
+ STRERRNO, retries);
} else {
ERROR("barometer: MPL115_read_averaged - requesting conversion: %s, "
"too many failed retries",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
}
if (retries > 0) {
ERROR("barometer: MPL115_read_averaged - reading conversion: %s, "
"will retry at most %d more times",
- sstrerror(errno, errbuf, sizeof(errbuf)), retries);
+ STRERRNO, retries);
} else {
ERROR("barometer: MPL115_read_averaged - reading conversion: %s, "
"too many failed retries",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
}
*/
static int MPL3115_detect(void) {
__s32 res;
- char errbuf[1024];
if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, MPL3115_I2C_ADDRESS) < 0) {
ERROR("barometer: MPL3115_detect problem setting i2c slave address to "
"0x%02X: %s",
- MPL3115_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
+ MPL3115_I2C_ADDRESS, STRERRNO);
return 0;
}
__s32 ctrl;
__u8 data[MPL3115_NUM_CONV_VALS];
long int tmp_value = 0;
- char errbuf[1024];
/* Set Active - activate the device from standby */
res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1);
if (res < 0) {
- ERROR("barometer: MPL3115_read - cannot read CTRL_REG1: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("barometer: MPL3115_read - cannot read CTRL_REG1: %s", STRERRNO);
return 1;
}
ctrl = res;
res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_CTRL_REG1,
ctrl | MPL3115_CTRL_REG1_SBYB);
if (res < 0) {
- ERROR("barometer: MPL3115_read - problem activating: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("barometer: MPL3115_read - problem activating: %s", STRERRNO);
return 1;
}
res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
if (res < 0) {
ERROR("barometer: MPL3115_read - cannot read status register: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
res = i2c_smbus_read_byte_data(i2c_bus_fd, MPL3115_REG_STATUS);
if (res < 0) {
ERROR("barometer: MPL3115_read - cannot read status register: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
}
res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, MPL3115_REG_OUT_P_MSB,
MPL3115_NUM_CONV_VALS, data);
if (res < 0) {
- ERROR("barometer: MPL3115_read - cannot read data registers: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("barometer: MPL3115_read - cannot read data registers: %s", STRERRNO);
return 1;
}
static int MPL3115_init_sensor(void) {
__s32 res;
__s8 offset;
- char errbuf[1024];
/* Reset the sensor. It will reset immediately without ACKing */
/* the transaction, so no error handling here. */
res = i2c_smbus_write_byte_data(i2c_bus_fd, MPL3115_REG_OFF_T, offset);
if (res < 0) {
ERROR("barometer: MPL3115_init_sensor - problem setting temp offset: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
if (res < 0) {
ERROR(
"barometer: MPL3115_init_sensor - problem setting pressure offset: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
MPL3115_PT_DATA_TDEF);
if (res < 0) {
ERROR("barometer: MPL3115_init_sensor - problem setting PT_DATA_CFG: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
mpl3115_oversample);
if (res < 0) {
ERROR("barometer: MPL3115_init_sensor - problem configuring CTRL_REG1: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
*/
static int BMP085_detect(void) {
__s32 res;
- char errbuf[1024];
if (ioctl(i2c_bus_fd, I2C_SLAVE_FORCE, BMP085_I2C_ADDRESS) < 0) {
ERROR("barometer: BMP085_detect - problem setting i2c slave address to "
"0x%02X: %s",
- BMP085_I2C_ADDRESS, sstrerror(errno, errbuf, sizeof(errbuf)));
+ BMP085_I2C_ADDRESS, STRERRNO);
return 0;
}
res = i2c_smbus_read_byte_data(i2c_bus_fd, BMP085_ADDR_VERSION);
if (res < 0) {
ERROR("barometer: BMP085_detect - problem checking chip version: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 0;
}
DEBUG("barometer: BMP085_detect - chip version ML:0x%02X AL:0x%02X",
static int BMP085_read_coeffs(void) {
__s32 res;
__u8 coeffs[BMP085_NUM_COEFFS];
- char errbuf[1024];
res = i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_COEFFS,
BMP085_NUM_COEFFS, coeffs);
if (res < 0) {
- ERROR("barometer: BMP085_read_coeffs - problem reading data: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("barometer: BMP085_read_coeffs - problem reading data: %s", STRERRNO);
return -1;
}
long adc_pressure;
long adc_temperature;
- char errbuf[1024];
-
/* start conversion of temperature */
res = i2c_smbus_write_byte_data(i2c_bus_fd, BMP085_ADDR_CTRL_REG,
BMP085_CMD_CONVERT_TEMP);
if (res < 0) {
ERROR("barometer: BMP085_read - problem requesting temperature conversion: "
"%s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_CONV, 2, measBuff);
if (res < 0) {
ERROR("barometer: BMP085_read - problem reading temperature data: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
bmp085_cmdCnvPress);
if (res < 0) {
ERROR("barometer: BMP085_read - problem requesting pressure conversion: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
i2c_smbus_read_i2c_block_data(i2c_bus_fd, BMP085_ADDR_CONV, 3, measBuff);
if (res < 0) {
ERROR("barometer: BMP085_read - problem reading pressure data: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
* @return Zero when successful.
*/
static int collectd_barometer_init(void) {
- char errbuf[1024];
DEBUG("barometer: collectd_barometer_init");
if (i2c_bus_fd < 0) {
ERROR("barometer: collectd_barometer_init problem opening I2C bus device "
"\"%s\": %s (is loaded mod i2c-dev?)",
- config_device, sstrerror(errno, errbuf, sizeof(errbuf)));
+ config_device, STRERRNO);
return -1;
}
#if HAVE_TIMEGM
time_t t = timegm(&tm);
if (t == ((time_t)-1)) {
- char errbuf[1024];
- ERROR("bind plugin: timegm() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("bind plugin: timegm() failed: %s", STRERRNO);
return -1;
}
*ret_value = t;
#else
time_t t = mktime(&tm);
if (t == ((time_t)-1)) {
- char errbuf[1024];
- ERROR("bind plugin: mktime() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("bind plugin: mktime() failed: %s", STRERRNO);
return -1;
}
/* mktime assumes that tm is local time. Luckily, it also sets timezone to
uint64_t avgcount;
/** current index of counters - used to get type of counter */
int index;
- /** do we already have an avgcount for latency pair */
- int avgcount_exists;
/**
* similar to index, but current index of latency type counters -
* used to get last poll data of counter
yajl_struct *state = (yajl_struct *)ctx;
char buffer[number_len + 1];
char key[2 * DATA_MAX_NAME_LEN] = {0};
- _Bool latency_type = 0;
int status;
memcpy(buffer, number_val, number_len);
BUFFER_ADD(key, state->stack[i]);
}
- /* Special case for latency metrics. */
- if ((strcmp("avgcount", state->key) == 0) ||
- (strcmp("sum", state->key) == 0)) {
- latency_type = 1;
-
- /* depth >= 2 => (stack[-1] != NULL && stack[-2] != NULL) */
- assert((state->depth < 2) || ((state->stack[state->depth - 1] != NULL) &&
- (state->stack[state->depth - 2] != NULL)));
-
- /* Super-special case for filestore.journal_wr_bytes.avgcount: For
- * some reason, Ceph schema encodes this as a count/sum pair while all
- * other "Bytes" data (excluding used/capacity bytes for OSD space) uses
- * a single "Derive" type. To spare further confusion, keep this KPI as
- * the same type of other "Bytes". Instead of keeping an "average" or
- * "rate", use the "sum" in the pair and assign that to the derive
- * value. */
- if (convert_special_metrics && (state->depth >= 2) &&
- (strcmp("filestore", state->stack[state->depth - 2]) == 0) &&
- (strcmp("journal_wr_bytes", state->stack[state->depth - 1]) == 0) &&
- (strcmp("avgcount", state->key) == 0)) {
- DEBUG("ceph plugin: Skipping avgcount for filestore.JournalWrBytes");
- return CEPH_CB_CONTINUE;
- }
- } else /* not a latency type */
- {
- BUFFER_ADD(key, ".");
- BUFFER_ADD(key, state->key);
+ /* Super-special case for filestore.journal_wr_bytes.avgcount: For
+ * some reason, Ceph schema encodes this as a count/sum pair while all
+ * other "Bytes" data (excluding used/capacity bytes for OSD space) uses
+ * a single "Derive" type. To spare further confusion, keep this KPI as
+ * the same type of other "Bytes". Instead of keeping an "average" or
+ * "rate", use the "sum" in the pair and assign that to the derive
+ * value. */
+ if (convert_special_metrics && (state->depth > 2) &&
+ (strcmp("filestore", state->stack[state->depth - 2]) == 0) &&
+ (strcmp("journal_wr_bytes", state->stack[state->depth - 1]) == 0) &&
+ (strcmp("avgcount", state->key) == 0)) {
+ DEBUG("ceph plugin: Skipping avgcount for filestore.JournalWrBytes");
+ return CEPH_CB_CONTINUE;
}
- status = state->handler(state->handler_arg, buffer, key);
- if ((status == RETRY_AVGCOUNT) && latency_type) {
- /* Add previously skipped part of the key, either "avgcount" or "sum",
- * and try again. */
- BUFFER_ADD(key, ".");
- BUFFER_ADD(key, state->key);
+ BUFFER_ADD(key, ".");
+ BUFFER_ADD(key, state->key);
- status = state->handler(state->handler_arg, buffer, key);
- }
+ status = state->handler(state->handler_arg, buffer, key);
if (status != 0) {
ERROR("ceph plugin: JSON handler failed with status %d.", status);
}
/* compact_ds_name removed the special characters ":", "_", "-" and "+" from the
- * intput string. Characters following these special characters are capitalized.
+ * input string. Characters following these special characters are capitalized.
* Trailing "+" and "-" characters are replaces with the strings "Plus" and
* "Minus". */
static int compact_ds_name(char *buffer, size_t buffer_size, char const *src) {
return 0;
}
+static void cut_suffix(char *buffer, size_t buffer_size, char const *str,
+ char const *suffix) {
+
+ size_t str_len = strlen(str);
+ size_t suffix_len = strlen(suffix);
+
+ size_t offset = str_len - suffix_len + 1;
+
+ if (offset > buffer_size) {
+ offset = buffer_size;
+ }
+
+ sstrncpy(buffer, str, offset);
+}
+
/* count_parts returns the number of elements a "foo.bar.baz" style key has. */
static size_t count_parts(char const *key) {
size_t parts_num = 0;
*/
static int parse_keys(char *buffer, size_t buffer_size, const char *key_str) {
char tmp[2 * buffer_size];
+ size_t tmp_size = sizeof(tmp);
+ const char *cut_suffixes[] = {".type", ".avgcount", ".sum", ".avgtime"};
if (buffer == NULL || buffer_size == 0 || key_str == NULL ||
strlen(key_str) == 0)
return EINVAL;
- if ((count_parts(key_str) > 2) && has_suffix(key_str, ".type")) {
- /* strip ".type" suffix iff the key has more than two parts. */
- size_t sz = strlen(key_str) - strlen(".type") + 1;
+ sstrncpy(tmp, key_str, tmp_size);
- if (sz > sizeof(tmp))
- sz = sizeof(tmp);
- sstrncpy(tmp, key_str, sz);
- } else {
- sstrncpy(tmp, key_str, sizeof(tmp));
+ /* Strip suffix if it is ".type" or one of latency metric suffix. */
+ if (count_parts(key_str) > 2) {
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(cut_suffixes); i++) {
+ if (has_suffix(key_str, cut_suffixes[i])) {
+ cut_suffix(tmp, tmp_size, key_str, cut_suffixes[i]);
+ break;
+ }
+ }
}
return compact_ds_name(buffer, buffer_size, tmp);
switch (type) {
case DSET_LATENCY:
- if (vtmp->avgcount_exists == -1) {
+ if (has_suffix(key, ".avgcount")) {
sscanf(val, "%" PRIu64, &vtmp->avgcount);
- vtmp->avgcount_exists = 0;
// return after saving avgcount - don't dispatch value
// until latency calculation
return 0;
- } else {
- double sum, result;
- sscanf(val, "%lf", &sum);
-
+ } else if (has_suffix(key, ".sum")) {
if (vtmp->avgcount == 0) {
vtmp->avgcount = 1;
}
-
- /** User wants latency values as long run avg */
+ // user wants latency values as long run avg
+ // skip this step
if (long_run_latency_avg) {
- result = (sum / vtmp->avgcount);
- } else {
- result = get_last_avg(vtmp->d, ds_name, vtmp->latency_index, sum,
- vtmp->avgcount);
- if (result == -ENOMEM) {
- return -ENOMEM;
- }
+ return 0;
}
+ double sum, result;
+ sscanf(val, "%lf", &sum);
+ result = get_last_avg(vtmp->d, ds_name, vtmp->latency_index, sum,
+ vtmp->avgcount);
+ if (result == -ENOMEM) {
+ return -ENOMEM;
+ }
+ uv.gauge = result;
+ vtmp->latency_index = (vtmp->latency_index + 1);
+ } else if (has_suffix(key, ".avgtime")) {
+ /* The "avgtime" metric reports ("sum" / "avgcount"), i.e. the average
+ * time per request since the start of the Ceph daemon. Report this only
+ * when the user has configured "long running average". Otherwise, use the
+ * rate of "sum" and "avgcount" to calculate the current latency.
+ */
+
+ if (!long_run_latency_avg) {
+ return 0;
+ }
+ double result;
+ sscanf(val, "%lf", &result);
uv.gauge = result;
- vtmp->avgcount_exists = -1;
vtmp->latency_index = (vtmp->latency_index + 1);
+ } else {
+ WARNING("ceph plugin: ignoring unknown latency metric: %s", key);
+ return 0;
}
break;
case DSET_BYTES:
sizeof(vtmp->vlist.plugin_instance));
vtmp->d = io->d;
- vtmp->avgcount_exists = -1;
vtmp->latency_index = 0;
vtmp->index = 0;
yajl->handler_arg = vtmp;
struct cconn *io = io_array + i;
ret = cconn_prepare(io, fds + nfds);
if (ret < 0) {
- WARNING("ceph plugin: cconn_prepare(name=%s,i=%zu,st=%d)=%d",
+ WARNING("ceph plugin: cconn_prepare(name=%s,i=%" PRIsz ",st=%d)=%d",
io->d->name, i, io->state, ret);
cconn_close(io);
io->request_type = ASOK_REQ_NONE;
{"WBThrottle.ios_wb.type", "2"},
{"WBThrottle.inodes_dirtied.type", "2"},
{"WBThrottle.inodes_wb.type", "10"},
- {"filestore.journal_wr_bytes", "3117"},
+ {"filestore.journal_wr_bytes.sum", "3117"},
{"filestore.example_latency.avgcount", "42"},
{"filestore.example_latency.sum", "4711"},
};
cgroup_name);
fh = fopen(abs_path, "r");
if (fh == NULL) {
- char errbuf[1024];
- ERROR("cgroups plugin: fopen (\"%s\") failed: %s", abs_path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cgroups plugin: fopen (\"%s\") failed: %s", abs_path, STRERRNO);
return -1;
}
=item B<PUTVAL> I<Identifier> [I<OptionList>] I<Valuelist>
Submits one or more values (identified by I<Identifier>, see below) to the
-daemon which will dispatch it to all it's write-plugins.
+daemon which will dispatch it to all its write-plugins.
An I<Identifier> is of the form
C<I<host>B</>I<plugin>B<->I<instance>B</>I<type>B<->I<instance>> with both
#endif
#endif /* NAN_ZERO_ZERO */
-#include "libcollectdclient/collectd/client.h"
+#include "collectd/client.h"
#define RET_OKAY 0
#define RET_WARNING 1
=head1 RETURN VALUE
As usual for Nagios plugins, this program writes a short, one line status
-message to STDOUT and signals success or failure with it's return value. It
+message to STDOUT and signals success or failure with its return value. It
exits with a return value of B<0> for I<success>, B<1> for I<warning> and B<2>
for I<critical>. If the values are not available or some other error occurred,
it returns B<3> for I<unknown>.
If a Python script throws an exception it will be logged by collectd with the
name of the exception and the message. If you set this option to true it will
also log the full stacktrace just like the default output of an interactive
-Python interpreter. This should probably be set to false most of the time but
-is very useful for development and debugging of new modules.
+Python interpreter. This does not apply to the CollectError exception, which
+will never log a stacktrace.
+This should probably be set to false most of the time but is very useful for
+development and debugging of new modules.
=item B<Interactive> I<bool>
The following complex types are used to pass values between the Python plugin
and collectd:
+=head2 CollectdError
+
+This is an exception. If any Python script raises this exception it will
+still be treated like an error by collectd but it will be logged as a
+warning instead of an error and it will never generate a stacktrace.
+
+ class CollectdError(Exception)
+
+Basic exception for collectd Python scripts.
+Throwing this exception will not cause a stacktrace to be logged, even if
+LogTraces is enabled in the config.
+
=head2 Signed
The Signed class is just a long. It has all its methods and behaves exactly
=over 4
-=item B<dispatch>([type][, values][, plugin_instance][, type_instance][, plugin][, host][, time][, interval]) -> None. Dispatch a value list.
+=item B<dispatch>([type][, message][, plugin_instance][, type_instance][, plugin][, host][, time][, severity][, meta]) -> None. Dispatch a notification.
Dispatch this instance to the collectd process. The object has members for each
of the possible arguments for this method. For a detailed explanation of these
The severity of this notification. Assign or compare to I<NOTIF_FAILURE>,
I<NOTIF_WARNING> or I<NOTIF_OKAY>.
+=item meta
+
+These are the meta data for the Notification object.
+It has to be a dictionary of numbers, strings or bools. All keys must be
+strings. I<int> and I<long> objects will be dispatched as signed integers unless
+they are between 2**63 and 2**64-1, which will result in a unsigned integer.
+One of these storage classes can be forced by using the classes
+B<collectd.Signed> and B<collectd.Unsigned>. A meta object received by a
+notification callback will always contain B<Signed> or B<Unsigned> objects.
+
=back
=head1 FUNCTIONS
Community "community_string"
Collect "std_traffic"
Interval 120
+ Timeout 10
+ Retries 1
</Host>
<Host "some.server.mydomain.org">
Address "192.168.0.42"
Community "more_communities"
Collect "powerplus_voltge_input"
Interval 300
+ Timeout 5
+ Retries 5
</Host>
</Plugin>
=head1 CONFIGURATION
Since the aim of the C<snmp plugin> is to provide a generic interface to SNMP,
-it's configuration is not trivial and may take some time.
+its configuration is not trivial and may take some time.
Since the C<Net-SNMP> library is used you can use all the environment variables
that are interpreted by that package. See L<snmpcmd(1)> for more details.
B<Step> of generated RRD files depends on this setting it's wise to select a
reasonable value once and never change it.
+=item B<Timeout> I<Seconds>
+
+How long to wait for a response. The C<Net-SNMP> library default is 1 second.
+
+=item B<Retries> I<Integer>
+
+The number of times that a query should be retried after the Timeout expires.
+The C<Net-SNMP> library default is 5.
+
=back
=head1 SEE ALSO
#include "utils_heap.h"
-#include "libcollectdclient/collectd/client.h"
-#include "libcollectdclient/collectd/network.h"
+#include "collectd/client.h"
+#include "collectd/network.h"
#define DEF_NUM_HOSTS 1000
#define DEF_NUM_PLUGINS 20
"interesting". As a consequence collectd will issue a notification if they are
not received for B<Timeout> iterations. The B<Timeout> configuration option is
explained in section L<collectd.conf(5)/"GLOBAL OPTIONS">. If, for example,
-B<Timeout> is set to "2" (the default) and some hosts sends it's CPU statistics
+B<Timeout> is set to "2" (the default) and some hosts sends its CPU statistics
to the server every 60 seconds, a notification will be dispatched after about
120 seconds. It may take a little longer because the timeout is checked only
once each B<Interval> on the server.
=item B<PUTVAL> I<Identifier> [I<OptionList>] I<Valuelist>
Submits one or more values (identified by I<Identifier>, see below) to the
-daemon which will dispatch it to all it's write-plugins.
+daemon which will dispatch it to all its write-plugins.
An I<Identifier> is of the form
C<I<host>B</>I<plugin>B<->I<instance>B</>I<type>B<->I<instance>> with both
# ReportByCpu true
# ReportByState true
# ValuesPercentage false
+# ReportNumCpu false
+# ReportGuestState false
+# SubtractGuestState true
#</Plugin>
#
#<Plugin csv>
#<Plugin curl_xml>
# <URL "http://localhost/stats.xml">
# Host "my_host"
+# #Plugin "stats"
# Instance "some_instance"
# User "collectd"
# Password "thaiNg0I"
# Type "magic_level"
# #InstancePrefix "prefix-"
# InstanceFrom "td[1]"
+# #PluginInstanceFrom "td[1]"
# ValuesFrom "td[2]/span[@class=\"level\"]"
# </XPath>
# </URL>
# </Result>
# </Query>
# <Database "customers_db">
+# #Plugin "mycompany"
# Driver "mysql"
# DriverOption "host" "localhost"
# DriverOption "username" "collectd"
# Coremask "0x2"
# MemoryChannels "4"
# FilePrefix "rte"
+# LogLevel "7"
+# RteDriverLibPath "/usr/lib/dpdk-pmd"
# </EAL>
# SharedMemObj "dpdk_collectd_stats_0"
# EnabledPortMask 0xffff
#<Plugin filecount>
# <Directory "/path/to/dir">
+# #Plugin "foo"
# Instance "foodir"
# Name "*.conf"
# MTime "-5m"
# Size "+10k"
# Recursive true
# IncludeHidden false
+# RegularOnly true
+# #FilesSizeType "bytes"
+# #FilesCountType "files"
+# #TypeInstance "instance"
# </Directory>
#</Plugin>
# SSLCACertificateFile "/path/to/root.pem"
# SSLCertificateFile "/path/to/client.pem"
# SSLCertificateKeyFile "/path/to/client.key"
+# VerifyPeer true
# </Listen>
#</Plugin>
#</Plugin>
#<Plugin ipmi>
-# Sensor "some_sensor"
-# Sensor "another_one"
-# IgnoreSelected false
-# NotifySensorAdd false
-# NotifySensorRemove true
-# NotifySensorNotPresent false
+# <Instance "local">
+# Sensor "some_sensor"
+# Sensor "another_one"
+# IgnoreSelected false
+# NotifySensorAdd false
+# NotifySensorRemove true
+# NotifySensorNotPresent false
+# NotifyIPMIConnectionState false
+# SELEnabled false
+# SELClearEvent false
+# </Instance>
+# <Instance "remote">
+# Host "server.example.com"
+# Address "1.2.3.4"
+# Username "user"
+# Password "secret"
+# #AuthType "md5"
+# Sensor "some_sensor"
+# Sensor "another_one"
+# IgnoreSelected false
+# NotifySensorAdd false
+# NotifySensorRemove true
+# NotifySensorNotPresent false
+# NotifyIPMIConnectionState false
+# SELEnabled false
+# SELClearEvent false
+# </Instance>
#</Plugin>
#<Plugin iptables>
#</Plugin>
#<Plugin mcelog>
-# McelogClientSocket "/var/run/mcelog-client"
-# McelogLogfile "/var/log/mcelog"
+# <Memory>
+# McelogClientSocket "/var/run/mcelog-client"
+# PersistentNotification false
+# </Memory>
+# McelogLogfile "/var/log/mcelog"
#</Plugin>
#<Plugin md>
# QoS 2
# Topic "collectd/#"
# CleanSession true
+# CACert "/etc/ssl/ca.crt"
+# CertificateFile "/etc/ssl/client.crt"
+# CertificateKeyFile "/etc/ssl/client.pem"
+# TLSProtocol "tlsv1.2"
+# CipherSuite "ciphers"
# </Subscribe>
#</Plugin>
# CacheFlush 1800
@LOAD_PLUGIN_NETWORK@</Plugin>
+#<Plugin nfs>
+# ReportV2 false
+# #ReportV3 false
+# #ReportV4 false
+#</Plugin>
+
#<Plugin nginx>
# URL "http://localhost/status?auto"
# User "www-user"
# </Result>
# </Query>
# <Database "product_information">
+# #Plugin "warehouse"
# ConnectID "db01"
# Username "oracle"
# Password "secret"
# StoreRates true
# </Writer>
# <Database foo>
+# #Plugin "kingdom"
# Host "hostname"
# Port "5432"
# User "username"
# <Database bar>
# Interval 60
# Service "service_name"
-# Query backend # predefined
+# Query backends # predefined
# Query rt36_tickets
# </Database>
# <Database qux>
#<Plugin processes>
# CollectFileDescriptor true
# CollectContextSwitch true
+# CollectMemoryMaps true
+# CollectDelayAccounting false
# Process "name"
# ProcessMatch "name" "regex"
# <Process "collectd">
# CollectFileDescriptor false
# CollectContextSwitch false
+# CollectDelayAccounting true
# </Process>
# <ProcessMatch "name" "regex">
# CollectFileDescriptor false
# Community "community_string"
# Collect "std_traffic"
# Interval 120
+# Timeout 10
+# Retries 1
# </Host>
# <Host "some.server.mydomain.org">
# Address "192.168.0.42"
# Community "more_communities"
# Collect "powerplus_voltge_input"
# Interval 300
+# Timeout 5
+# Retries 5
# </Host>
#</Plugin>
# ReportBytes true
# ValuesAbsolute true
# ValuesPercentage false
+# ReportIO true
#</Plugin>
#<Plugin table>
# <Table "/proc/slabinfo">
+# #Plugin "table"
# Instance "slabinfo"
# Separator " "
# <Result>
# Bucket 0.5 1.0 # -> bucket-latency-foo-0.5_1
# Bucket 1.0 2.0 # -> bucket-latency-foo-1_2
# Bucket 2.0 0 # -> bucket-latency-foo-2_inf
+# #BucketType "bucket"
# </DSType>
# Type "latency"
# Instance "foo"
# SystemManagementInterrupt true
# DigitalTemperatureSensor true
# PackageThermalManagement true
-# RunningAveragePowerLimit "7"
+# RunningAveragePowerLimit "7"
#</Plugin>
#<Plugin unixsock>
# CollectPurge false # Varnish 2 only
# CollectSession false
# CollectSHM true
-# CollectSMA false # Varnish 2 only
+# CollectSMA false # Varnish 2 & 4 only
# CollectSMS false
# CollectSM false # Varnish 2 only
# CollectStruct false
# CollectVCL false
# CollectVSM false # Varnish 4 only
# CollectWorkers false
+# CollectLock false # Varnish 4 only
+# CollectMempool false # Varnish 4 only
+# CollectManagement false # Varnish 4 only
+# CollectSMF false # Varnish 4 only
+# CollectVBE false # Varnish 4 only
+# CollectMSE false # Varnish-Plus 4 only
# </Instance>
#</Plugin>
# Header "X-Custom-Header: custom_value"
# SSLVersion "TLSv1"
# Format "Command"
+# Prefix "collectd" # metric prefix, only available for KAIROSDB format
# Attribute "key" "value" # only available for KAIROSDB format
# TTL 0 # data ttl, only available for KAIROSDB format
# Metrics true
When set to B<true>, reports the number of available CPUs.
Defaults to B<false>.
+=item B<ReportGuestState> B<false>|B<true>
+
+When set to B<true>, reports the "guest" and "guest_nice" CPU states.
+Defaults to B<false>.
+
+=item B<SubtractGuestState> B<false>|B<true>
+
+This option is only considered when B<ReportGuestState> is set to B<true>.
+"guest" and "guest_nice" are included in respectively "user" and "nice".
+If set to B<true>, "guest" will be subtracted from "user" and "guest_nice"
+will be subtracted from "nice".
+Defaults to B<true>.
+
=back
=head2 Plugin C<cpufreq>
<Plugin curl>
<Page "stock_quotes">
+ Plugin "quotes"
URL "http://finance.google.com/finance?q=NYSE%3AAMD"
User "foo"
Password "bar"
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<curl>.
+
=item B<URL> I<URL>
URL of the web site to retrieve. Since a regular expression will be used to
Use I<Name> as the host name when submitting values. Defaults to the global
host name setting.
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<curl_json>.
+
=item B<Instance> I<Instance>
Sets the plugin instance to I<Instance>.
<Plugin "curl_xml">
<URL "http://localhost/stats.xml">
Host "my_host"
+ #Plugin "curl_xml"
Instance "some_instance"
User "collectd"
Password "thaiNg0I"
Type "magic_level"
#InstancePrefix "prefix-"
InstanceFrom "td[1]"
+ #PluginInstanceFrom "td[1]"
ValuesFrom "td[2]/span[@class=\"level\"]"
</XPath>
</URL>
Use I<Name> as the host name when submitting values. Defaults to the global
host name setting.
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to 'curl_xml'.
+
=item B<Instance> I<Instance>
-Use I<Instance> as the plugin instance when submitting values. Defaults to an
-empty string (no plugin instance).
+Use I<Instance> as the plugin instance when submitting values.
+May be overridden by B<PluginInstanceFrom> option inside B<XPath> blocks.
+Defaults to an empty string (no plugin instance).
=item B<Namespace> I<Prefix> I<URL>
XPath expression must return exactly one element. The element's value is then
used as I<type instance>, possibly prefixed with I<InstancePrefix> (see above).
-This value is required. As a special exception, if the "base XPath expression"
-(the argument to the B<XPath> block) returns exactly one argument, then this
-option may be omitted.
+=item B<PluginInstanceFrom> I<PluginInstanceFrom>
+
+Specifies a XPath expression to use for determining the I<plugin instance>. The
+XPath expression must return exactly one element. The element's value is then
+used as I<plugin instance>.
+
+=back
+
+If the "base XPath expression" (the argument to the B<XPath> block) returns
+exactly one argument, then I<InstanceFrom> and I<PluginInstanceFrom> may be omitted.
+Otherwise, at least one of I<InstanceFrom> or I<PluginInstanceFrom> is required.
+
+=over 4
=item B<ValuesFrom> I<ValuesFrom> [I<ValuesFrom> ...]
I<type> specified with B<Type> (see above). Each XPath expression must return
exactly one element. The element's value is then parsed as a number and used as
value for the appropriate value in the value list dispatched to the daemon.
+This option is required.
=back
</Result>
</Query>
<Database "product_information">
+ #Plugin "warehouse"
Driver "mysql"
Interval 120
DriverOption "host" "localhost"
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting query results from
+this B<Database>. Defaults to C<dbi>.
+
=item B<Interval> I<Interval>
Sets the interval (in seconds) in which the values will be collected from this
MemoryChannels "4"
FilePrefix "rte"
SocketMemory "1024"
+ LogLevel "7"
+ RteDriverLibPath "/usr/lib/dpdk-pmd"
</EAL>
SharedMemObj "dpdk_collectd_stats_0"
EnabledPortMask 0xffff
A string containing amount of Memory to allocate from hugepages on specific
sockets in MB. This is an optional value.
+=item B<LogLevel> I<LogLevel_number>
+
+A string containing log level number. This parameter is optional.
+If parameter is not present then default value "7" - (INFO) is used.
+Value "8" - (DEBUG) can be set to enable debug traces.
+
+=item B<RteDriverLibPath> I<Path>
+
+A string containing path to shared pmd driver lib or path to directory,
+where shared pmd driver libs are available. This parameter is optional.
+This parameter enable loading of shared pmd driver libs from defined path.
+E.g.: "/usr/lib/dpdk-pmd/librte_pmd_i40e.so"
+or "/usr/lib/dpdk-pmd"
+
=back
=over 3
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to B<filecount>.
+
=item B<Instance> I<Instance>
-Sets the plugin instance to I<Instance>. That instance name must be unique, but
-it's your responsibility, the plugin doesn't check for that. If not given, the
-instance is set to the directory name with all slashes replaced by underscores
-and all leading underscores removed.
+Sets the plugin instance to I<Instance>. If not given, the instance is set to
+the directory name with all slashes replaced by underscores and all leading
+underscores removed. Empty value is allowed.
=item B<Name> I<Pattern>
"Hidden" files and directories are those, whose name begins with a dot.
Defaults to I<false>, i.e. by default hidden files and directories are ignored.
+=item B<RegularOnly> I<true>|I<false>
+
+Controls whether or not to include only regular files in the count.
+Defaults to I<true>, i.e. by default non regular files are ignored.
+
+=item B<FilesSizeType> I<Type>
+
+Sets the type used to dispatch files combined size. Empty value ("") disables
+reporting. Defaults to B<bytes>.
+
+=item B<FilesCountType> I<Type>
+
+Sets the type used to dispatch number of files. Empty value ("") disables
+reporting. Defaults to B<files>.
+
+=item B<TypeInstance> I<Instance>
+
+Sets the I<type instance> used to dispatch values. Defaults to an empty string
+(no plugin instance).
+
=back
=head2 Plugin C<GenericJMX>
Filenames specifying SSL certificate and key material to be used with SSL
connections.
+=item B<VerifyPeer> B<true>|B<false>
+
+When enabled, a valid client certificate is required to connect to the server.
+When disabled, a client certifiacte is not requested and any unsolicited client
+certificate is accepted.
+Enabled by default.
+
=back
=back
=head2 Plugin C<ipmi>
+The B<ipmi plugin> allows to monitor server platform status using the Intelligent
+Platform Management Interface (IPMI). Local and remote interfaces are supported.
+
+The plugin configuration consists of one or more B<Instance> blocks which
+specify one I<ipmi> connection each. Each block requires one unique string
+argument as the instance name. If instances are not configured, an instance with
+the default option values will be created.
+
+For backwards compatibility, any option other than B<Instance> block will trigger
+legacy config handling and it will be treated as an option within B<Instance>
+block. This support will go away in the next major version of Collectd.
+
+Within the B<Instance> blocks, the following options are allowed:
+
=over 4
+=item B<Address> I<Address>
+
+Hostname or IP to connect to. If not specified, plugin will try to connect to
+local management controller (BMC).
+
+=item B<Username> I<Username>
+
+=item B<Password> I<Password>
+
+The username and the password to use for the connection to remote BMC.
+
+=item B<AuthType> I<MD5>|I<rmcp+>
+
+Forces the authentication type to use for the connection to remote BMC.
+By default most secure type is seleted.
+
+=item B<Host> I<Hostname>
+
+Sets the B<host> field of dispatched values. Defaults to the global hostname
+setting.
+
=item B<Sensor> I<Sensor>
Selects sensors to collect or to ignore, depending on B<IgnoreSelected>.
If you have for example dual power supply and one of them is (un)plugged then
a notification is sent.
+=item B<NotifyIPMIConnectionState> I<true>|I<false>
+
+If a IPMI connection state changes after initialization time of a minute
+a notification is sent. Defaults to B<false>.
+
+=item B<SELEnabled> I<true>|I<false>
+
+If system event log (SEL) is enabled, plugin will listen for sensor threshold
+and discrete events. When event is received the notification is sent.
+Defaults to B<false>.
+
+=item B<SELClearEvent> I<true>|I<false>
+
+If SEL clear event is enabled, plugin will delete event from SEL list after
+it is received and successfully handled. In this case other tools that are
+subscribed for SEL events will receive an empty event.
+Defaults to B<false>.
+
=back
=head2 Plugin C<iptables>
mcelog server is running. When the server is running, the plugin will tail the
specified logfile to retrieve machine check exception information and send a
notification with the details from the logfile. The plugin will use the mcelog
-client protocol to retrieve memory related machine check exceptions.
+client protocol to retrieve memory related machine check exceptions. Note that
+for memory exceptions, notifications are only sent when there is a change in
+the number of corrected/uncorrected memory errors.
-=over 4
+=head3 The Memory block
+
+Note: these options cannot be used in conjunction with the logfile options, they are mutually
+exclusive.
+
+=over 3
=item B<McelogClientSocket> I<Path>
Connect to the mcelog client socket using the UNIX domain socket at I<Path>.
Defaults to B<"/var/run/mcelog-client">.
+=item B<PersistentNotification> B<true>|B<false>
+Override default configuration to only send notifications when sent when there
+is a change in the number of corrected/uncorrected memory errors. When set to
+true notifications will be sent for every read cycle. Default is false. Does
+not affect the stats being dispatched.
+
+=back
+
+=over 4
+
=item B<McelogLogfile> I<Path>
-The mcelog file to parse. Defaults to B<"/var/log/mcelog">.
+The mcelog file to parse. Defaults to B<"/var/log/mcelog">. Note: this option
+cannot be used in conjunction with the memory block options, they are mutually
+exclusive.
=back
<Page "plugin_instance">
Server "localhost"
Key "page_key"
+ Plugin "plugin_name"
<Match>
Regex "(\\d+) bytes sent"
DSType CounterAdd
When connected to the memcached server, asks for the page I<Key>.
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<memcachec>.
+
=item E<lt>B<Match>E<gt>
Match blocks define which strings to look for and how matches substrings are
B<RegisterType> has been set to B<Uint32> or B<Float>, this and the next
register will be read (the register number is increased by one).
-=item B<RegisterType> B<Int16>|B<Int32>|B<Uint16>|B<Uint32>|B<Float>
+=item B<RegisterType> B<Int16>|B<Int32>|B<Uint16>|B<Uint32>|B<Float>|B<Int32LE>|B<Uint32LE>|B<FloatLE>
-Specifies what kind of data is returned by the device. If the type is B<Int32>,
-B<Uint32> or B<Float>, two 16E<nbsp>bit registers will be read and the data is
-combined into one value. Defaults to B<Uint16>.
+Specifies what kind of data is returned by the device. This defaults to
+B<Uint16>. If the type is B<Int32>, B<Int32LE>, B<Uint32>, B<Uint32LE>,
+B<Float> or B<FloatLE>, two 16E<nbsp>bit registers at B<RegisterBase>
+and B<RegisterBase+1> will be read and the data is combined into one
+32E<nbsp>value. For B<Int32>, B<Uint32> and B<Float> the most significant
+16E<nbsp>bits are in the register at B<RegisterBase> and the least
+significant 16E<nbsp>bits are in the register at B<RegisterBase+1>.
+For B<Int32LE>, B<Uint32LE>, or B<Float32LE>, the high and low order
+registers are swapped with the most significant 16E<nbsp>bits in
+the B<RegisterBase+1> and the least significant 16E<nbsp>bits in
+B<RegisterBase>.
=item B<RegisterCmd> B<ReadHolding>|B<ReadInput>
Path to the PEM-encoded CA certificate file. Setting this option enables TLS
communication with the MQTT broker, and as such, B<Port> should be the TLS-enabled
port of the MQTT broker.
-A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
+This option enables the use of TLS.
=item B<CertificateFile> I<file>
Path to the PEM-encoded certificate file to use as client certificate when
connecting to the MQTT broker.
-A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
+Only valid if B<CACert> and B<CertificateKeyFile> are also set.
=item B<CertificateKeyFile> I<file>
Path to the unencrypted PEM-encoded key file corresponding to B<CertificateFile>.
-A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
+Only valid if B<CACert> and B<CertificateFile> are also set.
=item B<TLSProtocol> I<protocol>
C<tlsv1.2>) to use for the TLS connection to the broker. If not set a default
version is used which depends on the version of OpenSSL the Mosquitto library
was linked against.
+Only valid if B<CACert> is set.
=item B<CipherSuite> I<ciphersuite>
A string describing the ciphers available for use. See L<ciphers(1)> and the
C<openssl ciphers> utility for more information. If unset, the default ciphers
will be used.
-
+Only valid if B<CACert> is set.
=back
or SQL threads are not running. Defaults to B<false>.
=item B<WsrepStats> I<true|false>
-
+
Enable the collection of wsrep plugin statistics, used in Master-Master
replication setups like in MySQL Galera/Percona XtraDB Cluster.
User needs only privileges to execute 'SHOW GLOBAL STATUS'
-
+
=item B<ConnectTimeout> I<Seconds>
Sets the connect timeout for the MySQL client.
=back
+=head2 Plugin C<nfs>
+
+The I<nfs plugin> collects information about the usage of the Network File
+System (NFS). It counts the number of procedure calls for each procedure,
+grouped by version and whether the system runs as server or client.
+
+It is possibly to omit metrics for a specific NFS version by setting one or
+more of the following options to B<false> (all of them default to B<true>).
+
+=over 4
+
+=item B<ReportV2> B<true>|B<false>
+
+=item B<ReportV3> B<true>|B<false>
+
+=item B<ReportV4> B<true>|B<false>
+
+=back
+
=head2 Plugin C<nginx>
This plugin collects the number of connections and requests handled by the
traffic statistics about connected clients.
To set up OpenVPN to write to the status file periodically, use the
-B<--status> option of OpenVPN. Since OpenVPN can write two different formats,
-you need to set the required format, too. This is done by setting
-B<--status-version> to B<2>.
+B<--status> option of OpenVPN.
So, in a nutshell you need:
openvpn $OTHER_OPTIONS \
- --status "/var/run/openvpn-status" 10 \
- --status-version 2
+ --status "/var/run/openvpn-status" 10
Available options:
</Result>
</Query>
<Database "product_information">
+ #Plugin "warehouse"
ConnectID "db01"
Username "oracle"
Password "secret"
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting query results from
+this B<Database>. Defaults to C<oracle>.
+
=item B<ConnectID> I<ID>
Defines the "database alias" or "service name" to connect to. Usually, these
enable the interface, OVS DB daemon should be running with C<--remote=ptcp:>
option. See L<ovsdb-server(1)> for more details. The option may be either
network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string
-format. Defaults to B<'localhost'>.
+format. Defaults to C<localhost>.
=item B<Port> I<service>
enable the interface, OVS DB daemon should be running with C<--remote=ptcp:>
option. See L<ovsdb-server(1)> for more details. The option may be either
network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string
-format. Defaults to B<'localhost'>.
+format. Defaults to C<localhost>.
=item B<Port> I<service>
</Writer>
<Database foo>
+ Plugin "kingdom"
Host "hostname"
Port "5432"
User "username"
<Database bar>
Interval 300
Service "service_name"
- Query backend # predefined
+ Query backends # predefined
Query rt36_tickets
</Database>
amount of time will be lost, for example, if a single statement within the
transaction fails or if the database server crashes.
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting query results from
+this B<Database>. Defaults to C<postgresql>.
+
=item B<Instance> I<name>
Specify the plugin instance name that should be used instead of the database
=head2 Plugin C<processes>
-=over 4
+Collects information about processes of local system.
-=item B<Process> I<Name>
+By default, with no process matches configured, only general statistics is
+collected: the number of processes in each state and fork rate.
-Select more detailed statistics of processes matching this name. The statistics
-collected for these selected processes are:
+Process matches can be configured by B<Process> and B<ProcessMatch> options.
+These may also be a block in which further options may be specified.
+
+The statistics collected for matched processes are:
- size of the resident segment size (RSS)
- user- and system-time used
- number of processes
- number of threads
- number of open files (under Linux)
+ - number of memory mapped files (under Linux)
- io data (where available)
- context switches (under Linux)
- - minor and major pagefaults.
+ - minor and major pagefaults
+ - Delay Accounting information (Linux only, requires libmnl)
+
+B<Synopsis:>
+
+ <Plugin processes>
+ CollectFileDescriptor true
+ CollectContextSwitch true
+ CollectDelayAccounting false
+ Process "name"
+ ProcessMatch "name" "regex"
+ <Process "collectd">
+ CollectFileDescriptor false
+ CollectContextSwitch false
+ CollectDelayAccounting true
+ </Process>
+ <ProcessMatch "name" "regex">
+ CollectFileDescriptor false
+ CollectContextSwitch true
+ </Process>
+ </Plugin>
-Some platforms have a limit on the length of process names. I<Name> must stay
-below this limit.
+=over 4
+
+=item B<Process> I<Name>
+
+Select more detailed statistics of processes matching this name.
+
+Some platforms have a limit on the length of process names.
+I<Name> must stay below this limit.
=item B<ProcessMatch> I<name> I<regex>
-Similar to the B<Process> option this allows one to select more detailed
-statistics of processes matching the specified I<regex> (see L<regex(7)> for
-details). The statistics of all matching processes are summed up and
-dispatched to the daemon using the specified I<name> as an identifier. This
-allows one to "group" several processes together. I<name> must not contain
-slashes.
+Select more detailed statistics of processes matching the specified I<regex>
+(see L<regex(7)> for details). The statistics of all matching processes are
+summed up and dispatched to the daemon using the specified I<name> as an
+identifier. This allows one to "group" several processes together.
+I<name> must not contain slashes.
=item B<CollectContextSwitch> I<Boolean>
-Collect context switch of the process.
+Collect the number of context switches for matched processes.
+Disabled by default.
+
+=item B<CollectDelayAccounting> I<Boolean>
+
+If enabled, collect Linux Delay Accounding information for matching processes.
+Delay Accounting provides the time processes wait for the CPU to become
+available, for I/O operations to finish, for pages to be swapped in and for
+freed pages to be reclaimed. The metrics are reported as "seconds per second"
+using the C<delay_rate> type, e.g. C<delay_rate-delay-cpu>.
+Disabled by default.
+
+This option is only available on Linux, requires the C<libmnl> library and
+requires the C<CAP_NET_ADMIN> capability at runtime.
+
+=item B<CollectFileDescriptor> I<Boolean>
+
+Collect number of file descriptors of matched processes.
+Disabled by default.
+
+=item B<CollectMemoryMaps> I<Boolean>
+
+Collect the number of memory mapped files of the process.
+The limit for this number is configured via F</proc/sys/vm/max_map_count> in
+the Linux kernel.
=back
+The B<CollectContextSwitch>, B<CollectDelayAccounting>,
+B<CollectFileDescriptor> and B<CollectMemoryMaps> options may be used inside
+B<Process> and B<ProcessMatch> blocks. When used there, these options affect
+reporting the corresponding processes only. Outside of B<Process> and
+B<ProcessMatch> blocks these options set the default value for subsequent
+matches.
+
=head2 Plugin C<protocols>
Collects a lot of information about various network protocols, such as I<IP>,
an interval. If set to B<False>, the default, these values aren't calculated /
dispatched.
+Please note what reported timer values less than 0.001 are ignored in all B<Timer*> reports.
+
=back
=head2 Plugin C<swap>
This is useful for deploying I<collectd> in a heterogeneous environment, where
swap sizes differ and you want to specify generic thresholds or similar.
+=item B<ReportIO> B<true>|B<false>
+
+Enables or disables reporting swap IO. Defaults to B<true>.
+
+This is useful for the cases when swap IO is not neccessary, is not available,
+or is not reliable.
+
=back
=head2 Plugin C<syslog>
<Plugin table>
<Table "/proc/slabinfo">
+ #Plugin "slab"
Instance "slabinfo"
Separator " "
<Result>
=over 4
+=item B<Plugin> I<Plugin>
+
+If specified, I<Plugin> is used as the plugin name when submitting values.
+Defaults to B<table>.
+
=item B<Instance> I<instance>
-If specified, I<instance> is used as the plugin instance. So, in the above
-example, the plugin name C<table-slabinfo> would be used. If omitted, the
+If specified, I<instance> is used as the plugin instance. If omitted, the
filename of the table is used instead, with all special characters replaced
with an underscore (C<_>).
<Plugin "tail">
<File "/var/log/exim4/mainlog">
+ Plugin "mail"
Instance "exim"
Interval 60
<Match>
<DSType "Distribution">
Percentile 99
Bucket 0 100
+ #BucketType "bucket"
</DSType>
Type "latency"
Instance "foo"
logfile to parse. Within each B<File> block, there are one or more B<Match>
blocks, which configure a regular expression to search for.
-The B<Instance> option in the B<File> block may be used to set the plugin
-instance. So in the above example the plugin name C<tail-foo> would be used.
-This plugin instance is for all B<Match> blocks that B<follow> it, until the
-next B<Instance> option. This way you can extract several plugin instances from
-one logfile, handy when parsing syslog and the like.
+The B<Plugin> and B<Instance> options in the B<File> block may be used to set
+the plugin name and instance respectively. So in the above example the plugin name
+C<mail-exim> would be used.
+
+These options are applied for all B<Match> blocks that B<follow> it, until the
+next B<Plugin> or B<Instance> option. This way you can extract several plugin
+instances from one logfile, handy when parsing syslog and the like.
The B<Interval> option allows you to define the length of time between reads. If
this is not set, the default Interval will be used.
<DSType "Distribution">
Percentile 99
Bucket 0 100
+ BucketType "bucket"
</DSType>
=over 4
Bucket 20 50
Bucket 50 0
-Metrics are reported with the I<type> C<bucket> and the I<type instance>
+Metrics are reported with the I<type> set by B<BucketType> option (C<bucket>
+by default) and the I<type instance>
C<E<lt>TypeE<gt>[-E<lt>InstanceE<gt>]-E<lt>lower_boundE<gt>_E<lt>upper_boundE<gt>>.
This option may be repeated to calculate more than one rate.
+=item B<BucketType> I<Type>
+
+Sets the type used to dispatch B<Bucket> metrics.
+Optional, by default C<bucket> will be used.
+
=back
=back
Index 1
</Metric>
<File "/var/log/snort/snort.stats">
- Instance "snort-eth0"
+ Plugin "snortstats"
+ Instance "eth0"
Interval 600
Collect "snort-dropped"
</File>
=over 4
+=item B<Plugin> I<Plugin>
+
+Use I<Plugin> as the plugin name when submitting values.
+Defaults to C<tail_csv>.
+
=item B<Instance> I<PluginInstance>
Sets the I<plugin instance> used when dispatching the values.
Boolean enabling the use of logical core numbering for per core statistics.
When enabled, C<cpuE<lt>nE<gt>> is used as plugin instance, where I<n> is a
-sequential number assigned by the kernel. Otherwise, C<coreE<lt>nE<gt>> is used
-where I<n> is the n-th core of the socket, causing name conflicts when there is
-more than one socket.
+dynamic number assigned by the kernel. Otherwise, C<coreE<lt>nE<gt>> is used
+if there is only one package and C<pkgE<lt>nE<gt>-coreE<lt>mE<gt>> if there is
+more than one, where I<n> is the n-th core of package I<m>.
=back
CollectVCL false
CollectVSM false
CollectWorkers false
+ CollectLock false
+ CollectMempool false
+ CollectManagement false
+ CollectSMF false
+ CollectVBE false
+ CollectMSE false
</Instance>
</Plugin>
=item B<CollectSMA> B<true>|B<false>
malloc or umem (umem_alloc(3MALLOC) based) storage statistics. The umem storage
-component is Solaris specific. Only available with Varnish 2.x. False by
-default.
+component is Solaris specific. Note: SMA, SMF and MSE share counters, enable
+only the one used by the Varnish instance. Only available with Varnish 2.x.
+False by default.
=item B<CollectSMS> B<true>|B<false>
=item B<CollectSM> B<true>|B<false>
-file (memory mapped file) storage statistics. Only available with Varnish 2.x.
+file (memory mapped file) storage statistics. Only available with Varnish 2.x.,
+in varnish 4.x. use CollectSMF.
False by default.
=item B<CollectStruct> B<true>|B<false>
Collect statistics about worker threads. False by default.
+=item B<CollectVBE> B<true>|B<false>
+
+Backend counters. Only available with Varnish 4.x. False by default.
+
+=item B<CollectSMF> B<true>|B<false>
+
+file (memory mapped file) storage statistics. Only available with Varnish 4.x.
+Note: SMA, SMF and MSE share counters, enable only the one used by the Varnish
+instance. Used to be called SM in Varnish 2.x. False by default.
+
+=item B<CollectManagement> B<true>|B<false>
+
+Management process counters. Only available with Varnish 4.x. False by default.
+
+=item B<CollectLock> B<true>|B<false>
+
+Lock counters. Only available with Varnish 4.x. False by default.
+
+=item B<CollectMempool> B<true>|B<false>
+
+Memory pool counters. Only available with Varnish 4.x. False by default.
+
+=item B<CollectMSE> B<true>|B<false>
+
+Varnish Massive Storage Engine 2.0 (MSE2) is an improved storage backend for
+Varnish, replacing the traditional malloc and file storages. Only available
+with Varnish-Plus 4.x. Note: SMA, SMF and MSE share counters, enable only the
+one used by the Varnish instance. False by default.
+
=back
=head2 Plugin C<virt>
=item B<BlockDeviceFormat> B<target>|B<source>
If I<BlockDeviceFormat> is set to B<target>, the default, then the device name
-seen by the guest will be used for reporting metrics.
+seen by the guest will be used for reporting metrics.
This corresponds to the C<E<lt>targetE<gt>> node in the XML definition of the
domain.
Please refer to L<http://kairosdb.github.io/docs/build/html/restapi/AddDataPoints.html?highlight=ttl>
+=item B<Prefix> I<String>
+
+Only available for the KAIROSDB output format.
+
+Sets the metrics prefix I<string>. Defaults to I<collectd>.
+
=item B<Metrics> B<true>|B<false>
Controls whether I<metrics> are POSTed to this location. Defaults to B<true>.
Prefix "collectd/"
Database 1
MaxSetSize -1
+ MaxSetDuration -1
StoreRates true
</Node>
</Plugin>
The B<MaxSetSize> option limits the number of items that the I<Sorted Sets> can
hold. Negative values for I<Items> sets no limit, which is the default behavior.
+=item B<MaxSetDuration> I<Seconds>
+
+The B<MaxSetDuration> option limits the duration of items that the
+I<Sorted Sets> can hold. Negative values for I<Items> sets no duration, which
+is the default behavior.
+
=item B<StoreRates> B<true>|B<false>
If set to B<true> (the default), convert counter values to rates. If set to
=item B<-P> I<E<lt>pid-fileE<gt>>
-Specify an alternative pid file. This overwrites any settings in the config
+Specify an alternative pid file. This overwrites any settings in the config
file. This is thought for init-scripts that require the PID-file in a certain
directory to work correctly. For everyday-usage use the B<PIDFile>
config-option.
+=item B<-B>
+
+If set, collectd will I<not> try to create its base directory. If the base
+directory does not exist, it will exit rather than trying to create the
+directory.
+
=item B<-f>
Don't fork to the background. I<collectd> will also B<not> close standard file
=head1 PLUGINS
-As noted above, the real power of collectd lies within it's plugins. A
+As noted above, the real power of collectd lies within its plugins. A
(hopefully complete) list of plugins and short descriptions can be found in the
F<README> file that is distributed with the sourcecode. If you're using a
package it's a good bet to search somewhere near F</usr/share/doc/collectd>.
#endif
#endif /* NAN_ZERO_ZERO */
-#include "libcollectdclient/collectd/client.h"
+#include "collectd/client.h"
#ifndef PREFIX
#define PREFIX "/opt/" PACKAGE_NAME
fh = fopen("/proc/stat", "r");
if (fh == NULL) {
- ERROR("contextswitch plugin: unable to open /proc/stat: %s",
- sstrerror(errno, buffer, sizeof(buffer)));
+ ERROR("contextswitch plugin: unable to open /proc/stat: %s", STRERRNO);
return -1;
}
status =
perfstat_cpu_total(NULL, &perfcputotal, sizeof(perfstat_cpu_total_t), 1);
if (status < 0) {
- char errbuf[1024];
- ERROR("contextswitch plugin: perfstat_cpu_total: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("contextswitch plugin: perfstat_cpu_total: %s", STRERRNO);
return -1;
}
#define COLLECTD_CPU_STATE_INTERRUPT 5
#define COLLECTD_CPU_STATE_SOFTIRQ 6
#define COLLECTD_CPU_STATE_STEAL 7
-#define COLLECTD_CPU_STATE_IDLE 8
-#define COLLECTD_CPU_STATE_ACTIVE 9 /* sum of (!idle) */
-#define COLLECTD_CPU_STATE_MAX 10 /* #states */
+#define COLLECTD_CPU_STATE_GUEST 8
+#define COLLECTD_CPU_STATE_GUEST_NICE 9
+#define COLLECTD_CPU_STATE_IDLE 10
+#define COLLECTD_CPU_STATE_ACTIVE 11 /* sum of (!idle) */
+#define COLLECTD_CPU_STATE_MAX 12 /* #states */
#if HAVE_STATGRAB_H
#include <statgrab.h>
#error "No applicable input method."
#endif
-static const char *cpu_state_names[] = {"user", "system", "wait", "nice",
- "swap", "interrupt", "softirq", "steal",
- "idle", "active"};
+static const char *cpu_state_names[] = {
+ "user", "system", "wait", "nice", "swap", "interrupt",
+ "softirq", "steal", "guest", "guest_nice", "idle", "active"};
#ifdef PROCESSOR_CPU_LOAD_INFO
static mach_port_t port_host;
/* #endif KERNEL_LINUX */
#elif defined(HAVE_LIBKSTAT)
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
/* colleague tells me that Sun doesn't sell systems with more than 100 or so
* CPUs.. */
#define MAX_NUMCPU 256
static _Bool report_by_state = 1;
static _Bool report_percent = 0;
static _Bool report_num_cpu = 0;
+static _Bool report_guest = 0;
+static _Bool subtract_guest = 1;
-static const char *config_keys[] = {"ReportByCpu", "ReportByState",
- "ReportNumCpu", "ValuesPercentage"};
+static const char *config_keys[] = {"ReportByCpu", "ReportByState",
+ "ReportNumCpu", "ValuesPercentage",
+ "ReportGuestState", "SubtractGuestState"};
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
static int cpu_config(char const *key, char const *value) /* {{{ */
report_by_state = IS_TRUE(value) ? 1 : 0;
else if (strcasecmp(key, "ReportNumCpu") == 0)
report_num_cpu = IS_TRUE(value) ? 1 : 0;
+ else if (strcasecmp(key, "ReportGuestState") == 0)
+ report_guest = IS_TRUE(value) ? 1 : 0;
+ else if (strcasecmp(key, "SubtractGuestState") == 0)
+ subtract_guest = IS_TRUE(value) ? 1 : 0;
else
return -1;
status = sysctl(mib, STATIC_ARRAY_SIZE(mib), &numcpu, &numcpu_size, NULL, 0);
if (status == -1) {
- char errbuf[1024];
- WARNING("cpu plugin: sysctl: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("cpu plugin: sysctl: %s", STRERRNO);
return -1;
}
/* #endif CAN_USE_SYSCTL */
numcpu_size = sizeof(numcpu);
if (sysctlbyname("hw.ncpu", &numcpu, &numcpu_size, NULL, 0) < 0) {
- char errbuf[1024];
- WARNING("cpu plugin: sysctlbyname(hw.ncpu): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("cpu plugin: sysctlbyname(hw.ncpu): %s", STRERRNO);
return -1;
}
numcpu_size = sizeof(maxcpu);
if (sysctlbyname("kern.smp.maxcpus", &maxcpu, &numcpu_size, NULL, 0) < 0) {
- char errbuf[1024];
- WARNING("cpu plugin: sysctlbyname(kern.smp.maxcpus): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("cpu plugin: sysctlbyname(kern.smp.maxcpus): %s", STRERRNO);
return -1;
}
#else
perfstat_cpu_total_t cputotal = {0};
if (!perfstat_cpu_total(NULL, &cputotal, sizeof(cputotal), 1)) {
- char errbuf[1024];
- WARNING("cpu plugin: perfstat_cpu_total: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("cpu plugin: perfstat_cpu_total: %s", STRERRNO);
return;
}
static void cpu_commit(void) /* {{{ */
{
gauge_t global_rates[COLLECTD_CPU_STATE_MAX] = {
- NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */
+ NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN /* Batman! */
};
if (report_num_cpu)
for (size_t cpu_num = 0; cpu_num < global_cpu_num; cpu_num++) {
cpu_state_t *this_cpu_states = get_cpu_state(cpu_num, 0);
- gauge_t local_rates[COLLECTD_CPU_STATE_MAX] = {NAN, NAN, NAN, NAN, NAN,
- NAN, NAN, NAN, NAN, NAN};
+ gauge_t local_rates[COLLECTD_CPU_STATE_MAX] = {
+ NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN, NAN};
for (size_t state = 0; state < COLLECTD_CPU_STATE_MAX; state++)
if (this_cpu_states[state].has_value)
FILE *fh;
char buf[1024];
- char *fields[9];
+ char *fields[11];
int numfields;
if ((fh = fopen("/proc/stat", "r")) == NULL) {
- char errbuf[1024];
- ERROR("cpu plugin: fopen (/proc/stat) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cpu plugin: fopen (/proc/stat) failed: %s", STRERRNO);
return -1;
}
if ((buf[3] < '0') || (buf[3] > '9'))
continue;
- numfields = strsplit(buf, fields, 9);
+ numfields = strsplit(buf, fields, STATIC_ARRAY_SIZE(fields));
if (numfields < 5)
continue;
cpu = atoi(fields[0] + 3);
- cpu_stage(cpu, COLLECTD_CPU_STATE_USER, (derive_t)atoll(fields[1]), now);
- cpu_stage(cpu, COLLECTD_CPU_STATE_NICE, (derive_t)atoll(fields[2]), now);
+ /* Do not stage User and Nice immediately: we may need to alter them later:
+ */
+ long long user_value = atoll(fields[1]);
+ long long nice_value = atoll(fields[2]);
cpu_stage(cpu, COLLECTD_CPU_STATE_SYSTEM, (derive_t)atoll(fields[3]), now);
cpu_stage(cpu, COLLECTD_CPU_STATE_IDLE, (derive_t)atoll(fields[4]), now);
now);
cpu_stage(cpu, COLLECTD_CPU_STATE_SOFTIRQ, (derive_t)atoll(fields[7]),
now);
+ }
- if (numfields >= 9)
- cpu_stage(cpu, COLLECTD_CPU_STATE_STEAL, (derive_t)atoll(fields[8]),
- now);
+ if (numfields >= 9) { /* Steal (since Linux 2.6.11) */
+ cpu_stage(cpu, COLLECTD_CPU_STATE_STEAL, (derive_t)atoll(fields[8]), now);
+ }
+
+ if (numfields >= 10) { /* Guest (since Linux 2.6.24) */
+ if (report_guest) {
+ long long value = atoll(fields[9]);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_GUEST, (derive_t)value, now);
+ /* Guest is included in User; optionally subtract Guest from User: */
+ if (subtract_guest) {
+ user_value -= value;
+ if (user_value < 0)
+ user_value = 0;
+ }
+ }
}
+
+ if (numfields >= 11) { /* Guest_nice (since Linux 2.6.33) */
+ if (report_guest) {
+ long long value = atoll(fields[10]);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_GUEST_NICE, (derive_t)value, now);
+ /* Guest_nice is included in Nice; optionally subtract Guest_nice from
+ Nice: */
+ if (subtract_guest) {
+ nice_value -= value;
+ if (nice_value < 0)
+ nice_value = 0;
+ }
+ }
+ }
+
+ /* Eventually stage User and Nice: */
+ cpu_stage(cpu, COLLECTD_CPU_STATE_USER, (derive_t)user_value, now);
+ cpu_stage(cpu, COLLECTD_CPU_STATE_NICE, (derive_t)nice_value, now);
}
fclose(fh);
/* }}} #endif defined(KERNEL_LINUX) */
status = sysctl(mib, STATIC_ARRAY_SIZE(mib), cpuinfo[i], &cpuinfo_size,
NULL, 0);
if (status == -1) {
- char errbuf[1024];
- ERROR("cpu plugin: sysctl failed: %s.",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cpu plugin: sysctl failed: %s.", STRERRNO);
return -1;
}
}
status = sysctl(mib, STATIC_ARRAY_SIZE(mib), &cpuinfo_tmp, &cpuinfo_size,
NULL, 0);
if (status == -1) {
- char errbuf[1024];
- ERROR("cpu plugin: sysctl failed: %s.",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cpu plugin: sysctl failed: %s.", STRERRNO);
return -1;
}
cpuinfo_size = sizeof(cpuinfo);
if (sysctlbyname("kern.cp_times", &cpuinfo, &cpuinfo_size, NULL, 0) < 0) {
- char errbuf[1024];
- ERROR("cpu plugin: sysctlbyname failed: %s.",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cpu plugin: sysctlbyname failed: %s.", STRERRNO);
return -1;
}
cpuinfo_size = sizeof(cpuinfo);
if (sysctlbyname("kern.cp_time", &cpuinfo, &cpuinfo_size, NULL, 0) < 0) {
- char errbuf[1024];
- ERROR("cpu plugin: sysctlbyname failed: %s.",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cpu plugin: sysctlbyname failed: %s.", STRERRNO);
return -1;
}
numcpu = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
if (numcpu == -1) {
- char errbuf[1024];
- WARNING("cpu plugin: perfstat_cpu: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("cpu plugin: perfstat_cpu: %s", STRERRNO);
return -1;
}
id.name[0] = '\0';
if ((cpus = perfstat_cpu(&id, perfcpu, sizeof(perfstat_cpu_t), numcpu)) < 0) {
- char errbuf[1024];
- WARNING("cpu plugin: perfstat_cpu: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("cpu plugin: perfstat_cpu: %s", STRERRNO);
return -1;
}
/* Python object declarations. */
typedef struct {
+ // clang-format off
PyObject_HEAD /* No semicolon! */
- PyObject *parent; /* Config */
+ PyObject *parent; /* Config */
PyObject *key; /* String */
PyObject *values; /* Sequence */
PyObject *children; /* Sequence */
+ // clang-format on
} Config;
extern PyTypeObject ConfigType;
typedef struct {
+ // clang-format off
PyObject_HEAD /* No semicolon! */
- double time;
+ double time;
+ // clang-format on
char host[DATA_MAX_NAME_LEN];
char plugin[DATA_MAX_NAME_LEN];
char plugin_instance[DATA_MAX_NAME_LEN];
typedef struct {
PluginData data;
+ PyObject *meta; /* dict */
int severity;
char message[NOTIF_MAX_MSG_LEN];
} Notification;
}
status = snprintf(buffer + offset, buffer_len - offset, ",%lf", rates[i]);
} else if (ds->ds[i].type == DS_TYPE_COUNTER) {
- status = snprintf(buffer + offset, buffer_len - offset, ",%llu",
- vl->values[i].counter);
+ status = snprintf(buffer + offset, buffer_len - offset, ",%" PRIu64,
+ (uint64_t)vl->values[i].counter);
} else if (ds->ds[i].type == DS_TYPE_DERIVE) {
status = snprintf(buffer + offset, buffer_len - offset, ",%" PRIi64,
vl->values[i].derive);
csv = fopen(filename, "w");
if (csv == NULL) {
- char errbuf[1024];
- ERROR("csv plugin: fopen (%s) failed: %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("csv plugin: fopen (%s) failed: %s", filename, STRERRNO);
return -1;
}
if (csv_create_file(filename, ds))
return -1;
} else {
- char errbuf[1024];
- ERROR("stat(%s) failed: %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("stat(%s) failed: %s", filename, STRERRNO);
return -1;
}
} else if (!S_ISREG(statbuf.st_mode)) {
csv = fopen(filename, "a");
if (csv == NULL) {
- char errbuf[1024];
- ERROR("csv plugin: fopen (%s) failed: %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("csv plugin: fopen (%s) failed: %s", filename, STRERRNO);
return -1;
}
csv_fd = fileno(csv);
status = fcntl(csv_fd, F_SETLK, &fl);
if (status != 0) {
- char errbuf[1024];
- ERROR("csv plugin: flock (%s) failed: %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("csv plugin: flock (%s) failed: %s", filename, STRERRNO);
fclose(csv);
return -1;
}
typedef struct web_page_s web_page_t;
struct web_page_s /* {{{ */
{
+ char *plugin_name;
char *instance;
char *url;
curl_easy_cleanup(wp->curl);
wp->curl = NULL;
+ sfree(wp->plugin_name);
sfree(wp->instance);
sfree(wp->url);
ERROR("curl plugin: calloc failed.");
return -1;
}
+ page->plugin_name = NULL;
page->url = NULL;
page->user = NULL;
page->pass = NULL;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
- if (strcasecmp("URL", child->key) == 0)
+ if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &page->plugin_name);
+ else if (strcasecmp("URL", child->key) == 0)
status = cf_util_get_string(child, &page->url);
else if (strcasecmp("User", child->key) == 0)
status = cf_util_get_string(child, &page->user);
vl.values = &value;
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, wm->type, sizeof(vl.type));
if (wm->instance != NULL)
vl.values = &(value_t){.gauge = (gauge_t)code};
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, "response_code", sizeof(vl.type));
vl.values = &(value_t){.gauge = response_time};
vl.values_len = 1;
- sstrncpy(vl.plugin, "curl", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "curl",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, "response_time", sizeof(vl.type));
if (wp->response_time)
cc_submit_response_time(wp, CDTIME_T_TO_DOUBLE(cdtime() - start));
if (wp->stats != NULL)
- curl_stats_dispatch(wp->stats, wp->curl, hostname_g, "curl", wp->instance);
+ curl_stats_dispatch(wp->stats, wp->curl, NULL, "curl", wp->instance);
if (wp->response_code) {
long response_code = 0;
struct cj_s /* {{{ */
{
char *instance;
+ char *plugin_name;
char *host;
char *sock;
#define CJ_CB_ABORT 0
#define CJ_CB_CONTINUE 1
-static int cj_cb_boolean(void *ctx, int boolVal) {
- cj_advance_array(ctx);
- return CJ_CB_CONTINUE;
-}
-
static int cj_cb_null(void *ctx) {
cj_advance_array(ctx);
return CJ_CB_CONTINUE;
return cj_cb_number(ctx, (const char *)val, len);
} /* int cj_cb_string */
+static int cj_cb_boolean(void *ctx, int boolVal) {
+ if (boolVal)
+ return cj_cb_number(ctx, "1", 1);
+ else
+ return cj_cb_number(ctx, "0", 1);
+} /* int cj_cb_boolean */
+
static int cj_cb_end(void *ctx) {
cj_t *db = (cj_t *)ctx;
memset(&db->state[db->depth], 0, sizeof(db->state[db->depth]));
db->tree = NULL;
sfree(db->instance);
+ sfree(db->plugin_name);
sfree(db->host);
sfree(db->sock);
if (strcasecmp("Instance", child->key) == 0)
status = cf_util_get_string(child, &db->instance);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &db->plugin_name);
else if (strcasecmp("Host", child->key) == 0)
status = cf_util_get_string(child, &db->host);
else if (db->url && strcasecmp("User", child->key) == 0)
sstrncpy(vl.type_instance, key->instance, sizeof(vl.type_instance));
sstrncpy(vl.host, cj_host(db), sizeof(vl.host));
- sstrncpy(vl.plugin, "curl_json", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (db->plugin_name != NULL) ? db->plugin_name : "curl_json",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, db->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, key->type, sizeof(vl.type));
static int cj_sock_perform(cj_t *db) /* {{{ */
{
- char errbuf[1024];
struct sockaddr_un sa_unix = {
.sun_family = AF_UNIX,
};
return -1;
if (connect(fd, (struct sockaddr *)&sa_unix, sizeof(sa_unix)) < 0) {
ERROR("curl_json plugin: connect(%s) failed: %s",
- (db->sock != NULL) ? db->sock : "<null>",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ (db->sock != NULL) ? db->sock : "<null>", STRERRNO);
close(fd);
return -1;
}
red = read(fd, buffer, sizeof(buffer));
if (red < 0) {
ERROR("curl_json plugin: read(%s) failed: %s",
- (db->sock != NULL) ? db->sock : "<null>",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ (db->sock != NULL) ? db->sock : "<null>", STRERRNO);
close(fd);
return -1;
}
size_t values_len;
char *instance_prefix;
char *instance;
+ char *plugin_instance_from;
int is_table;
unsigned long magic;
};
struct cx_s /* {{{ */
{
char *instance;
+ char *plugin_name;
char *host;
char *url;
size_t buffer_size;
size_t buffer_fill;
- llist_t *list; /* list of xpath blocks */
+ llist_t *xpath_list; /* list of xpath blocks */
};
typedef struct cx_s cx_t; /* }}} */
static size_t cx_curl_callback(void *buf, /* {{{ */
size_t size, size_t nmemb, void *user_data) {
size_t len = size * nmemb;
- cx_t *db;
- db = user_data;
+ cx_t *db = user_data;
if (db == NULL) {
ERROR("curl_xml plugin: cx_curl_callback: "
"user_data pointer is NULL.");
return len;
if ((db->buffer_fill + len) >= db->buffer_size) {
- char *temp;
-
- temp = realloc(db->buffer, db->buffer_fill + len + 1);
+ char *temp = realloc(db->buffer, db->buffer_fill + len + 1);
if (temp == NULL) {
ERROR("curl_xml plugin: realloc failed.");
return 0;
sfree(xpath->path);
sfree(xpath->type);
sfree(xpath->instance_prefix);
+ sfree(xpath->plugin_instance_from);
sfree(xpath->instance);
sfree(xpath->values);
sfree(xpath);
} /* }}} void cx_xpath_free */
-static void cx_list_free(llist_t *list) /* {{{ */
+static void cx_xpath_list_free(llist_t *list) /* {{{ */
{
llentry_t *le;
le = llist_head(list);
while (le != NULL) {
- llentry_t *le_next;
+ llentry_t *le_next = le->next;
- le_next = le->next;
-
- sfree(le->key);
+ /* this also frees xpath->path used for le->key */
cx_xpath_free(le->value);
le = le_next;
}
llist_destroy(list);
-} /* }}} void cx_list_free */
+} /* }}} void cx_xpath_list_free */
static void cx_free(void *arg) /* {{{ */
{
curl_easy_cleanup(db->curl);
db->curl = NULL;
- if (db->list != NULL)
- cx_list_free(db->list);
+ if (db->xpath_list != NULL)
+ cx_xpath_list_free(db->xpath_list);
sfree(db->buffer);
sfree(db->instance);
+ sfree(db->plugin_name);
sfree(db->host);
sfree(db->url);
sfree(db);
} /* }}} void cx_free */
-static const char *cx_host(cx_t *db) /* {{{ */
+static const char *cx_host(const cx_t *db) /* {{{ */
{
if (db->host == NULL)
return hostname_g;
}
if (ds->ds_num != xpath->values_len) {
- WARNING("curl_xml plugin: DataSet `%s' requires %zu values, but config "
- "talks about %zu",
+ WARNING("curl_xml plugin: DataSet `%s' requires %" PRIsz
+ " values, but config talks about %" PRIsz,
xpath->type, ds->ds_num, xpath->values_len);
return -1;
}
return 0;
} /* }}} cx_check_type */
-static xmlXPathObjectPtr
-cx_evaluate_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */
- xmlChar *expr) {
- xmlXPathObjectPtr xpath_obj;
-
- /* XXX: When to free this? */
- xpath_obj = xmlXPathEvalExpression(BAD_CAST expr, xpath_ctx);
+static xmlXPathObjectPtr cx_evaluate_xpath(xmlXPathContextPtr xpath_ctx,
+ char *expr) /* {{{ */
+{
+ xmlXPathObjectPtr xpath_obj =
+ xmlXPathEvalExpression(BAD_CAST expr, xpath_ctx);
if (xpath_obj == NULL) {
WARNING("curl_xml plugin: "
"Error unable to evaluate xpath expression \"%s\". Skipping...",
return -1;
} /* }}} cx_if_not_text_node */
-static int cx_handle_single_value_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */
- cx_xpath_t *xpath, const data_set_t *ds,
- value_list_t *vl, int index) {
- xmlXPathObjectPtr values_node_obj;
- xmlNodeSetPtr values_node;
- int tmp_size;
- char *node_value;
-
- values_node_obj =
- cx_evaluate_xpath(xpath_ctx, BAD_CAST xpath->values[index].path);
+/*
+ * Returned value should be freed with xmlFree().
+ */
+static char *cx_get_text_node_value(xmlXPathContextPtr xpath_ctx, /* {{{ */
+ char *expr, const char *from_option) {
+ xmlXPathObjectPtr values_node_obj = cx_evaluate_xpath(xpath_ctx, expr);
if (values_node_obj == NULL)
- return -1; /* Error already logged. */
+ return NULL; /* Error already logged. */
- values_node = values_node_obj->nodesetval;
- tmp_size = (values_node) ? values_node->nodeNr : 0;
+ xmlNodeSetPtr values_node = values_node_obj->nodesetval;
+ size_t tmp_size = (values_node) ? values_node->nodeNr : 0;
if (tmp_size == 0) {
WARNING("curl_xml plugin: "
- "relative xpath expression \"%s\" doesn't match any of the nodes. "
- "Skipping...",
- xpath->values[index].path);
+ "relative xpath expression \"%s\" from '%s' doesn't match "
+ "any of the nodes.",
+ expr, from_option);
xmlXPathFreeObject(values_node_obj);
- return -1;
+ return NULL;
}
if (tmp_size > 1) {
WARNING("curl_xml plugin: "
- "relative xpath expression \"%s\" is expected to return "
- "only one node. Skipping...",
- xpath->values[index].path);
+ "relative xpath expression \"%s\" from '%s' is expected to return "
+ "only one text node. Skipping the node.",
+ expr, from_option);
xmlXPathFreeObject(values_node_obj);
- return -1;
+ return NULL;
}
/* ignoring the element if other than textnode/attribute*/
if (cx_if_not_text_node(values_node->nodeTab[0])) {
WARNING("curl_xml plugin: "
- "relative xpath expression \"%s\" is expected to return "
- "only text/attribute node which is not the case. Skipping...",
- xpath->values[index].path);
+ "relative xpath expression \"%s\" from '%s' is expected to return "
+ "only text/attribute node which is not the case. "
+ "Skipping the node.",
+ expr, from_option);
xmlXPathFreeObject(values_node_obj);
- return -1;
+ return NULL;
}
- node_value = (char *)xmlNodeGetContent(values_node->nodeTab[0]);
+ char *node_value = (char *)xmlNodeGetContent(values_node->nodeTab[0]);
+
+ /* free up object */
+ xmlXPathFreeObject(values_node_obj);
+
+ return node_value;
+} /* }}} char * cx_get_text_node_value */
+
+static int cx_handle_single_value_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */
+ cx_xpath_t *xpath, const data_set_t *ds,
+ value_list_t *vl, int index) {
+
+ char *node_value = cx_get_text_node_value(
+ xpath_ctx, xpath->values[index].path, "ValuesFrom");
+
+ if (node_value == NULL)
+ return -1;
+
switch (ds->ds[index].type) {
case DS_TYPE_COUNTER:
vl->values[index].counter =
/* endptr = */ NULL);
}
- /* free up object */
- xmlXPathFreeObject(values_node_obj);
- sfree(node_value);
+ xmlFree(node_value);
/* We have reached here which means that
* we have got something to work */
cx_xpath_t *xpath, const data_set_t *ds,
value_list_t *vl) {
value_t values[xpath->values_len];
- int status;
assert(xpath->values_len > 0);
assert(xpath->values_len == vl->values_len);
vl->values = values;
for (size_t i = 0; i < xpath->values_len; i++) {
- status = cx_handle_single_value_xpath(xpath_ctx, xpath, ds, vl, i);
- if (status != 0)
+ if (cx_handle_single_value_xpath(xpath_ctx, xpath, ds, vl, i) != 0)
return -1; /* An error has been printed. */
} /* for (i = 0; i < xpath->values_len; i++) */
} /* }}} int cx_handle_all_value_xpaths */
static int cx_handle_instance_xpath(xmlXPathContextPtr xpath_ctx, /* {{{ */
- cx_xpath_t *xpath, value_list_t *vl,
- _Bool is_table) {
- xmlXPathObjectPtr instance_node_obj = NULL;
- xmlNodeSetPtr instance_node = NULL;
-
- memset(vl->type_instance, 0, sizeof(vl->type_instance));
-
- /* If the base xpath returns more than one block, the result is assumed to be
- * a table. The `Instance' option is not optional in this case. Check for the
- * condition and inform the user. */
- if (is_table && (xpath->instance == NULL)) {
- WARNING("curl_xml plugin: "
- "Base-XPath %s is a table (more than one result was returned), "
- "but no instance-XPath has been defined.",
- xpath->path);
- return -1;
- }
+ cx_xpath_t *xpath, value_list_t *vl) {
- /* instance has to be an xpath expression */
+ /* Handle type instance */
if (xpath->instance != NULL) {
- int tmp_size;
-
- instance_node_obj = cx_evaluate_xpath(xpath_ctx, BAD_CAST xpath->instance);
- if (instance_node_obj == NULL)
- return -1; /* error is logged already */
-
- instance_node = instance_node_obj->nodesetval;
- tmp_size = (instance_node) ? instance_node->nodeNr : 0;
-
- if (tmp_size <= 0) {
- WARNING(
- "curl_xml plugin: "
- "relative xpath expression for 'InstanceFrom' \"%s\" doesn't match "
- "any of the nodes. Skipping the node.",
- xpath->instance);
- xmlXPathFreeObject(instance_node_obj);
+ char *node_value =
+ cx_get_text_node_value(xpath_ctx, xpath->instance, "InstanceFrom");
+ if (node_value == NULL)
return -1;
- }
- if (tmp_size > 1) {
- WARNING("curl_xml plugin: "
- "relative xpath expression for 'InstanceFrom' \"%s\" is expected "
- "to return only one text node. Skipping the node.",
- xpath->instance);
- xmlXPathFreeObject(instance_node_obj);
- return -1;
- }
-
- /* ignoring the element if other than textnode/attribute */
- if (cx_if_not_text_node(instance_node->nodeTab[0])) {
- WARNING("curl_xml plugin: "
- "relative xpath expression \"%s\" is expected to return only "
- "text node "
- "which is not the case. Skipping the node.",
- xpath->instance);
- xmlXPathFreeObject(instance_node_obj);
- return -1;
- }
- } /* if (xpath->instance != NULL) */
-
- if (xpath->instance_prefix != NULL) {
- if (instance_node != NULL) {
- char *node_value = (char *)xmlNodeGetContent(instance_node->nodeTab[0]);
+ if (xpath->instance_prefix != NULL)
snprintf(vl->type_instance, sizeof(vl->type_instance), "%s%s",
xpath->instance_prefix, node_value);
- sfree(node_value);
- } else
- sstrncpy(vl->type_instance, xpath->instance_prefix,
- sizeof(vl->type_instance));
- } else {
- /* If instance_prefix and instance_node are NULL, then
- * don't set the type_instance */
- if (instance_node != NULL) {
- char *node_value = (char *)xmlNodeGetContent(instance_node->nodeTab[0]);
+ else
sstrncpy(vl->type_instance, node_value, sizeof(vl->type_instance));
- sfree(node_value);
- }
- }
- /* Free `instance_node_obj' this late, because `instance_node' points to
- * somewhere inside this structure. */
- xmlXPathFreeObject(instance_node_obj);
+ xmlFree(node_value);
+ } else if (xpath->instance_prefix != NULL)
+ sstrncpy(vl->type_instance, xpath->instance_prefix,
+ sizeof(vl->type_instance));
+
+ /* Handle plugin instance */
+ if (xpath->plugin_instance_from != NULL) {
+ char *node_value = cx_get_text_node_value(
+ xpath_ctx, xpath->plugin_instance_from, "PluginInstanceFrom");
+
+ if (node_value == NULL)
+ return -1;
+
+ sstrncpy(vl->plugin_instance, node_value, sizeof(vl->plugin_instance));
+ xmlFree(node_value);
+ }
return 0;
} /* }}} int cx_handle_instance_xpath */
-static int cx_handle_base_xpath(char const *plugin_instance, /* {{{ */
- char const *host, xmlXPathContextPtr xpath_ctx,
- const data_set_t *ds, char *base_xpath,
- cx_xpath_t *xpath) {
- int total_nodes;
+static int cx_handle_xpath(const cx_t *db, /* {{{ */
+ xmlXPathContextPtr xpath_ctx, cx_xpath_t *xpath) {
- xmlXPathObjectPtr base_node_obj = NULL;
- xmlNodeSetPtr base_nodes = NULL;
-
- value_list_t vl = VALUE_LIST_INIT;
+ const data_set_t *ds = plugin_get_ds(xpath->type);
+ if (cx_check_type(ds, xpath) != 0)
+ return -1;
- base_node_obj = cx_evaluate_xpath(xpath_ctx, BAD_CAST base_xpath);
+ xmlXPathObjectPtr base_node_obj = cx_evaluate_xpath(xpath_ctx, xpath->path);
if (base_node_obj == NULL)
return -1; /* error is logged already */
- base_nodes = base_node_obj->nodesetval;
- total_nodes = (base_nodes) ? base_nodes->nodeNr : 0;
+ xmlNodeSetPtr base_nodes = base_node_obj->nodesetval;
+ int total_nodes = (base_nodes) ? base_nodes->nodeNr : 0;
if (total_nodes == 0) {
ERROR("curl_xml plugin: "
"xpath expression \"%s\" doesn't match any of the nodes. "
"Skipping the xpath block...",
- base_xpath);
+ xpath->path);
xmlXPathFreeObject(base_node_obj);
return -1;
}
/* If base_xpath returned multiple results, then */
- /* Instance in the xpath block is required */
- if (total_nodes > 1 && xpath->instance == NULL) {
+ /* InstanceFrom or PluginInstanceFrom in the xpath block is required */
+ if (total_nodes > 1 && xpath->instance == NULL &&
+ xpath->plugin_instance_from == NULL) {
ERROR("curl_xml plugin: "
- "InstanceFrom is must in xpath block since the base xpath expression "
- "\"%s\" "
+ "InstanceFrom or PluginInstanceFrom is must in xpath block "
+ "since the base xpath expression \"%s\" "
"returned multiple results. Skipping the xpath block...",
- base_xpath);
+ xpath->path);
+ xmlXPathFreeObject(base_node_obj);
return -1;
}
+ value_list_t vl = VALUE_LIST_INIT;
+
/* set the values for the value_list */
vl.values_len = ds->ds_num;
sstrncpy(vl.type, xpath->type, sizeof(vl.type));
- sstrncpy(vl.plugin, "curl_xml", sizeof(vl.plugin));
- sstrncpy(vl.host, host, sizeof(vl.host));
- if (plugin_instance != NULL)
- sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
+ sstrncpy(vl.plugin, (db->plugin_name != NULL) ? db->plugin_name : "curl_xml",
+ sizeof(vl.plugin));
+ sstrncpy(vl.host, cx_host(db), sizeof(vl.host));
for (int i = 0; i < total_nodes; i++) {
- int status;
-
xpath_ctx->node = base_nodes->nodeTab[i];
- status = cx_handle_instance_xpath(xpath_ctx, xpath, &vl,
- /* is_table = */ (total_nodes > 1));
- if (status != 0)
+ if (db->instance != NULL)
+ sstrncpy(vl.plugin_instance, db->instance, sizeof(vl.plugin_instance));
+
+ if (cx_handle_instance_xpath(xpath_ctx, xpath, &vl) != 0)
continue; /* An error has already been reported. */
- status = cx_handle_all_value_xpaths(xpath_ctx, xpath, ds, &vl);
- if (status != 0)
+ if (cx_handle_all_value_xpaths(xpath_ctx, xpath, ds, &vl) != 0)
continue; /* An error has been logged. */
} /* for (i = 0; i < total_nodes; i++) */
xmlXPathFreeObject(base_node_obj);
return 0;
-} /* }}} cx_handle_base_xpath */
+} /* }}} cx_handle_xpath */
-static int cx_handle_parsed_xml(xmlDocPtr doc, /* {{{ */
- xmlXPathContextPtr xpath_ctx, cx_t *db) {
- llentry_t *le;
- const data_set_t *ds;
- cx_xpath_t *xpath;
+static int cx_handle_parsed_xml(cx_t *db, xmlDocPtr doc, /* {{{ */
+ xmlXPathContextPtr xpath_ctx) {
int status = -1;
- le = llist_head(db->list);
+ llentry_t *le = llist_head(db->xpath_list);
while (le != NULL) {
- /* get the ds */
- xpath = (cx_xpath_t *)le->value;
- ds = plugin_get_ds(xpath->type);
+ cx_xpath_t *xpath = (cx_xpath_t *)le->value;
- if ((cx_check_type(ds, xpath) == 0) &&
- (cx_handle_base_xpath(db->instance, cx_host(db), xpath_ctx, ds, le->key,
- xpath) == 0))
+ if (cx_handle_xpath(db, xpath_ctx, xpath) == 0)
status = 0; /* we got atleast one success */
le = le->next;
return status;
} /* }}} cx_handle_parsed_xml */
-static int cx_parse_stats_xml(xmlChar *xml, cx_t *db) /* {{{ */
+static int cx_parse_xml(cx_t *db, char *xml) /* {{{ */
{
- int status;
- xmlDocPtr doc;
- xmlXPathContextPtr xpath_ctx;
-
/* Load the XML */
- doc = xmlParseDoc(xml);
+ xmlDocPtr doc = xmlParseDoc(BAD_CAST xml);
if (doc == NULL) {
ERROR("curl_xml plugin: Failed to parse the xml document - %s", xml);
return -1;
}
- xpath_ctx = xmlXPathNewContext(doc);
+ xmlXPathContextPtr xpath_ctx = xmlXPathNewContext(doc);
if (xpath_ctx == NULL) {
ERROR("curl_xml plugin: Failed to create the xml context");
xmlFreeDoc(doc);
for (size_t i = 0; i < db->namespaces_num; i++) {
cx_namespace_t const *ns = db->namespaces + i;
- status =
+ int status =
xmlXPathRegisterNs(xpath_ctx, BAD_CAST ns->prefix, BAD_CAST ns->url);
if (status != 0) {
ERROR("curl_xml plugin: "
}
}
- status = cx_handle_parsed_xml(doc, xpath_ctx, db);
+ int status = cx_handle_parsed_xml(db, doc, xpath_ctx);
/* Cleanup */
xmlXPathFreeContext(xpath_ctx);
xmlFreeDoc(doc);
return status;
-} /* }}} cx_parse_stats_xml */
+} /* }}} cx_parse_xml */
-static int cx_curl_perform(cx_t *db, CURL *curl) /* {{{ */
+static int cx_read(user_data_t *ud) /* {{{ */
{
- int status;
+ if ((ud == NULL) || (ud->data == NULL)) {
+ ERROR("curl_xml plugin: cx_read: Invalid user data.");
+ return -1;
+ }
+
long rc;
- char *ptr;
char *url;
+ cx_t *db = (cx_t *)ud->data;
db->buffer_fill = 0;
curl_easy_setopt(db->curl, CURLOPT_URL, db->url);
- status = curl_easy_perform(curl);
+ int status = curl_easy_perform(db->curl);
if (status != CURLE_OK) {
ERROR("curl_xml plugin: curl_easy_perform failed with status %i: %s (%s)",
status, db->curl_errbuf, db->url);
curl_stats_dispatch(db->stats, db->curl, cx_host(db), "curl_xml",
db->instance);
- curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &rc);
+ curl_easy_getinfo(db->curl, CURLINFO_EFFECTIVE_URL, &url);
+ curl_easy_getinfo(db->curl, CURLINFO_RESPONSE_CODE, &rc);
/* The response code is zero if a non-HTTP transport was used. */
if ((rc != 0) && (rc != 200)) {
return -1;
}
- ptr = db->buffer;
-
- status = cx_parse_stats_xml(BAD_CAST ptr, db);
+ status = cx_parse_xml(db, db->buffer);
db->buffer_fill = 0;
return status;
-} /* }}} int cx_curl_perform */
-
-static int cx_read(user_data_t *ud) /* {{{ */
-{
- cx_t *db;
-
- if ((ud == NULL) || (ud->data == NULL)) {
- ERROR("curl_xml plugin: cx_read: Invalid user data.");
- return -1;
- }
-
- db = (cx_t *)ud->data;
-
- return cx_curl_perform(db, db->curl);
} /* }}} int cx_read */
/* Configuration handling functions {{{ */
static int cx_config_add_xpath(cx_t *db, oconfig_item_t *ci) /* {{{ */
{
- cx_xpath_t *xpath;
- char *name;
- llentry_t *le;
- int status;
-
- xpath = calloc(1, sizeof(*xpath));
+ cx_xpath_t *xpath = calloc(1, sizeof(*xpath));
if (xpath == NULL) {
ERROR("curl_xml plugin: calloc failed.");
return -1;
}
- status = cf_util_get_string(ci, &xpath->path);
+ int status = cf_util_get_string(ci, &xpath->path);
if (status != 0) {
cx_xpath_free(xpath);
return status;
status = cf_util_get_string(child, &xpath->instance_prefix);
else if (strcasecmp("InstanceFrom", child->key) == 0)
status = cf_util_get_string(child, &xpath->instance);
+ else if (strcasecmp("PluginInstanceFrom", child->key) == 0)
+ status = cf_util_get_string(child, &xpath->plugin_instance_from);
else if (strcasecmp("ValuesFrom", child->key) == 0)
status = cx_config_add_values("ValuesFrom", xpath, child);
else {
return -1;
}
- if (db->list == NULL) {
- db->list = llist_create();
- if (db->list == NULL) {
- ERROR("curl_xml plugin: list creation failed.");
- cx_xpath_free(xpath);
- return -1;
- }
- }
-
- name = strdup(xpath->path);
- if (name == NULL) {
- ERROR("curl_xml plugin: strdup failed.");
+ if (xpath->values_len == 0) {
+ WARNING("curl_xml plugin: `ValuesFrom' missing in `xpath' block.");
cx_xpath_free(xpath);
return -1;
}
- le = llentry_create(name, xpath);
+ llentry_t *le = llentry_create(xpath->path, xpath);
if (le == NULL) {
ERROR("curl_xml plugin: llentry_create failed.");
cx_xpath_free(xpath);
- sfree(name);
return -1;
}
- llist_append(db->list, le);
+ llist_append(db->xpath_list, le);
return 0;
} /* }}} int cx_config_add_xpath */
static int cx_config_add_namespace(cx_t *db, /* {{{ */
oconfig_item_t *ci) {
- cx_namespace_t *ns;
if ((ci->values_num != 2) || (ci->values[0].type != OCONFIG_TYPE_STRING) ||
(ci->values[1].type != OCONFIG_TYPE_STRING)) {
return EINVAL;
}
- ns = realloc(db->namespaces,
- sizeof(*db->namespaces) * (db->namespaces_num + 1));
+ cx_namespace_t *ns = realloc(
+ db->namespaces, sizeof(*db->namespaces) * (db->namespaces_num + 1));
if (ns == NULL) {
ERROR("curl_xml plugin: realloc failed.");
return ENOMEM;
static int cx_config_add_url(oconfig_item_t *ci) /* {{{ */
{
- cx_t *db;
- int status = 0;
-
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
WARNING("curl_xml plugin: The `URL' block "
"needs exactly one string argument.");
return -1;
}
- db = calloc(1, sizeof(*db));
+ cx_t *db = calloc(1, sizeof(*db));
if (db == NULL) {
ERROR("curl_xml plugin: calloc failed.");
return -1;
}
- db->timeout = -1;
+ db->instance = strdup("default");
+ if (db->instance == NULL) {
+ ERROR("curl_xml plugin: strdup failed.");
+ sfree(db);
+ return -1;
+ }
- if (strcasecmp("URL", ci->key) == 0) {
- status = cf_util_get_string(ci, &db->url);
- if (status != 0) {
- sfree(db);
- return status;
- }
- } else {
- ERROR("curl_xml plugin: cx_config: "
- "Invalid key: %s",
- ci->key);
- cx_free(db);
+ db->xpath_list = llist_create();
+ if (db->xpath_list == NULL) {
+ ERROR("curl_xml plugin: list creation failed.");
+ sfree(db->instance);
+ sfree(db);
return -1;
}
+ db->timeout = -1;
+
+ int status = cf_util_get_string(ci, &db->url);
+ if (status != 0) {
+ llist_destroy(db->xpath_list);
+ sfree(db->instance);
+ sfree(db);
+ return status;
+ }
+
/* Fill the `cx_t' structure.. */
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
if (strcasecmp("Instance", child->key) == 0)
status = cf_util_get_string(child, &db->instance);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &db->plugin_name);
else if (strcasecmp("Host", child->key) == 0)
status = cf_util_get_string(child, &db->host);
else if (strcasecmp("User", child->key) == 0)
break;
}
- if (status == 0) {
- if (db->list == NULL) {
- WARNING("curl_xml plugin: No (valid) `Key' block "
- "within `URL' block `%s'.",
- db->url);
- status = -1;
- }
- if (status == 0)
- status = cx_init_curl(db);
+ if (status != 0) {
+ cx_free(db);
+ return status;
}
- /* If all went well, register this database for reading */
- if (status == 0) {
- char *cb_name;
-
- if (db->instance == NULL)
- db->instance = strdup("default");
-
- DEBUG("curl_xml plugin: Registering new read callback: %s", db->instance);
-
- cb_name = ssnprintf_alloc("curl_xml-%s-%s", db->instance, db->url);
+ if (llist_size(db->xpath_list) == 0) {
+ WARNING("curl_xml plugin: No `xpath' block within `URL' block `%s'.",
+ db->url);
+ cx_free(db);
+ return -1;
+ }
- plugin_register_complex_read(/* group = */ "curl_xml", cb_name, cx_read,
- /* interval = */ 0,
- &(user_data_t){
- .data = db, .free_func = cx_free,
- });
- sfree(cb_name);
- } else {
+ if (cx_init_curl(db) != 0) {
cx_free(db);
return -1;
}
+ /* If all went well, register this database for reading */
+ DEBUG("curl_xml plugin: Registering new read callback: %s", db->instance);
+
+ char *cb_name = ssnprintf_alloc("curl_xml-%s-%s", db->instance, db->url);
+
+ plugin_register_complex_read(/* group = */ "curl_xml", cb_name, cx_read,
+ /* interval = */ 0,
+ &(user_data_t){
+ .data = db, .free_func = cx_free,
+ });
+ sfree(cb_name);
return 0;
} /* }}} int cx_config_add_url */
static int cx_config(oconfig_item_t *ci) /* {{{ */
{
- int success;
- int errors;
- int status;
-
- success = 0;
- errors = 0;
+ int success = 0;
+ int errors = 0;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
if (strcasecmp("URL", child->key) == 0) {
- status = cx_config_add_url(child);
- if (status == 0)
+ if (cx_config_add_url(child) == 0)
success++;
else
errors++;
#include <statgrab.h>
#endif
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#ifndef COLLECTD_LOCALE
#define COLLECTD_LOCALE "C"
#endif
-/*
- * Global variables
- */
-char hostname_g[DATA_MAX_NAME_LEN];
-cdtime_t interval_g;
-int timeout_g;
-#if HAVE_LIBKSTAT
-kstat_ctl_t *kc;
-#endif /* HAVE_LIBKSTAT */
-
static int loop = 0;
static void *do_flush(void __attribute__((unused)) * arg) {
}
static int init_hostname(void) {
- const char *str;
-
- struct addrinfo *ai_list;
- int status;
-
- str = global_option_get("Hostname");
+ const char *str = global_option_get("Hostname");
if ((str != NULL) && (str[0] != 0)) {
- sstrncpy(hostname_g, str, sizeof(hostname_g));
+ hostname_set(str);
return 0;
}
- if (gethostname(hostname_g, sizeof(hostname_g)) != 0) {
+ long hostname_len = sysconf(_SC_HOST_NAME_MAX);
+ if (hostname_len == -1) {
+ hostname_len = NI_MAXHOST;
+ }
+ char hostname[hostname_len];
+
+ if (gethostname(hostname, hostname_len) != 0) {
fprintf(stderr, "`gethostname' failed and no "
"hostname was configured.\n");
return -1;
}
+ hostname_set(hostname);
+
str = global_option_get("FQDNLookup");
if (IS_FALSE(str))
return 0;
+ struct addrinfo *ai_list;
struct addrinfo ai_hints = {.ai_flags = AI_CANONNAME};
- status = getaddrinfo(hostname_g, NULL, &ai_hints, &ai_list);
+ int status = getaddrinfo(hostname, NULL, &ai_hints, &ai_list);
if (status != 0) {
ERROR("Looking up \"%s\" failed. You have set the "
"\"FQDNLookup\" option, but I cannot resolve "
"my hostname to a fully qualified domain "
"name. Please fix the network "
"configuration.",
- hostname_g);
+ hostname);
return -1;
}
if (ai_ptr->ai_canonname == NULL)
continue;
- sstrncpy(hostname_g, ai_ptr->ai_canonname, sizeof(hostname_g));
+ hostname_set(ai_ptr->ai_canonname);
break;
}
return 0;
} /* int init_global_variables */
-static int change_basedir(const char *orig_dir) {
+static int change_basedir(const char *orig_dir, _Bool create) {
char *dir;
size_t dirlen;
int status;
dir = strdup(orig_dir);
if (dir == NULL) {
- char errbuf[1024];
- ERROR("strdup failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("strdup failed: %s", STRERRNO);
return -1;
}
if (status == 0) {
free(dir);
return 0;
- } else if (errno != ENOENT) {
- char errbuf[1024];
- ERROR("change_basedir: chdir (%s): %s", dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ } else if (!create || (errno != ENOENT)) {
+ ERROR("change_basedir: chdir (%s): %s", dir, STRERRNO);
free(dir);
return -1;
}
status = mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO);
if (status != 0) {
- char errbuf[1024];
- ERROR("change_basedir: mkdir (%s): %s", dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("change_basedir: mkdir (%s): %s", dir, STRERRNO);
free(dir);
return -1;
}
status = chdir(dir);
if (status != 0) {
- char errbuf[1024];
- ERROR("change_basedir: chdir (%s): %s", dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("change_basedir: chdir (%s): %s", dir, STRERRNO);
free(dir);
return -1;
}
} /* static int change_basedir (char *dir) */
#if HAVE_LIBKSTAT
+extern kstat_ctl_t *kc;
static void update_kstat(void) {
if (kc == NULL) {
if ((kc = kstat_open()) == NULL)
#if COLLECT_DAEMON
" -f Don't fork to the background.\n"
#endif
+ " -B Don't create the BaseDir\n"
" -h Display help (this message)\n"
"\nBuiltin defaults:\n"
" Config file " CONFIGFILE "\n"
while ((loop == 0) && (nanosleep(&ts_wait, &ts_wait) != 0)) {
if (errno != EINTR) {
- char errbuf[1024];
- ERROR("nanosleep failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("nanosleep failed: %s", STRERRNO);
return -1;
}
}
const char *file = global_option_get("PIDFile");
if ((fh = fopen(file, "w")) == NULL) {
- char errbuf[1024];
- ERROR("fopen (%s): %s", file, sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("fopen (%s): %s", file, STRERRNO);
return 1;
}
return 0;
}
- NOTICE("Upstart detected, stopping now to signal readyness.");
+ NOTICE("Upstart detected, stopping now to signal readiness.");
raise(SIGSTOP);
unsetenv("UPSTART_JOB");
notifysocket);
return 0;
}
- NOTICE("Systemd detected, trying to signal readyness.");
+ NOTICE("Systemd detected, trying to signal readiness.");
unsetenv("NOTIFY_SOCKET");
fd = socket(AF_UNIX, SOCK_DGRAM, /* protocol = */ 0);
#endif
if (fd < 0) {
- char errbuf[1024];
- ERROR("creating UNIX socket failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("creating UNIX socket failed: %s", STRERRNO);
return 0;
}
if (sendto(fd, buffer, strlen(buffer), MSG_NOSIGNAL, (void *)&su,
(socklen_t)su_size) < 0) {
- char errbuf[1024];
- ERROR("sendto(\"%s\") failed: %s", notifysocket,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("sendto(\"%s\") failed: %s", notifysocket, STRERRNO);
close(fd);
return 0;
}
}
#endif /* KERNEL_LINUX */
-int main(int argc, char **argv) {
- const char *configfile = CONFIGFILE;
- int test_config = 0;
- int test_readall = 0;
- const char *basedir;
-#if COLLECT_DAEMON
- pid_t pid;
- int daemonize = 1;
-#endif
- int exit_status = 0;
+struct cmdline_config {
+ _Bool test_config;
+ _Bool test_readall;
+ _Bool create_basedir;
+ const char *configfile;
+ _Bool daemonize;
+};
+static void read_cmdline(int argc, char **argv, struct cmdline_config *config) {
/* read options */
while (1) {
int c;
-
c = getopt(argc, argv, "htTC:"
#if COLLECT_DAEMON
"fP:"
break;
switch (c) {
+ case 'B':
+ config->create_basedir = 0;
+ break;
case 'C':
- configfile = optarg;
+ config->configfile = optarg;
break;
case 't':
- test_config = 1;
+ config->test_config = 1;
break;
case 'T':
- test_readall = 1;
+ config->test_readall = 1;
global_option_set("ReadThreads", "-1", 1);
#if COLLECT_DAEMON
- daemonize = 0;
+ config->daemonize = 0;
#endif /* COLLECT_DAEMON */
break;
#if COLLECT_DAEMON
global_option_set("PIDFile", optarg, 1);
break;
case 'f':
- daemonize = 0;
+ config->daemonize = 0;
break;
#endif /* COLLECT_DAEMON */
case 'h':
exit_usage(1);
} /* switch (c) */
} /* while (1) */
+}
- if (optind < argc)
- exit_usage(1);
-
- plugin_init_ctx();
-
+static int configure_collectd(struct cmdline_config *config) {
+ const char *basedir;
/*
* Read options from the config file, the environment and the command
* line (in that order, with later options overwriting previous ones in
* general).
* Also, this will automatically load modules.
*/
- if (cf_read(configfile)) {
+ if (cf_read(config->configfile)) {
fprintf(stderr, "Error: Reading the config file failed!\n"
"Read the logs for details.\n");
return 1;
fprintf(stderr,
"Don't have a basedir to use. This should not happen. Ever.");
return 1;
- } else if (change_basedir(basedir)) {
+ } else if (change_basedir(basedir, config->create_basedir)) {
fprintf(stderr, "Error: Unable to change to directory `%s'.\n", basedir);
return 1;
}
/*
- * Set global variables or, if that failes, exit. We cannot run with
+ * Set global variables or, if that fails, exit. We cannot run with
* them being uninitialized. If nothing is configured, then defaults
* are being used. So this means that the user has actually done
* something wrong.
*/
if (init_global_variables() != 0)
- exit(EXIT_FAILURE);
+ return 1;
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+#if COLLECT_DAEMON
+ pid_t pid;
+#endif
+ int exit_status = 0;
- if (test_config)
+ struct cmdline_config config = {
+ .daemonize = 1, .create_basedir = 1, .configfile = CONFIGFILE,
+ };
+
+ read_cmdline(argc, argv, &config);
+
+ if (config.test_config)
return 0;
+ if (optind < argc)
+ exit_usage(1);
+
+ plugin_init_ctx();
+
+ if (configure_collectd(&config) != 0)
+ exit(EXIT_FAILURE);
+
#if COLLECT_DAEMON
/*
* fork off child
* Only daemonize if we're not being supervised
* by upstart or systemd (when using Linux).
*/
- if (daemonize
+ if (config.daemonize
#ifdef KERNEL_LINUX
&& notify_upstart() == 0 && notify_systemd() == 0
#endif
if ((pid = fork()) == -1) {
/* error */
- char errbuf[1024];
- fprintf(stderr, "fork: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ fprintf(stderr, "fork: %s", STRERRNO);
return 1;
} else if (pid != 0) {
/* parent */
status);
return 1;
}
- } /* if (daemonize) */
+ } /* if (config.daemonize) */
#endif /* COLLECT_DAEMON */
struct sigaction sig_pipe_action = {.sa_handler = SIG_IGN};
struct sigaction sig_int_action = {.sa_handler = sig_int_handler};
if (0 != sigaction(SIGINT, &sig_int_action, NULL)) {
- char errbuf[1024];
ERROR("Error: Failed to install a signal handler for signal INT: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
struct sigaction sig_term_action = {.sa_handler = sig_term_handler};
if (0 != sigaction(SIGTERM, &sig_term_action, NULL)) {
- char errbuf[1024];
ERROR("Error: Failed to install a signal handler for signal TERM: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
struct sigaction sig_usr1_action = {.sa_handler = sig_usr1_handler};
if (0 != sigaction(SIGUSR1, &sig_usr1_action, NULL)) {
- char errbuf[1024];
ERROR("Error: Failed to install a signal handler for signal USR1: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return 1;
}
exit_status = 1;
}
- if (test_readall) {
+ if (config.test_readall) {
if (plugin_read_all_once() != 0) {
ERROR("Error: one or more plugin read callbacks failed.");
exit_status = 1;
}
#if COLLECT_DAEMON
- if (daemonize)
+ if (config.daemonize)
pidfile_remove();
#endif /* COLLECT_DAEMON */
#include <sys/param.h>
#endif
-#if HAVE_KSTAT_H
-#include <kstat.h>
-#endif
-
#ifndef PACKAGE_NAME
#define PACKAGE_NAME "collectd"
#endif
#define GAUGE_FORMAT "%.15g"
#endif
-/* Type for time as used by "utils_time.h" */
-typedef uint64_t cdtime_t;
-
-extern char hostname_g[];
-extern cdtime_t interval_g;
-extern int timeout_g;
+#include "globals.h"
#endif /* COLLECTD_H */
#include <sys/capability.h>
#endif
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#ifdef HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
#endif
}
#endif
-ssize_t sread(int fd, void *buf, size_t count) {
+int sread(int fd, void *buf, size_t count) {
char *ptr;
size_t nleft;
ssize_t status;
return status;
if (status == 0) {
- DEBUG("Received EOF from fd %i. "
- "Closing fd and returning error.",
- fd);
- close(fd);
+ DEBUG("Received EOF from fd %i. ", fd);
return -1;
}
return 0;
}
-ssize_t swrite(int fd, const void *buf, size_t count) {
+int swrite(int fd, const void *buf, size_t count) {
const char *ptr;
size_t nleft;
ssize_t status;
if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
/* if recv returns zero (even though poll() said there is data to be
* read), that means the connection has been closed */
- return errno ? errno : -1;
+ errno = ECONNRESET;
+ return -1;
}
}
if (EEXIST == errno)
continue;
- char errbuf[1024];
- ERROR("check_create_dir: mkdir (%s): %s", dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("check_create_dir: mkdir (%s): %s", dir, STRERRNO);
return -1;
} else {
- char errbuf[1024];
- ERROR("check_create_dir: stat (%s): %s", dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("check_create_dir: stat (%s): %s", dir, STRERRNO);
return -1;
}
} else if (!S_ISDIR(statbuf.st_mode)) {
}
BUFFER_ADD(":" GAUGE_FORMAT, rates[i]);
} else if (ds->ds[i].type == DS_TYPE_COUNTER)
- BUFFER_ADD(":%llu", vl->values[i].counter);
+ BUFFER_ADD(":%" PRIu64, (uint64_t)vl->values[i].counter);
else if (ds->ds[i].type == DS_TYPE_DERIVE)
BUFFER_ADD(":%" PRIi64, vl->values[i].derive);
else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
failure = 0;
if ((dh = opendir(dir)) == NULL) {
- char errbuf[1024];
- ERROR("walk_directory: Cannot open '%s': %s", dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("walk_directory: Cannot open '%s': %s", dir, STRERRNO);
return -1;
}
void *smalloc(size_t size);
char *sstrerror(int errnum, char *buf, size_t buflen);
+#ifndef ERRBUF_SIZE
+#define ERRBUF_SIZE 256
+#endif
+
+#define STRERROR(e) sstrerror((e), (char[ERRBUF_SIZE]){0}, ERRBUF_SIZE)
+#define STRERRNO STRERROR(errno)
+
/*
* NAME
* sread
*
* DESCRIPTION
* Reads exactly `n' bytes or fails. Syntax and other behavior is analogous
- * to `read(2)'. If EOF is received the file descriptor is closed and an
- * error is returned.
+ * to `read(2)'.
*
* PARAMETERS
* `fd' File descriptor to write to.
* Zero upon success or non-zero if an error occurred. `errno' is set in this
* case.
*/
-ssize_t sread(int fd, void *buf, size_t count);
+int sread(int fd, void *buf, size_t count);
/*
* NAME
* Zero upon success or non-zero if an error occurred. `errno' is set in this
* case.
*/
-ssize_t swrite(int fd, const void *buf, size_t count);
+int swrite(int fd, const void *buf, size_t count);
/*
* NAME
int check_create_dir(const char *file_orig);
#ifdef HAVE_LIBKSTAT
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
int get_kstat(kstat_t **ksp_ptr, char *module, int instance, char *name);
long long get_kstat_value(kstat_t *ksp, char *name);
#endif
#include "common.h"
#include "testing.h"
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#if HAVE_LIBKSTAT
kstat_ctl_t *kc;
#endif /* HAVE_LIBKSTAT */
return 0;
}
- temp =
- realloc(dst->children, sizeof(oconfig_item_t) *
- (dst->children_num + src->children_num - 1));
+ temp = realloc(dst->children,
+ sizeof(oconfig_item_t) *
+ (dst->children_num + src->children_num - 1));
if (temp == NULL) {
ERROR("configfile: realloc failed.");
return -1;
if ((src == NULL) || (src->children_num == 0))
return 0;
- temp = realloc(dst->children, sizeof(oconfig_item_t) *
- (dst->children_num + src->children_num));
+ temp =
+ realloc(dst->children,
+ sizeof(oconfig_item_t) * (dst->children_num + src->children_num));
if (temp == NULL) {
ERROR("configfile: realloc failed.");
return -1;
dh = opendir(dir);
if (dh == NULL) {
- char errbuf[1024];
- ERROR("configfile: opendir failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("configfile: opendir failed: %s", STRERRNO);
return NULL;
}
status = stat(path_ptr, &statbuf);
if (status != 0) {
- char errbuf[1024];
- WARNING("configfile: stat (%s) failed: %s", path_ptr,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("configfile: stat (%s) failed: %s", path_ptr, STRERRNO);
continue;
}
status = stat(path, &statbuf);
if (status != 0) {
- char errbuf[1024];
- ERROR("configfile: stat (%s) failed: %s", path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("configfile: stat (%s) failed: %s", path, STRERRNO);
return NULL;
}
return NULL;
}
- return (cf_global_options[i].value != NULL) ? cf_global_options[i].value : cf_global_options[i].def;
+ return (cf_global_options[i].value != NULL) ? cf_global_options[i].value
+ : cf_global_options[i].def;
} /* char *global_option_get */
long global_option_get_long(const char *option, long default_value) {
}
return ret;
+
} /* int cf_read */
/* Assures the config option is a string, duplicates it and returns the copy in
--- /dev/null
+/**
+ * collectd - src/globals.c
+ * Copyright (C) 2017 Google LLC
+ *
+ * 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.
+ **/
+
+#include "common.h"
+#include "globals.h"
+
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
+/*
+ * Global variables
+ */
+char *hostname_g;
+cdtime_t interval_g;
+int timeout_g;
+#if HAVE_KSTAT_H
+kstat_ctl_t *kc;
+#endif
+
+void hostname_set(char const *hostname) {
+ char *h = strdup(hostname);
+ if (h == NULL)
+ return;
+
+ sfree(hostname_g);
+ hostname_g = h;
+}
--- /dev/null
+/**
+ * collectd - src/globals.h
+ * Copyright (C) 2017 Google LLC
+ *
+ * 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.
+ **/
+
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+#include <inttypes.h>
+
+#ifndef DATA_MAX_NAME_LEN
+#define DATA_MAX_NAME_LEN 128
+#endif
+
+#ifndef PRIsz
+#define PRIsz "zu"
+#endif /* PRIsz */
+
+/* Type for time as used by "utils_time.h" */
+typedef uint64_t cdtime_t;
+
+/* hostname_set updates hostname_g */
+void hostname_set(char const *hostname);
+
+extern char *hostname_g;
+extern cdtime_t interval_g;
+extern int pidfile_from_cli;
+extern int timeout_g;
+#endif /* GLOBALS_H */
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;
}
return 0;
} /* }}} int plugin_update_internal_statistics */
-static void destroy_callback(callback_func_t *cf) /* {{{ */
+static void free_userdata(user_data_t const *ud) /* {{{ */
{
- if (cf == NULL)
+ if (ud == NULL)
return;
- if ((cf->cf_udata.data != NULL) && (cf->cf_udata.free_func != NULL)) {
- cf->cf_udata.free_func(cf->cf_udata.data);
- cf->cf_udata.data = NULL;
- cf->cf_udata.free_func = NULL;
+ if ((ud->data != NULL) && (ud->free_func != NULL)) {
+ ud->free_func(ud->data);
}
+} /* }}} void free_userdata */
+
+static void destroy_callback(callback_func_t *cf) /* {{{ */
+{
+ if (cf == NULL)
+ return;
+ free_userdata(&cf->cf_udata);
sfree(cf);
} /* }}} void destroy_callback */
cf = calloc(1, sizeof(*cf));
if (cf == NULL) {
+ free_userdata(ud);
ERROR("plugin: create_register_callback: calloc failed.");
return -1;
}
return 0;
} /* }}} int plugin_unregister */
-/*
- * (Try to) load the shared object `file'. Won't complain if it isn't a shared
- * object, but it will bitch about a shared object not having a
- * ``module_register'' symbol..
- */
-static int plugin_load_file(const char *file, _Bool global) {
- void (*reg_handle)(void);
-
+/* plugin_load_file loads the shared object "file" and calls its
+ * "module_register" function. Returns zero on success, non-zero otherwise. */
+static int plugin_load_file(char const *file, _Bool global) {
int flags = RTLD_NOW;
if (global)
flags |= RTLD_GLOBAL;
void *dlh = dlopen(file, flags);
-
if (dlh == NULL) {
char errbuf[1024] = "";
snprintf(errbuf, sizeof(errbuf),
- "dlopen (\"%s\") failed: %s. "
- "The most common cause for this problem is "
- "missing dependencies. Use ldd(1) to check "
- "the dependencies of the plugin "
- "/ shared object.",
+ "dlopen(\"%s\") failed: %s. "
+ "The most common cause for this problem is missing dependencies. "
+ "Use ldd(1) to check the dependencies of the plugin / shared "
+ "object.",
file, dlerror());
- ERROR("%s", errbuf);
- /* Make sure this is printed to STDERR in any case, but also
- * make sure it's printed only once. */
- if (list_log != NULL)
- fprintf(stderr, "ERROR: %s\n", errbuf);
+ /* This error is printed to STDERR unconditionally. If list_log is NULL,
+ * plugin_log() will also print to STDERR. We avoid duplicate output by
+ * checking that the list of log handlers, list_log, is not NULL. */
+ fprintf(stderr, "ERROR: %s\n", errbuf);
+ if (list_log != NULL) {
+ ERROR("%s", errbuf);
+ }
- return 1;
+ return ENOENT;
}
- reg_handle = (void (*)(void))dlsym(dlh, "module_register");
+ void (*reg_handle)(void) = dlsym(dlh, "module_register");
if (reg_handle == NULL) {
- WARNING("Couldn't find symbol \"module_register\" in \"%s\": %s\n", file,
- dlerror());
+ ERROR("Couldn't find symbol \"module_register\" in \"%s\": %s\n", file,
+ dlerror());
dlclose(dlh);
- return -1;
+ return ENOENT;
}
(*reg_handle)();
-
return 0;
}
#if defined(HAVE_PTHREAD_SETNAME_NP)
int status = pthread_setname_np(tid, n);
if (status != 0) {
- char errbuf[1024];
- ERROR("set_thread_name(\"%s\"): %s", n,
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("set_thread_name(\"%s\"): %s", n, STRERROR(status));
}
#else /* if defined(HAVE_PTHREAD_SET_NAME_NP) */
pthread_set_name_np(tid, n);
/* attr = */ NULL, plugin_read_thread,
/* arg = */ NULL);
if (status != 0) {
- char errbuf[1024];
- ERROR("plugin: start_read_threads: pthread_create failed "
- "with status %i (%s).",
- status, sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("plugin: start_read_threads: pthread_create failed with status %i "
+ "(%s).",
+ status, STRERROR(status));
return;
}
char name[THREAD_NAME_MAX];
- snprintf(name, sizeof(name), "reader#%zu", read_threads_num);
+ snprintf(name, sizeof(name), "reader#%" PRIsz, read_threads_num);
set_thread_name(read_threads[read_threads_num], name);
read_threads_num++;
if (read_threads == NULL)
return;
- INFO("collectd: Stopping %zu read threads.", read_threads_num);
+ INFO("collectd: Stopping %" PRIsz " read threads.", read_threads_num);
pthread_mutex_lock(&read_lock);
read_loop = 0;
/* attr = */ NULL, plugin_write_thread,
/* arg = */ NULL);
if (status != 0) {
- char errbuf[1024];
- ERROR("plugin: start_write_threads: pthread_create failed "
- "with status %i (%s).",
- status, sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("plugin: start_write_threads: pthread_create failed with status %i "
+ "(%s).",
+ status, STRERROR(status));
return;
}
char name[THREAD_NAME_MAX];
- snprintf(name, sizeof(name), "writer#%zu", write_threads_num);
+ snprintf(name, sizeof(name), "writer#%" PRIsz, write_threads_num);
set_thread_name(write_threads[write_threads_num], name);
write_threads_num++;
if (write_threads == NULL)
return;
- INFO("collectd: Stopping %zu write threads.", write_threads_num);
+ INFO("collectd: Stopping %" PRIsz " write threads.", write_threads_num);
pthread_mutex_lock(&write_lock);
write_loop = 0;
pthread_mutex_unlock(&write_lock);
if (i > 0) {
- WARNING("plugin: %zu value list%s left after shutting down "
+ WARNING("plugin: %" PRIsz " value list%s left after shutting down "
"the write threads.",
i, (i == 1) ? " was" : "s were");
}
}
if ((dh = opendir(dir)) == NULL) {
- char errbuf[1024];
- ERROR("plugin_load: opendir (%s) failed: %s", dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("plugin_load: opendir (%s) failed: %s", dir, STRERRNO);
return -1;
}
}
if (lstat(filename, &statbuf) == -1) {
- char errbuf[1024];
- WARNING("plugin_load: stat (\"%s\") failed: %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("plugin_load: stat (\"%s\") failed: %s", filename, STRERRNO);
continue;
} else if (!S_ISREG(statbuf.st_mode)) {
/* don't follow symlinks */
if (le != NULL) {
pthread_mutex_unlock(&read_lock);
WARNING("The read function \"%s\" is already registered. "
- "Check for duplicate \"LoadPlugin\" lines "
- "in your configuration!",
+ "Check for duplicates in your configuration!",
rf->rf_name);
return EINVAL;
}
rf = calloc(1, sizeof(*rf));
if (rf == NULL) {
+ free_userdata(user_data);
ERROR("plugin_register_complex_read: calloc failed.");
return ENOMEM;
}
status = plugin_insert_read(rf);
if (status != 0) {
+ free_userdata(&rf->rf_udata);
sfree(rf->rf_name);
sfree(rf);
}
});
sfree(flush_name);
- if (status != 0) {
- sfree(cb->name);
- sfree(cb);
- return status;
- }
+ return status;
}
return 0;
} /* int plugin_register_missing */
int plugin_register_shutdown(const char *name, int (*callback)(void)) {
- return create_register_callback(&list_shutdown, name, (void *)callback,
- NULL);
+ return create_register_callback(&list_shutdown, name, (void *)callback, NULL);
} /* int plugin_register_shutdown */
static void plugin_free_data_sets(void) {
int plugin_dispatch_missing(const value_list_t *vl) /* {{{ */
{
- llentry_t *le;
-
if (list_missing == NULL)
return 0;
- le = llist_head(list_missing);
+ llentry_t *le = llist_head(list_missing);
while (le != NULL) {
- callback_func_t *cf;
- plugin_missing_cb callback;
- plugin_ctx_t old_ctx;
- int status;
-
- cf = le->value;
- old_ctx = plugin_set_ctx(cf->cf_ctx);
- callback = cf->cf_callback;
+ callback_func_t *cf = le->value;
+ plugin_ctx_t old_ctx = plugin_set_ctx(cf->cf_ctx);
+ plugin_missing_cb callback = cf->cf_callback;
- status = (*callback)(vl, &cf->cf_udata);
+ int status = (*callback)(vl, &cf->cf_udata);
plugin_set_ctx(old_ctx);
if (status != 0) {
if (status < 0) {
int status;
static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
- data_set_t *ds;
-
_Bool free_meta_data = 0;
assert(vl != NULL);
return -1;
}
+ data_set_t *ds = NULL;
if (c_avl_get(data_sets, vl->type, (void *)&ds) != 0) {
char ident[6 * DATA_MAX_NAME_LEN];
#else
if (ds->ds_num != vl->values_len) {
ERROR("plugin_dispatch_values: ds->type = %s: "
- "(ds->ds_num = %zu) != "
- "(vl->values_len = %zu)",
+ "(ds->ds_num = %" PRIsz ") != "
+ "(vl->values_len = %" PRIsz ")",
ds->type, ds->ds_num, vl->values_len);
return -1;
}
status = plugin_write_enqueue(vl);
if (status != 0) {
- char errbuf[1024];
- ERROR("plugin_dispatch_values: plugin_write_enqueue failed "
- "with status %i (%s).",
- status, sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("plugin_dispatch_values: plugin_write_enqueue failed with status %i "
+ "(%s).",
+ status, STRERROR(status));
return status;
}
ctx = malloc(sizeof(*ctx));
if (ctx == NULL) {
- char errbuf[1024];
- ERROR("Failed to allocate plugin context: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("Failed to allocate plugin context: %s", STRERRNO);
return NULL;
}
#include <pthread.h>
-#ifndef DATA_MAX_NAME_LEN
-#define DATA_MAX_NAME_LEN 128
-#endif
-
#define DS_TYPE_COUNTER 0
#define DS_TYPE_GAUGE 1
#define DS_TYPE_DERIVE 2
#define DS_TYPE_ABSOLUTE 3
#define DS_TYPE_TO_STRING(t) \
- (t == DS_TYPE_COUNTER) ? "counter" : (t == DS_TYPE_GAUGE) \
- ? "gauge" \
- : (t == DS_TYPE_DERIVE) \
- ? "derive" \
- : (t == DS_TYPE_ABSOLUTE) \
- ? "absolute" \
- : "unknown"
+ (t == DS_TYPE_COUNTER) \
+ ? "counter" \
+ : (t == DS_TYPE_GAUGE) \
+ ? "gauge" \
+ : (t == DS_TYPE_DERIVE) \
+ ? "derive" \
+ : (t == DS_TYPE_ABSOLUTE) ? "absolute" : "unknown"
#ifndef LOG_ERR
#define LOG_ERR 3
#include "plugin.h"
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#if HAVE_LIBKSTAT
kstat_ctl_t *kc = NULL;
#endif /* HAVE_LIBKSTAT */
-char hostname_g[] = "example.com";
+char *hostname_g = "example.com";
void plugin_set_dir(const char *dir) { /* nop */
}
int fields_num;
if (buf_len < 11) {
- ERROR("parse_ds: (buf_len = %zu) < 11", buf_len);
+ ERROR("parse_ds: (buf_len = %" PRIsz ") < 11", buf_len);
return -1;
}
for (size_t i = 0; i < ds->ds_num; i++)
if (parse_ds(ds->ds + i, fields[i + 1], strlen(fields[i + 1])) != 0) {
- ERROR("types_list: parse_line: Cannot parse data source #%zu "
- "of data set %s",
+ ERROR("types_list: parse_line: Cannot parse data source #%" PRIsz
+ " of data set %s",
i, ds->type);
sfree(ds->ds);
sfree(ds);
fh = fopen(file, "r");
if (fh == NULL) {
- char errbuf[1024];
fprintf(stderr, "Failed to open types database `%s': %s.\n", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
- ERROR("Failed to open types database `%s': %s", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
+ ERROR("Failed to open types database `%s': %s", file, STRERRNO);
return -1;
}
ce = cache_alloc(ds->ds_num);
if (ce == NULL) {
sfree(key_copy);
- ERROR("uc_insert: cache_alloc (%zu) failed.", ds->ds_num);
+ ERROR("uc_insert: cache_alloc (%" PRIsz ") failed.", ds->ds_num);
return -1;
}
return -1;
} /* switch (ds->ds[i].type) */
- DEBUG("uc_update: %s: ds[%zu] = %lf", name, i, ce->values_gauge[i]);
+ DEBUG("uc_update: %s: ds[%" PRIsz "] = %lf", name, i, ce->values_gauge[i]);
} /* for (i) */
/* Update the history if it exists. */
/* This is important - the caller has no other way of knowing how many
* values are returned. */
if (ret_num != ds->ds_num) {
- ERROR("utils_cache: uc_get_rate: ds[%s] has %zu values, "
- "but uc_get_rate_by_name returned %zu.",
+ ERROR("utils_cache: uc_get_rate: ds[%s] has %" PRIsz " values, "
+ "but uc_get_rate_by_name returned %" PRIsz ".",
ds->type, ds->ds_num, ret_num);
sfree(ret);
return NULL;
pthread_mutex_lock(&cache_lock);
- if (c_avl_get(cache_tree, name, (void *) &ce) == 0) {
+ if (c_avl_get(cache_tree, name, (void *)&ce) == 0) {
assert(ce != NULL);
/* remove missing values from getval */
memcpy(ret, ce->values_raw, ret_num * sizeof(value_t));
}
}
- }
- else {
+ } else {
DEBUG("utils_cache: uc_get_value_by_name: No such value: %s", name);
status = -1;
}
/* This is important - the caller has no other way of knowing how many
* values are returned. */
- if (ret_num != (size_t) ds->ds_num) {
- ERROR("utils_cache: uc_get_value: ds[%s] has %zu values, "
- "but uc_get_value_by_name returned %zu.", ds->type, ds->ds_num,
- ret_num);
+ if (ret_num != (size_t)ds->ds_num) {
+ ERROR("utils_cache: uc_get_value: ds[%s] has %" PRIsz " values, "
+ "but uc_get_value_by_name returned %" PRIsz ".",
+ ds->type, ds->ds_num, ret_num);
sfree(ret);
return (NULL);
}
return 0;
} /* int uc_iterator_get_name */
+int uc_iterator_get_meta(uc_iter_t *iter, meta_data_t **ret_meta) {
+ if ((iter == NULL) || (iter->entry == NULL) || (ret_meta == NULL))
+ return -1;
+
+ *ret_meta = meta_data_clone(iter->entry->meta);
+
+ return 0;
+} /* int uc_iterator_get_meta */
+
/*
* Meta data interface
*/
size_t *ret_num);
/* Return the interval of the value at the current position. */
int uc_iterator_get_interval(uc_iter_t *iter, cdtime_t *ret_interval);
+/* Return the metadata for the value at the current position. */
+int uc_iterator_get_meta(uc_iter_t *iter, meta_data_t **ret_meta);
/*
* Meta data interface
}
if (i >= buflen) {
- WARNING("subst_string: Loop exited after %zu iterations: "
+ WARNING("subst_string: Loop exited after %" PRIsz " iterations: "
"string = %s; needle = %s; replacement = %s;",
i, string, needle, replacement);
}
* Florian octo Forster <octo at collectd.org>
*/
-#include "common.h" /* for STATIC_ARRAY_SIZE */
#include "collectd.h"
+#include "common.h" /* for STATIC_ARRAY_SIZE */
#include "testing.h"
#include "utils_subst.h"
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#if HAVE_LIBKSTAT
kstat_ctl_t *kc;
#endif /* HAVE_LIBKSTAT */
status = clock_gettime(CLOCK_REALTIME, &ts);
if (status != 0) {
- char errbuf[1024];
- ERROR("cdtime: clock_gettime failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cdtime: clock_gettime failed: %s", STRERRNO);
return 0;
}
status = gettimeofday(&tv, /* struct timezone = */ NULL);
if (status != 0) {
- char errbuf[1024];
- ERROR("cdtime: gettimeofday failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cdtime: gettimeofday failed: %s", STRERRNO);
return 0;
}
NORMALIZE_TIMESPEC(t_spec);
if (gmtime_r(&t_spec.tv_sec, t_tm) == NULL) {
- char errbuf[1024];
int status = errno;
- ERROR("get_utc_time: gmtime_r failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("get_utc_time: gmtime_r failed: %s", STRERRNO);
return status;
}
NORMALIZE_TIMESPEC(t_spec);
if (localtime_r(&t_spec.tv_sec, t_tm) == NULL) {
- char errbuf[1024];
int status = errno;
- ERROR("get_local_time: localtime_r failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("get_local_time: localtime_r failed: %s", STRERRNO);
return status;
}
{
char *name;
char *select_db;
+ char *plugin_name;
cdtime_t interval;
return;
sfree(db->name);
+ sfree(db->select_db);
+ sfree(db->plugin_name);
sfree(db->driver);
+ sfree(db->host);
for (size_t i = 0; i < db->driver_options_num; i++) {
sfree(db->driver_options[i].key);
if (db->q_prep_areas)
for (size_t i = 0; i < db->queries_num; ++i)
udb_query_delete_preparation_area(db->q_prep_areas[i]);
- free(db->q_prep_areas);
+ sfree(db->q_prep_areas);
+ /* N.B.: db->queries references objects "owned" by the global queries
+ * variable. Free the array here, but not the content. */
+ sfree(db->queries);
sfree(db);
} /* }}} void cdbi_database_free */
status = cf_util_get_string(child, &db->host);
else if (strcasecmp("Interval", child->key) == 0)
status = cf_util_get_cdtime(child, &db->interval);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &db->plugin_name);
else {
WARNING("dbi plugin: Option `%s' not allowed here.", child->key);
status = -1;
}
column_num = (size_t)db_status;
- DEBUG("cdbi_read_database_query (%s, %s): There are %zu columns.", db->name,
- udb_query_get_name(q), column_num);
+ DEBUG("cdbi_read_database_query (%s, %s): There are %" PRIsz " columns.",
+ db->name, udb_query_get_name(q), column_num);
}
/* Allocate `column_names' and `column_values'. {{{ */
column_name = dbi_result_get_field_name(res, (unsigned int)(i + 1));
if (column_name == NULL) {
ERROR("dbi plugin: cdbi_read_database_query (%s, %s): "
- "Cannot retrieve name of field %zu.",
+ "Cannot retrieve name of field %" PRIsz ".",
db->name, udb_query_get_name(q), i + 1);
BAIL_OUT(-1);
}
udb_query_prepare_result(
q, prep_area, (db->host ? db->host : hostname_g),
- /* plugin = */ "dbi", db->name, column_names, column_num,
+ /* plugin = */ (db->plugin_name != NULL) ? db->plugin_name : "dbi",
+ db->name, column_names, column_num,
/* interval = */ (db->interval > 0) ? db->interval : 0);
/* 0 = error; 1 = success; */
if (status != 0) {
ERROR("dbi plugin: cdbi_read_database_query (%s, %s): "
- "cdbi_result_get_field (%zu) failed.",
+ "cdbi_result_get_field (%" PRIsz ") failed.",
db->name, udb_query_get_name(q), i + 1);
status = -1;
break;
#elif HAVE_STATFS
struct statfs statbuf;
#endif
+ int retval = 0;
/* struct STATANYFS statbuf; */
cu_mount_t *mnt_list;
continue;
if (STATANYFS(mnt_ptr->dir, &statbuf) < 0) {
- char errbuf[1024];
- ERROR(STATANYFS_STR "(%s) failed: %s", mnt_ptr->dir,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR(STATANYFS_STR "(%s) failed: %s", mnt_ptr->dir, STRERRNO);
continue;
}
(gauge_t)((float_t)(blk_reserved) / statbuf.f_blocks * 100));
df_submit_one(disk_name, "percent_bytes", "used",
(gauge_t)((float_t)(blk_used) / statbuf.f_blocks * 100));
- } else
- return -1;
+ } else {
+ retval = -1;
+ break;
+ }
}
/* inode handling */
df_submit_one(
disk_name, "percent_inodes", "used",
(gauge_t)((float_t)(inode_used) / statbuf.f_files * 100));
- } else
- return -1;
+ } else {
+ retval = -1;
+ break;
+ }
}
if (values_absolute) {
df_submit_one(disk_name, "df_inodes", "free", (gauge_t)inode_free);
cu_mount_freelist(mnt_list);
- return 0;
+ return retval;
} /* int df_read */
void module_register(void) {
/* #endif KERNEL_FREEBSD */
#elif HAVE_LIBKSTAT
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
#define MAX_NUMDISK 1024
extern kstat_ctl_t *kc;
static kstat_t *ksp[MAX_NUMDISK];
#error "No applicable input method."
#endif
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
#include <libudev.h>
static char *conf_udev_name_attr = NULL;
"on Mach / Mac OS X and will be ignored.");
#endif
} else if (strcasecmp("UdevNameAttr", key) == 0) {
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
if (conf_udev_name_attr != NULL) {
free(conf_udev_name_attr);
conf_udev_name_attr = NULL;
/* #endif HAVE_IOKIT_IOKITLIB_H */
#elif KERNEL_LINUX
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
if (conf_udev_name_attr != NULL) {
handle_udev = udev_new();
if (handle_udev == NULL) {
return -1;
}
}
-#endif /* HAVE_UDEV_H */
+#endif /* HAVE_LIBUDEV_H */
/* #endif KERNEL_LINUX */
#elif KERNEL_FREEBSD
static int disk_shutdown(void) {
#if KERNEL_LINUX
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
if (handle_udev != NULL)
udev_unref(handle_udev);
-#endif /* HAVE_UDEV_H */
+#endif /* HAVE_LIBUDEV_H */
#endif /* KERNEL_LINUX */
return 0;
} /* int disk_shutdown */
}
#endif
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
/**
* Attempt to provide an rename disk instance from an assigned udev attribute.
*
output_name = disk_name;
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
char *alt_name = NULL;
if (conf_udev_name_attr != NULL) {
alt_name =
#endif
if (ignorelist_match(ignorelist, output_name) != 0) {
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
/* release udev-based alternate name, if allocated */
sfree(alt_name);
#endif
submit_io_time(output_name, io_time, weighted_time);
} /* if (is_disk) */
-#if HAVE_UDEV_H
+#if HAVE_LIBUDEV_H
/* release udev-based alternate name, if allocated */
sfree(alt_name);
#endif
int rnumdisk;
if ((numdisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0)) < 0) {
- char errbuf[1024];
- WARNING("disk plugin: perfstat_disk: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("disk plugin: perfstat_disk: %s", STRERRNO);
return -1;
}
firstpath.name[0] = '\0';
if ((rnumdisk = perfstat_disk(&firstpath, stat_disk, sizeof(perfstat_disk_t),
numdisk)) < 0) {
- char errbuf[1024];
- WARNING("disk plugin: perfstat_disk : %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("disk plugin: perfstat_disk : %s", STRERRNO);
return -1;
}
#include "common.h"
#include "plugin.h"
-#include <poll.h>
#include "utils_dns.h"
+#include <poll.h>
#include <pcap.h>
status = plugin_thread_create(&listen_thread, NULL, dns_child_loop, (void *)0,
"dns listen");
if (status != 0) {
- char errbuf[1024];
- ERROR("dns plugin: pthread_create failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("dns plugin: pthread_create failed: %s", STRERRNO);
return -1;
}
shm_name);
}
- char errbuf[ERR_BUF_SIZE];
int fd = shm_open(shm_name, O_RDONLY, 0);
if (fd < 0) {
ERROR(DPDK_EVENTS_PLUGIN ": Failed to open %s as SHM:%s. Is DPDK KA "
"primary application running?",
- shm_name, sstrerror(errno, errbuf, sizeof(errbuf)));
+ shm_name, STRERRNO);
return errno;
}
ec->config.keep_alive.shm = (dpdk_keepalive_shm_t *)mmap(
0, sizeof(*(ec->config.keep_alive.shm)), PROT_READ, MAP_SHARED, fd, 0);
if (ec->config.keep_alive.shm == MAP_FAILED) {
- ERROR(DPDK_EVENTS_PLUGIN ": Failed to mmap KA SHM:%s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR(DPDK_EVENTS_PLUGIN ": Failed to mmap KA SHM:%s", STRERRNO);
close(fd);
return errno;
}
.plugin = DPDK_EVENTS_PLUGIN,
.type = "gauge",
.meta = NULL};
- sstrncpy(vl.host, hostname_g, sizeof(vl.host));
sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
plugin_dispatch_values(&vl);
int ret = dpdk_helper_init(g_shm_name, sizeof(dpdk_stats_ctx_t), &g_hc);
if (ret != 0) {
- char errbuf[ERR_BUF_SIZE];
ERROR("%s: failed to initialize %s helper(error: %s)", DPDK_STATS_PLUGIN,
- g_shm_name, sstrerror(errno, errbuf, sizeof(errbuf)));
+ g_shm_name, STRERRNO);
return ret;
}
vl.values = &(value_t){.derive = value};
vl.values_len = 1;
vl.time = port_read_time;
- sstrncpy(vl.host, hostname_g, sizeof(vl.host));
sstrncpy(vl.plugin, DPDK_STATS_PLUGIN, sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
dpdk_stats_resolve_cnt_type(vl.type, sizeof(vl.type), cnt_name);
size_t data_size = sizeof(dpdk_stats_ctx_t) +
(ctx->stats_count * DPDK_STATS_CTX_GET_XSTAT_SIZE);
- DEBUG("%s:%d helper reinit (new_size=%zu)", __FUNCTION__, __LINE__,
+ DEBUG("%s:%d helper reinit (new_size=%" PRIsz ")", __FUNCTION__, __LINE__,
data_size);
dpdk_stats_ctx_t tmp_ctx;
int ret;
ret = dpdk_helper_init(g_shm_name, data_size, &g_hc);
if (ret != 0) {
- char errbuf[ERR_BUF_SIZE];
ERROR("%s: failed to initialize %s helper(error: %s)", DPDK_STATS_PLUGIN,
- g_shm_name, sstrerror(errno, errbuf, sizeof(errbuf)));
+ g_shm_name, STRERRNO);
return ret;
}
if (fields_num != drbd_names_num) {
WARNING("drbd plugin: Wrong number of fields for "
- "r%ld statistics. Expected %zu, got %zu.",
+ "r%ld statistics. Expected %" PRIsz ", got %" PRIsz ".",
resource, drbd_names_num, fields_num);
return EINVAL;
}
errno = 0;
if (fgets(line, sizeof(line), this->socket) == NULL) {
if (errno != 0) {
- char errbuf[1024];
log_err("collect: reading from socket (fd #%i) "
"failed: %s",
- fileno(this->socket),
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ fileno(this->socket), STRERRNO);
}
break;
}
len = strlen(line);
if ((line[len - 1] != '\n') && (line[len - 1] != '\r')) {
- log_warn("collect: line too long (> %zu characters): "
+ log_warn("collect: line too long (> %" PRIsz " characters): "
"'%s' (truncated)",
sizeof(line) - 1, line);
}
if (line[0] == 'e') { /* e:<type>:<bytes> */
- char *ptr = NULL;
- char *type = strtok_r(line + 2, ":", &ptr);
- char *tmp = strtok_r(NULL, ":", &ptr);
- int bytes = 0;
-
- if (tmp == NULL) {
+ char *type = line + 2;
+ char *bytes_str = strchr(type, ':');
+ if (bytes_str == NULL) {
log_err("collect: syntax error in line '%s'", line);
continue;
}
- bytes = atoi(tmp);
+ *bytes_str = 0;
+ bytes_str++;
pthread_mutex_lock(&count_mutex);
type_list_incr(&list_count, type, /* increment = */ 1);
pthread_mutex_unlock(&count_mutex);
+ int bytes = atoi(bytes_str);
if (bytes > 0) {
pthread_mutex_lock(&size_mutex);
type_list_incr(&list_size, type, /* increment = */ bytes);
/* create UNIX socket */
errno = 0;
if ((connector_socket = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
- char errbuf[1024];
disabled = 1;
- log_err("socket() failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("socket() failed: %s", STRERRNO);
pthread_exit((void *)1);
}
struct sockaddr_un addr = {
- .sun_family = AF_UNIX
+ .sun_family = AF_UNIX,
};
sstrncpy(addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
errno = 0;
if (bind(connector_socket, (struct sockaddr *)&addr,
- offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path)) == -1) {
- char errbuf[1024];
+ offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path)) ==
+ -1) {
disabled = 1;
close(connector_socket);
connector_socket = -1;
- log_err("bind() failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("bind() failed: %s", STRERRNO);
pthread_exit((void *)1);
}
errno = 0;
if (listen(connector_socket, 5) == -1) {
- char errbuf[1024];
disabled = 1;
close(connector_socket);
connector_socket = -1;
- log_err("listen() failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("listen() failed: %s", STRERRNO);
pthread_exit((void *)1);
}
{
struct group sg;
struct group *grp;
- char grbuf[4096];
int status;
+ long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (grbuf_size <= 0)
+ grbuf_size = sysconf(_SC_PAGESIZE);
+ if (grbuf_size <= 0)
+ grbuf_size = 4096;
+ char grbuf[grbuf_size];
+
grp = NULL;
status = getgrnam_r(group, &sg, grbuf, sizeof(grbuf), &grp);
if (status != 0) {
- char errbuf[1024];
- log_warn("getgrnam_r (%s) failed: %s", group,
- sstrerror(status, errbuf, sizeof(errbuf)));
+ log_warn("getgrnam_r (%s) failed: %s", group, STRERROR(status));
} else if (grp == NULL) {
log_warn("No such group: `%s'", group);
} else {
status = chown(path, (uid_t)-1, grp->gr_gid);
if (status != 0) {
- char errbuf[1024];
log_warn("chown (%s, -1, %i) failed: %s", path, (int)grp->gr_gid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
}
}
}
errno = 0;
if (chmod(path, sock_perms) != 0) {
- char errbuf[1024];
- log_warn("chmod() failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_warn("chmod() failed: %s", STRERRNO);
}
{ /* initialize collector threads */
if (plugin_thread_create(&collectors[i]->thread, &ptattr, collect,
collectors[i], "email collector") != 0) {
- char errbuf[1024];
- log_err("plugin_thread_create() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("plugin_thread_create() failed: %s", STRERRNO);
collectors[i]->thread = (pthread_t)0;
}
}
remote = accept(connector_socket, NULL, NULL);
if (remote == -1) {
- char errbuf[1024];
-
if (errno == EINTR)
continue;
disabled = 1;
close(connector_socket);
connector_socket = -1;
- log_err("accept() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("accept() failed: %s", STRERRNO);
pthread_exit((void *)1);
}
static int email_init(void) {
if (plugin_thread_create(&connector, NULL, open_connection, NULL,
"email listener") != 0) {
- char errbuf[1024];
disabled = 1;
- log_err("plugin_thread_create() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("plugin_thread_create() failed: %s", STRERRNO);
return -1;
}
fd = socket(AF_INET, SOCK_DGRAM, /* protocol = */ 0);
if (fd < 0) {
- char errbuf[1024];
- ERROR("ethstat plugin: Failed to open control socket: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ethstat plugin: Failed to open control socket: %s", STRERRNO);
return 1;
}
status = ioctl(fd, SIOCETHTOOL, &req);
if (status < 0) {
- char errbuf[1024];
close(fd);
ERROR("ethstat plugin: Failed to get driver information "
"from %s: %s",
- device, sstrerror(errno, errbuf, sizeof(errbuf)));
+ device, STRERRNO);
return -1;
}
req.ifr_data = (void *)strings;
status = ioctl(fd, SIOCETHTOOL, &req);
if (status < 0) {
- char errbuf[1024];
close(fd);
free(strings);
free(stats);
- ERROR("ethstat plugin: Cannot get strings from %s: %s", device,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ethstat plugin: Cannot get strings from %s: %s", device, STRERRNO);
return -1;
}
req.ifr_data = (void *)stats;
status = ioctl(fd, SIOCETHTOOL, &req);
if (status < 0) {
- char errbuf[1024];
close(fd);
free(strings);
free(stats);
ERROR("ethstat plugin: Reading statistics from %s failed: %s", device,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
int gid, int egid) /* {{{ */
{
int status;
- char errbuf[1024];
#if HAVE_SETGROUPS
if (getuid() == 0) {
status = setgid(gid);
if (status != 0) {
- ERROR("exec plugin: setgid (%i) failed: %s", gid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: setgid (%i) failed: %s", gid, STRERRNO);
exit(-1);
}
if (egid != -1) {
status = setegid(egid);
if (status != 0) {
- ERROR("exec plugin: setegid (%i) failed: %s", egid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: setegid (%i) failed: %s", egid, STRERRNO);
exit(-1);
}
}
status = setuid(uid);
if (status != 0) {
- ERROR("exec plugin: setuid (%i) failed: %s", uid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: setuid (%i) failed: %s", uid, STRERRNO);
exit(-1);
}
execvp(pl->exec, pl->argv);
- ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec, STRERRNO);
exit(-1);
} /* void exec_child }}} */
static int create_pipe(int fd_pipe[2]) /* {{{ */
{
- char errbuf[1024];
int status;
status = pipe(fd_pipe);
if (status != 0) {
- ERROR("exec plugin: pipe failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: pipe failed: %s", STRERRNO);
return -1;
}
int fd_pipe_in[2] = {-1, -1};
int fd_pipe_out[2] = {-1, -1};
int fd_pipe_err[2] = {-1, -1};
- char errbuf[1024];
int status;
int pid;
struct passwd *sp_ptr;
struct passwd sp;
- char nambuf[4096];
if (pl->pid != 0)
return -1;
+ long int nambuf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (nambuf_size <= 0)
+ nambuf_size = sysconf(_SC_PAGESIZE);
+ if (nambuf_size <= 0)
+ nambuf_size = 4096;
+ char nambuf[nambuf_size];
+
if ((create_pipe(fd_pipe_in) == -1) || (create_pipe(fd_pipe_out) == -1) ||
(create_pipe(fd_pipe_err) == -1))
goto failed;
status = getpwnam_r(pl->user, &sp, nambuf, sizeof(nambuf), &sp_ptr);
if (status != 0) {
ERROR("exec plugin: Failed to get user information for user ``%s'': %s",
- pl->user, sstrerror(status, errbuf, sizeof(errbuf)));
+ pl->user, STRERROR(status));
goto failed;
}
struct group *gr_ptr = NULL;
struct group gr;
- status = getgrnam_r(pl->group, &gr, nambuf, sizeof(nambuf), &gr_ptr);
+ long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (grbuf_size <= 0)
+ grbuf_size = sysconf(_SC_PAGESIZE);
+ if (grbuf_size <= 0)
+ grbuf_size = 4096;
+ char grbuf[grbuf_size];
+
+ status = getgrnam_r(pl->group, &gr, grbuf, sizeof(grbuf), &gr_ptr);
if (status != 0) {
ERROR("exec plugin: Failed to get group information "
"for group ``%s'': %s",
- pl->group, sstrerror(status, errbuf, sizeof(errbuf)));
+ pl->group, STRERROR(status));
goto failed;
}
if (gr_ptr == NULL) {
pid = fork();
if (pid < 0) {
- ERROR("exec plugin: fork failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: fork failed: %s", STRERRNO);
goto failed;
} else if (pid == 0) {
int fd_num;
fh = fdopen(fd, "w");
if (fh == NULL) {
- char errbuf[1024];
- ERROR("exec plugin: fdopen (%i) failed: %s", fd,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("exec plugin: fdopen (%i) failed: %s", fd, STRERRNO);
kill(pid, SIGTERM);
close(fd);
sfree(arg);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- plugin_thread_create(&t, &attr, exec_read_one, (void *)pl, "exec read");
+ int status =
+ plugin_thread_create(&t, &attr, exec_read_one, (void *)pl, "exec read");
+ if (status != 0) {
+ ERROR("exec plugin: plugin_thread_create failed.");
+ }
pthread_attr_destroy(&attr);
} /* for (pl) */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- plugin_thread_create(&t, &attr, exec_notification_one, (void *)pln,
- "exec notify");
+ int status = plugin_thread_create(&t, &attr, exec_notification_one,
+ (void *)pln, "exec notify");
+ if (status != 0) {
+ ERROR("exec plugin: plugin_thread_create failed.");
+ }
pthread_attr_destroy(&attr);
} /* for (pl) */
int prc_used, prc_unused;
char *fields[3];
char buffer[buffer_len];
- char errbuf[1024];
FILE *fp;
// Open file
fp = fopen("/proc/sys/fs/file-nr", "r");
if (fp == NULL) {
- ERROR("fhcount: fopen: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("fhcount: fopen: %s", STRERRNO);
return EXIT_FAILURE;
}
if (fgets(buffer, buffer_len, fp) == NULL) {
- ERROR("fhcount: fgets: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("fhcount: fgets: %s", STRERRNO);
fclose(fp);
return EXIT_FAILURE;
}
#define FC_RECURSIVE 1
#define FC_HIDDEN 2
+#define FC_REGULAR 4
struct fc_directory_conf_s {
char *path;
+ char *plugin_name;
char *instance;
+ char *files_size_type;
+ char *files_num_type;
+ char *type_instance;
int options;
static fc_directory_conf_t **directories = NULL;
static size_t directories_num = 0;
+static void fc_free_dir(fc_directory_conf_t *dir) {
+ sfree(dir->path);
+ sfree(dir->plugin_name);
+ sfree(dir->instance);
+ sfree(dir->files_size_type);
+ sfree(dir->files_num_type);
+ sfree(dir->type_instance);
+ sfree(dir->name);
+
+ sfree(dir);
+} /* void fc_free_dir */
+
static void fc_submit_dir(const fc_directory_conf_t *dir) {
value_list_t vl = VALUE_LIST_INIT;
- vl.values = &(value_t){.gauge = (gauge_t)dir->files_num};
- vl.values_len = 1;
- sstrncpy(vl.plugin, "filecount", sizeof(vl.plugin));
- sstrncpy(vl.plugin_instance, dir->instance, sizeof(vl.plugin_instance));
- sstrncpy(vl.type, "files", sizeof(vl.type));
+ sstrncpy(vl.plugin, dir->plugin_name, sizeof(vl.plugin));
+ if (dir->instance != NULL)
+ sstrncpy(vl.plugin_instance, dir->instance, sizeof(vl.plugin_instance));
+ if (dir->type_instance != NULL)
+ sstrncpy(vl.type_instance, dir->type_instance, sizeof(vl.type_instance));
- plugin_dispatch_values(&vl);
+ vl.values_len = 1;
- vl.values = &(value_t){.gauge = (gauge_t)dir->files_size};
- sstrncpy(vl.type, "bytes", sizeof(vl.type));
+ if (dir->files_num_type != NULL) {
+ vl.values = &(value_t){.gauge = (gauge_t)dir->files_num};
+ sstrncpy(vl.type, dir->files_num_type, sizeof(vl.type));
+ plugin_dispatch_values(&vl);
+ }
- plugin_dispatch_values(&vl);
+ if (dir->files_size_type != NULL) {
+ vl.values = &(value_t){.gauge = (gauge_t)dir->files_size};
+ sstrncpy(vl.type, dir->files_size_type, sizeof(vl.type));
+ plugin_dispatch_values(&vl);
+ }
} /* void fc_submit_dir */
/*
* Config:
* <Plugin filecount>
* <Directory /path/to/dir>
+ * Plugin "foo"
* Instance "foobar"
* Name "*.conf"
* MTime -3600
* Size "+10M"
+ * Recursive true
+ * IncludeHidden false
+ * FilesSizeType "bytes"
+ * FilesCountType "files"
+ * TypeInstance "instance"
* </Directory>
* </Plugin>
*
static int fc_config_set_instance(fc_directory_conf_t *dir, const char *str) {
char buffer[1024];
char *ptr;
- char *copy;
sstrncpy(buffer, str, sizeof(buffer));
for (ptr = buffer; *ptr != 0; ptr++)
for (ptr = buffer; *ptr == '_'; ptr++)
/* do nothing */;
- if (*ptr == 0)
- return -1;
-
- copy = strdup(ptr);
+ char *copy = strdup(ptr);
if (copy == NULL)
return -1;
static int fc_config_add_dir_name(fc_directory_conf_t *dir,
oconfig_item_t *ci) {
- char *temp;
-
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
WARNING("filecount plugin: The `Name' config option needs exactly one "
"string argument.");
return -1;
}
- temp = strdup(ci->values[0].value.string);
+ char *temp = strdup(ci->values[0].value.string);
if (temp == NULL) {
ERROR("filecount plugin: strdup failed.");
return -1;
static int fc_config_add_dir_mtime(fc_directory_conf_t *dir,
oconfig_item_t *ci) {
- char *endptr;
- double temp;
-
if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) &&
(ci->values[0].type != OCONFIG_TYPE_NUMBER))) {
WARNING("filecount plugin: The `MTime' config option needs exactly one "
}
errno = 0;
- endptr = NULL;
- temp = strtod(ci->values[0].value.string, &endptr);
+ char *endptr = NULL;
+ double temp = strtod(ci->values[0].value.string, &endptr);
if ((errno != 0) || (endptr == NULL) ||
(endptr == ci->values[0].value.string)) {
WARNING("filecount plugin: Converting `%s' to a number failed.",
static int fc_config_add_dir_size(fc_directory_conf_t *dir,
oconfig_item_t *ci) {
- char *endptr;
- double temp;
-
if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_STRING) &&
(ci->values[0].type != OCONFIG_TYPE_NUMBER))) {
WARNING("filecount plugin: The `Size' config option needs exactly one "
}
errno = 0;
- endptr = NULL;
- temp = strtod(ci->values[0].value.string, &endptr);
+ char *endptr = NULL;
+ double temp = strtod(ci->values[0].value.string, &endptr);
if ((errno != 0) || (endptr == NULL) ||
(endptr == ci->values[0].value.string)) {
WARNING("filecount plugin: Converting `%s' to a number failed.",
} /* int fc_config_add_dir_option */
static int fc_config_add_dir(oconfig_item_t *ci) {
- fc_directory_conf_t *dir;
- int status;
-
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
WARNING("filecount plugin: `Directory' needs exactly one string "
"argument.");
}
/* Initialize `dir' */
- dir = calloc(1, sizeof(*dir));
+ fc_directory_conf_t *dir = calloc(1, sizeof(*dir));
if (dir == NULL) {
ERROR("filecount plugin: calloc failed.");
return -1;
dir->path = strdup(ci->values[0].value.string);
if (dir->path == NULL) {
ERROR("filecount plugin: strdup failed.");
- sfree(dir);
+ fc_free_dir(dir);
return -1;
}
- fc_config_set_instance(dir, dir->path);
-
- dir->options = FC_RECURSIVE;
+ dir->options = FC_RECURSIVE | FC_REGULAR;
dir->name = NULL;
+ dir->plugin_name = strdup("filecount");
+ dir->instance = NULL;
+ dir->type_instance = NULL;
dir->mtime = 0;
dir->size = 0;
- status = 0;
+ dir->files_size_type = strdup("bytes");
+ dir->files_num_type = strdup("files");
+
+ if (dir->plugin_name == NULL || dir->files_size_type == NULL ||
+ dir->files_num_type == NULL) {
+ ERROR("filecount plugin: strdup failed.");
+ fc_free_dir(dir);
+ return -1;
+ }
+
+ int status = 0;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *option = ci->children + i;
- if (strcasecmp("Instance", option->key) == 0)
+ if (strcasecmp("Plugin", option->key) == 0)
+ status = cf_util_get_string(option, &dir->plugin_name);
+ else if (strcasecmp("Instance", option->key) == 0)
status = fc_config_add_dir_instance(dir, option);
else if (strcasecmp("Name", option->key) == 0)
status = fc_config_add_dir_name(dir, option);
status = fc_config_add_dir_option(dir, option, FC_RECURSIVE);
else if (strcasecmp("IncludeHidden", option->key) == 0)
status = fc_config_add_dir_option(dir, option, FC_HIDDEN);
+ else if (strcasecmp("RegularOnly", option->key) == 0)
+ status = fc_config_add_dir_option(dir, option, FC_REGULAR);
+ else if (strcasecmp("FilesSizeType", option->key) == 0)
+ status = cf_util_get_string(option, &dir->files_size_type);
+ else if (strcasecmp("FilesCountType", option->key) == 0)
+ status = cf_util_get_string(option, &dir->files_num_type);
+ else if (strcasecmp("TypeInstance", option->key) == 0)
+ status = cf_util_get_string(option, &dir->type_instance);
else {
WARNING("filecount plugin: fc_config_add_dir: "
"Option `%s' not allowed here.",
break;
} /* for (ci->children) */
- if (status == 0) {
- fc_directory_conf_t **temp;
+ if (status != 0) {
+ fc_free_dir(dir);
+ return -1;
+ }
- temp = realloc(directories, sizeof(*directories) * (directories_num + 1));
- if (temp == NULL) {
- ERROR("filecount plugin: realloc failed.");
- status = -1;
- } else {
- directories = temp;
- directories[directories_num] = dir;
- directories_num++;
+ /* Set default plugin instance */
+ if (dir->instance == NULL) {
+ fc_config_set_instance(dir, dir->path);
+ if (dir->instance == NULL || strlen(dir->instance) == 0) {
+ ERROR("filecount plugin: failed to build plugin instance name.");
+ fc_free_dir(dir);
+ return -1;
}
}
- if (status != 0) {
- sfree(dir->name);
+ /* Handle disabled types */
+ if (strlen(dir->instance) == 0)
sfree(dir->instance);
- sfree(dir->path);
- sfree(dir);
+
+ if (strlen(dir->files_size_type) == 0)
+ sfree(dir->files_size_type);
+
+ if (strlen(dir->files_num_type) == 0)
+ sfree(dir->files_num_type);
+
+ if (dir->files_size_type == NULL && dir->files_num_type == NULL) {
+ WARNING("filecount plugin: Both `FilesSizeType' and `FilesCountType ' "
+ "are disabled for '%s'. There's no types to report.",
+ dir->path);
+ fc_free_dir(dir);
return -1;
}
+ /* Ready to add it to list */
+ fc_directory_conf_t **temp =
+ realloc(directories, sizeof(*directories) * (directories_num + 1));
+ if (temp == NULL) {
+ ERROR("filecount plugin: realloc failed.");
+ fc_free_dir(dir);
+ return -1;
+ }
+
+ directories = temp;
+ directories[directories_num] = dir;
+ directories_num++;
+
return 0;
} /* int fc_config_add_dir */
fc_directory_conf_t *dir = user_data;
char abs_path[PATH_MAX];
struct stat statbuf;
- int status;
if (dir == NULL)
return -1;
snprintf(abs_path, sizeof(abs_path), "%s/%s", dirname, filename);
- status = lstat(abs_path, &statbuf);
+ int status = lstat(abs_path, &statbuf);
if (status != 0) {
ERROR("filecount plugin: stat (%s) failed.", abs_path);
return -1;
abs_path, fc_read_dir_callback, dir,
/* include hidden = */ (dir->options & FC_HIDDEN) ? 1 : 0);
return status;
- } else if (!S_ISREG(statbuf.st_mode)) {
+ } else if ((dir->options & FC_REGULAR) && !S_ISREG(statbuf.st_mode)) {
return 0;
}
return 0;
}
+ if (!S_ISREG(statbuf.st_mode)) {
+ dir->files_num++;
+ return 0;
+ }
+
if (dir->mtime != 0) {
time_t mtime = dir->now;
} /* int fc_read_dir_callback */
static int fc_read_dir(fc_directory_conf_t *dir) {
- int status;
-
dir->files_num = 0;
dir->files_size = 0;
if (dir->mtime != 0)
dir->now = time(NULL);
- status =
+ int status =
walk_directory(dir->path, fc_read_dir_callback, dir,
/* include hidden */ (dir->options & FC_HIDDEN) ? 1 : 0);
if (status != 0) {
ai_return = getaddrinfo(node, service, &ai_hints, &ai_list);
if (ai_return != 0) {
- char errbuf[1024];
ERROR("gmond plugin: getaddrinfo (%s, %s) failed: %s",
(node == NULL) ? "(null)" : node,
(service == NULL) ? "(null)" : service,
- (ai_return == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(ai_return));
+ (ai_return == EAI_SYSTEM) ? STRERRNO : gai_strerror(ai_return));
return -1;
}
sockets[sockets_num].fd =
socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (sockets[sockets_num].fd < 0) {
- char errbuf[1024];
- ERROR("gmond plugin: socket failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("gmond plugin: socket failed: %s", STRERRNO);
continue;
}
status = setsockopt(sockets[sockets_num].fd, SOL_SOCKET, SO_REUSEADDR,
(void *)&yes, sizeof(yes));
if (status != 0) {
- char errbuf[1024];
- WARNING("gmond plugin: setsockopt(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("gmond plugin: setsockopt(2) failed: %s", STRERRNO);
}
}
status = bind(sockets[sockets_num].fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0) {
- char errbuf[1024];
- ERROR("gmond plugin: bind failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("gmond plugin: bind failed: %s", STRERRNO);
close(sockets[sockets_num].fd);
continue;
}
status = setsockopt(sockets[sockets_num].fd, IPPROTO_IP,
IP_MULTICAST_LOOP, (void *)&loop, sizeof(loop));
if (status != 0) {
- char errbuf[1024];
- WARNING("gmond plugin: setsockopt(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("gmond plugin: setsockopt(2) failed: %s", STRERRNO);
}
struct ip_mreq mreq = {.imr_multiaddr.s_addr = addr->sin_addr.s_addr,
status = setsockopt(sockets[sockets_num].fd, IPPROTO_IP,
IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq));
if (status != 0) {
- char errbuf[1024];
- WARNING("gmond plugin: setsockopt(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("gmond plugin: setsockopt(2) failed: %s", STRERRNO);
}
} /* if (ai_ptr->ai_family == AF_INET) */
else if (ai_ptr->ai_family == AF_INET6) {
status = setsockopt(sockets[sockets_num].fd, IPPROTO_IPV6,
IPV6_MULTICAST_LOOP, (void *)&loop, sizeof(loop));
if (status != 0) {
- char errbuf[1024];
- WARNING("gmond plugin: setsockopt(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("gmond plugin: setsockopt(2) failed: %s", STRERRNO);
}
struct ipv6_mreq mreq = {
status = setsockopt(sockets[sockets_num].fd, IPPROTO_IPV6,
IPV6_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq));
if (status != 0) {
- char errbuf[1024];
- WARNING("gmond plugin: setsockopt(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("gmond plugin: setsockopt(2) failed: %s", STRERRNO);
}
} /* if (ai_ptr->ai_family == AF_INET6) */
/* flags = */ 0, (struct sockaddr *)&mc_send_sockets[i].addr,
mc_send_sockets[i].addrlen);
if (status == -1) {
- char errbuf[1024];
- ERROR("gmond plugin: sendto(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("gmond plugin: sendto(2) failed: %s", STRERRNO);
continue;
}
}
}
if (ds->ds_num <= ds_index) {
- ERROR("gmond plugin: Invalid index %zu: %s has only %zu data source(s).",
+ ERROR("gmond plugin: Invalid index %" PRIsz ": %s has only %" PRIsz
+ " data source(s).",
ds_index, ds->type, ds->ds_num);
return -1;
}
buffer_size = recv(p->fd, buffer, sizeof(buffer), /* flags = */ 0);
if (buffer_size <= 0) {
- char errbuf[1024];
- ERROR("gmond plugin: recv failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("gmond plugin: recv failed: %s", STRERRNO);
p->revents = 0;
return -1;
}
while (mc_receive_thread_loop != 0) {
status = poll(mc_receive_sockets, mc_receive_sockets_num, -1);
if (status <= 0) {
- char errbuf[1024];
if (errno == EINTR)
continue;
- ERROR("gmond plugin: poll failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("gmond plugin: poll failed: %s", STRERRNO);
break;
}
* Marc Fournier <marc.fournier at camptocamp.com>
**/
+#include "collectd.h"
#include "common.h"
#include "plugin.h"
#include "utils_time.h"
-#include "collectd.h"
#define CGPS_TRUE 1
#define CGPS_FALSE 0
int ret = !cgps_thread_shutdown;
- pthread_mutex_lock(&cgps_thread_lock);
+ pthread_mutex_unlock(&cgps_thread_lock);
return ret;
}
free(res);
// Clean mutex:
- pthread_mutex_unlock(&cgps_thread_lock);
pthread_mutex_destroy(&cgps_thread_lock);
pthread_mutex_unlock(&cgps_data_lock);
pthread_mutex_destroy(&cgps_data_lock);
using google::protobuf::util::TimeUtil;
+typedef google::protobuf::Map<grpc::string, collectd::types::MetadataValue>
+ grpcMetadata;
+
/*
* private types
*/
return grpc::Status::OK;
} /* unmarshal_ident() */
+static grpc::Status marshal_meta_data(meta_data_t *meta,
+ grpcMetadata *mutable_meta_data) {
+ char **meta_data_keys = nullptr;
+ int meta_data_keys_len = meta_data_toc(meta, &meta_data_keys);
+ if (meta_data_keys_len < 0) {
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("error getting metadata keys"));
+ }
+
+ for (int i = 0; i < meta_data_keys_len; i++) {
+ char *key = meta_data_keys[i];
+ int md_type = meta_data_type(meta, key);
+
+ collectd::types::MetadataValue md_value;
+ md_value.Clear();
+
+ switch (md_type) {
+ case MD_TYPE_STRING:
+ char *md_string;
+ if (meta_data_get_string(meta, key, &md_string) != 0 ||
+ md_string == nullptr) {
+ strarray_free(meta_data_keys, meta_data_keys_len);
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("missing metadata"));
+ }
+ md_value.set_string_value(md_string);
+ free(md_string);
+ break;
+ case MD_TYPE_SIGNED_INT:
+ int64_t int64_value;
+ if (meta_data_get_signed_int(meta, key, &int64_value) != 0) {
+ strarray_free(meta_data_keys, meta_data_keys_len);
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("missing metadata"));
+ }
+ md_value.set_int64_value(int64_value);
+ break;
+ case MD_TYPE_UNSIGNED_INT:
+ uint64_t uint64_value;
+ if (meta_data_get_unsigned_int(meta, key, &uint64_value) != 0) {
+ strarray_free(meta_data_keys, meta_data_keys_len);
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("missing metadata"));
+ }
+ md_value.set_uint64_value(uint64_value);
+ break;
+ case MD_TYPE_DOUBLE:
+ double double_value;
+ if (meta_data_get_double(meta, key, &double_value) != 0) {
+ strarray_free(meta_data_keys, meta_data_keys_len);
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("missing metadata"));
+ }
+ md_value.set_double_value(double_value);
+ break;
+ case MD_TYPE_BOOLEAN:
+ bool bool_value;
+ if (meta_data_get_boolean(meta, key, &bool_value) != 0) {
+ strarray_free(meta_data_keys, meta_data_keys_len);
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("missing metadata"));
+ }
+ md_value.set_bool_value(bool_value);
+ break;
+ default:
+ strarray_free(meta_data_keys, meta_data_keys_len);
+ ERROR("grpc: invalid metadata type (%d)", md_type);
+ return grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("unknown metadata type"));
+ }
+
+ (*mutable_meta_data)[grpc::string(key)] = md_value;
+
+ strarray_free(meta_data_keys, meta_data_keys_len);
+ }
+
+ return grpc::Status::OK;
+}
+
+static grpc::Status unmarshal_meta_data(const grpcMetadata &rpc_metadata,
+ meta_data_t **md_out) {
+ *md_out = meta_data_create();
+ if (*md_out == nullptr) {
+ return grpc::Status(grpc::StatusCode::RESOURCE_EXHAUSTED,
+ grpc::string("failed to create metadata list"));
+ }
+ for (auto kv : rpc_metadata) {
+ auto k = kv.first.c_str();
+ auto v = kv.second;
+
+ // The meta_data collection individually allocates copies of the keys and
+ // string values for each entry, so it's safe for us to pass a reference
+ // to our short-lived strings.
+
+ switch (v.value_case()) {
+ case collectd::types::MetadataValue::ValueCase::kStringValue:
+ meta_data_add_string(*md_out, k, v.string_value().c_str());
+ break;
+ case collectd::types::MetadataValue::ValueCase::kInt64Value:
+ meta_data_add_signed_int(*md_out, k, v.int64_value());
+ break;
+ case collectd::types::MetadataValue::ValueCase::kUint64Value:
+ meta_data_add_unsigned_int(*md_out, k, v.uint64_value());
+ break;
+ case collectd::types::MetadataValue::ValueCase::kDoubleValue:
+ meta_data_add_double(*md_out, k, v.double_value());
+ break;
+ case collectd::types::MetadataValue::ValueCase::kBoolValue:
+ meta_data_add_boolean(*md_out, k, v.bool_value());
+ break;
+ default:
+ meta_data_destroy(*md_out);
+ return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
+ grpc::string("Metadata of unknown type"));
+ }
+ }
+ return grpc::Status::OK;
+}
+
static grpc::Status marshal_value_list(const value_list_t *vl,
collectd::types::ValueList *msg) {
auto id = msg->mutable_identifier();
msg->set_allocated_time(new google::protobuf::Timestamp(t));
msg->set_allocated_interval(new google::protobuf::Duration(d));
+ msg->clear_meta_data();
+ if (vl->meta != nullptr) {
+ grpc::Status status = marshal_meta_data(vl->meta, msg->mutable_meta_data());
+ if (!status.ok()) {
+ return status;
+ }
+ }
+
for (size_t i = 0; i < vl->values_len; ++i) {
auto v = msg->add_values();
- switch (ds->ds[i].type) {
+ int value_type = ds->ds[i].type;
+ switch (value_type) {
case DS_TYPE_COUNTER:
v->set_counter(vl->values[i].counter);
break;
v->set_absolute(vl->values[i].absolute);
break;
default:
+ ERROR("grpc: invalid value type (%d)", value_type);
return grpc::Status(grpc::StatusCode::INTERNAL,
grpc::string("unknown value type"));
}
if (!status.ok())
return status;
+ status = unmarshal_meta_data(msg.meta_data(), &vl->meta);
+ if (!status.ok())
+ return status;
+
value_t *values = NULL;
size_t values_len = 0;
if (status.ok()) {
vl->values = values;
vl->values_len = values_len;
- } else if (values) {
+ } else {
+ meta_data_destroy(vl->meta);
free(values);
}
auto vl = value_lists.front();
value_lists.pop();
sfree(vl.values);
+ meta_data_destroy(vl.meta);
}
return status;
if (!ident_matches(&vl, match))
continue;
-
if (uc_iterator_get_time(iter, &vl.time) < 0) {
status =
grpc::Status(grpc::StatusCode::INTERNAL,
grpc::string("failed to retrieve values"));
break;
}
+ if (uc_iterator_get_meta(iter, &vl.meta) < 0) {
+ status =
+ grpc::Status(grpc::StatusCode::INTERNAL,
+ grpc::string("failed to retrieve value metadata"));
+ }
value_lists->push(vl);
} // while (uc_iterator_next(iter, &name) == 0)
listener.port = grpc::string(ci->values[1].value.string);
listener.ssl = nullptr;
- auto ssl_opts = new (grpc::SslServerCredentialsOptions);
+ auto ssl_opts = new grpc::SslServerCredentialsOptions(
+ GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp = {};
bool use_ssl = false;
return -1;
}
pkcp.cert_chain = read_file(cert);
+ } else if (!strcasecmp("VerifyPeer", child->key)) {
+ _Bool verify = 0;
+ if (cf_util_get_boolean(child, &verify)) {
+ return -1;
+ }
+ ssl_opts->client_certificate_request =
+ verify ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
+ : GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
} else {
WARNING("grpc: Option `%s` not allowed in <%s> block.", child->key,
ci->key);
.ai_socktype = SOCK_STREAM};
if ((ai_return = getaddrinfo(host, port, &ai_hints, &ai_list)) != 0) {
- char errbuf[1024];
ERROR("hddtemp plugin: getaddrinfo (%s, %s): %s", host, port,
- (ai_return == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(ai_return));
+ (ai_return == EAI_SYSTEM) ? STRERRNO : gai_strerror(ai_return));
return NULL;
}
/* create our socket descriptor */
fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (fd < 0) {
- char errbuf[1024];
- ERROR("hddtemp plugin: socket: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("hddtemp plugin: socket: %s", STRERRNO);
continue;
}
/* connect to the hddtemp daemon */
if (connect(fd, (struct sockaddr *)ai_ptr->ai_addr, ai_ptr->ai_addrlen)) {
- char errbuf[1024];
- INFO("hddtemp plugin: connect (%s, %s) failed: %s", host, port,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ INFO("hddtemp plugin: connect (%s, %s) failed: %s", host, port, STRERRNO);
close(fd);
fd = -1;
continue;
if (status == 0) {
break;
} else if (status == -1) {
- char errbuf[1024];
if ((errno == EAGAIN) || (errno == EINTR))
continue;
- ERROR("hddtemp plugin: Error reading from socket: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("hddtemp plugin: Error reading from socket: %s", STRERRNO);
close(fd);
free(buffer);
return NULL;
long page_size = strtol(result->d_name + strlen(hugepages_dir),
/* endptr = */ NULL, /* base = */ 10);
if (errno != 0) {
- char errbuf[1024];
ERROR("%s: failed to determine page size from directory name \"%s\": %s",
- g_plugin_name, result->d_name,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ g_plugin_name, result->d_name, STRERRNO);
continue;
}
_Bool hw_cache_events;
_Bool kernel_pmu_events;
_Bool sw_events;
- char event_list_fn[PATH_MAX];
+ char event_list_fn[PATH_MAX];
char **hw_events;
size_t hw_events_count;
struct eventlist *event_list;
DEBUG(PMU_PLUGIN ": software_events : %d", g_ctx.sw_events);
for (size_t i = 0; i < g_ctx.hw_events_count; i++) {
- DEBUG(PMU_PLUGIN ": hardware_events[%zu]: %s", i, g_ctx.hw_events[i]);
+ DEBUG(PMU_PLUGIN ": hardware_events[%" PRIsz "]: %s", i,
+ g_ctx.hw_events[i]);
}
}
return -EINVAL;
}
+ if (g_ctx.hw_events) {
+ ERROR(PMU_PLUGIN ": Duplicate config for HardwareEvents.");
+ return -EINVAL;
+ }
+
g_ctx.hw_events = calloc(ci->values_num, sizeof(char *));
if (g_ctx.hw_events == NULL) {
ERROR(PMU_PLUGIN ": Failed to allocate hw events.");
return 0;
}
-static void pmu_submit_counter(int cpu, char *event, counter_t value) {
+static void pmu_submit_counter(int cpu, char *event, counter_t value,
+ meta_data_t *meta) {
value_list_t vl = VALUE_LIST_INIT;
vl.values = &(value_t){.counter = value};
if (cpu == -1) {
snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "all");
} else {
+ vl.meta = meta;
snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%d", cpu);
}
sstrncpy(vl.type, "counter", sizeof(vl.type));
plugin_dispatch_values(&vl);
}
+meta_data_t *pmu_meta_data_create(const struct efd *efd) {
+ meta_data_t *meta = NULL;
+
+ /* create meta data only if value was scaled */
+ if (efd->val[1] == efd->val[2] || !efd->val[2]) {
+ return NULL;
+ }
+
+ meta = meta_data_create();
+ if (meta == NULL) {
+ ERROR(PMU_PLUGIN ": meta_data_create failed.");
+ return NULL;
+ }
+
+ meta_data_add_unsigned_int(meta, "intel_pmu:raw_count", efd->val[0]);
+ meta_data_add_unsigned_int(meta, "intel_pmu:time_enabled", efd->val[1]);
+ meta_data_add_unsigned_int(meta, "intel_pmu:time_running", efd->val[2]);
+
+ return meta;
+}
+
static void pmu_dispatch_data(void) {
struct event *e;
event_enabled++;
+ /* If there are more events than counters, the kernel uses time
+ * multiplexing. With multiplexing, at the end of the run,
+ * the counter is scaled basing on total time enabled vs time running.
+ * final_count = raw_count * time_enabled/time_running
+ */
uint64_t value = event_scaled_value(e, i);
all_value += value;
+ /* get meta data with information about scaling */
+ meta_data_t *meta = pmu_meta_data_create(&e->efd[i]);
+
/* dispatch per CPU value */
- pmu_submit_counter(i, e->event, value);
+ pmu_submit_counter(i, e->event, value, meta);
+
+ meta_data_destroy(meta);
}
if (event_enabled > 0) {
DEBUG(PMU_PLUGIN ": %-20s %'10lu", e->event, all_value);
/* dispatch all CPU value */
- pmu_submit_counter(-1, e->event, all_value);
+ pmu_submit_counter(-1, e->event, all_value, NULL);
}
}
}
char *s, *tmp;
for (s = strtok_r(events, ",", &tmp); s; s = strtok_r(NULL, ",", &tmp)) {
- /* Multiple events parsed in one entry */
- if (group_events_count == 1) {
- /* Mark previously added event as group leader */
- el->eventlist_last->group_leader = 1;
- }
-
/* Allocate memory for event struct that contains array of efd structs
for all cores */
struct event *e =
return -ENOMEM;
}
- if (resolve_event(s, &e->attr) == 0) {
- e->next = NULL;
- if (!el->eventlist)
- el->eventlist = e;
- if (el->eventlist_last)
- el->eventlist_last->next = e;
- el->eventlist_last = e;
- e->event = strdup(s);
- } else {
- DEBUG(PMU_PLUGIN ": Cannot resolve %s", s);
+ if (resolve_event(s, &e->attr) != 0) {
+ WARNING(PMU_PLUGIN ": Cannot resolve %s", s);
sfree(e);
+ continue;
+ }
+
+ /* Multiple events parsed in one entry */
+ if (group_events_count == 1) {
+ /* Mark previously added event as group leader */
+ el->eventlist_last->group_leader = 1;
}
+ e->next = NULL;
+ if (!el->eventlist)
+ el->eventlist = e;
+ if (el->eventlist_last)
+ el->eventlist_last->next = e;
+ el->eventlist_last = e;
+ e->event = strdup(s);
+
group_events_count++;
}
sfree(g_ctx.hw_events);
g_ctx.hw_events_count = 0;
-
return ret;
}
* Serhiy Pshyk <serhiyx.pshyk@intel.com>
**/
-#include "common.h"
#include "collectd.h"
+#include "common.h"
#include <pqos.h>
return;
DEBUG(RDT_PLUGIN ": Core Groups Dump");
- DEBUG(RDT_PLUGIN ": groups count: %zu", g_rdt->num_groups);
+ DEBUG(RDT_PLUGIN ": groups count: %" PRIsz, g_rdt->num_groups);
for (int i = 0; i < g_rdt->num_groups; i++) {
core_idx++) {
if (!rdt_is_core_id_valid(g_rdt->cgroups[group_idx].cores[core_idx])) {
ERROR(RDT_PLUGIN ": Core group '%s' contains invalid core id '%d'",
- g_rdt->cgroups[group_idx].desc,
- (int)g_rdt->cgroups[group_idx].cores[core_idx]);
+ g_rdt->cgroups[group_idx].desc,
+ (int)g_rdt->cgroups[group_idx].cores[core_idx]);
rdt_free_cgroups();
return -EINVAL;
}
static _Bool report_inactive = 1;
#ifdef HAVE_LIBKSTAT
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
#define MAX_NUMIF 256
extern kstat_ctl_t *kc;
static kstat_t *ksp[MAX_NUMIF];
int numfields;
if ((fh = fopen("/proc/net/dev", "r")) == NULL) {
- char errbuf[1024];
- WARNING("interface plugin: fopen: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("interface plugin: fopen: %s", STRERRNO);
return -1;
}
if ((nif = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t),
0)) < 0) {
- char errbuf[1024];
- WARNING("interface plugin: perfstat_netinterface: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("interface plugin: perfstat_netinterface: %s", STRERRNO);
return -1;
}
id.name[0] = '\0';
if ((ifs = perfstat_netinterface(&id, ifstat, sizeof(perfstat_netinterface_t),
nif)) < 0) {
- char errbuf[1024];
WARNING("interface plugin: perfstat_netinterface (interfaces=%d): %s", nif,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
status = semctl(/* id = */ 0, /* num = */ 0, SEM_INFO, arg);
if (status == -1) {
- char errbuf[1024];
ERROR("ipc plugin: semctl(2) failed: %s. "
"Maybe the kernel is not configured for semaphores?",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
status = shmctl(/* id = */ 0, SHM_INFO, (void *)&shm_info);
if (status == -1) {
- char errbuf[1024];
ERROR("ipc plugin: shmctl(2) failed: %s. "
"Maybe the kernel is not configured for shared memory?",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
if (get_ipc_info(cid, cmd, version, buff, &size) < 0) {
if (errno != ENOSPC) {
- char errbuf[1024];
- WARNING("ipc plugin: get_ipc_info: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("ipc plugin: get_ipc_info: %s", STRERRNO);
return NULL;
}
}
}
if (get_ipc_info(cid, cmd, version, buff, &size) < 0) {
- char errbuf[1024];
- WARNING("ipc plugin: get_ipc_info: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("ipc plugin: get_ipc_info: %s", STRERRNO);
free(buff);
return NULL;
}
* Florian octo Forster <octo at collectd.org>
* Peter Holik <peter at holik.at>
* Bruno Prémont <bonbons at linux-vserver.org>
+ * Pavel Rochnyak <pavel2000 ngs.ru>
**/
#include "collectd.h"
#include "plugin.h"
#include "utils_ignorelist.h"
+#include <OpenIPMI/ipmi_auth.h>
#include <OpenIPMI/ipmi_conn.h>
#include <OpenIPMI/ipmi_err.h>
+#include <OpenIPMI/ipmi_lan.h>
#include <OpenIPMI/ipmi_posix.h>
#include <OpenIPMI/ipmi_smi.h>
#include <OpenIPMI/ipmiif.h>
+#define ERR_BUF_SIZE 1024
+
/*
* Private data types
*/
struct c_ipmi_sensor_list_s;
typedef struct c_ipmi_sensor_list_s c_ipmi_sensor_list_t;
+struct c_ipmi_instance_s {
+ char *name;
+ ignorelist_t *ignorelist;
+ _Bool notify_add;
+ _Bool notify_remove;
+ _Bool notify_notpresent;
+ _Bool notify_conn;
+ _Bool sel_enabled;
+ _Bool sel_clear_event;
+
+ char *host;
+ char *connaddr;
+ char *username;
+ char *password;
+ unsigned int authtype;
+
+ _Bool connected;
+ ipmi_con_t *connection;
+ pthread_mutex_t sensor_list_lock;
+ c_ipmi_sensor_list_t *sensor_list;
+
+ _Bool active;
+ pthread_t thread_id;
+ int init_in_progress;
+
+ struct c_ipmi_instance_s *next;
+};
+typedef struct c_ipmi_instance_s c_ipmi_instance_t;
+
struct c_ipmi_sensor_list_s {
ipmi_sensor_id_t sensor_id;
char sensor_name[DATA_MAX_NAME_LEN];
char sensor_type[DATA_MAX_NAME_LEN];
+ char type_instance[DATA_MAX_NAME_LEN];
int sensor_not_present;
c_ipmi_sensor_list_t *next;
+ c_ipmi_instance_t *instance;
+ unsigned int use;
};
+struct c_ipmi_db_type_map_s {
+ enum ipmi_unit_type_e type;
+ const char *type_name;
+};
+typedef struct c_ipmi_db_type_map_s c_ipmi_db_type_map_t;
+
/*
* Module global variables
*/
-static pthread_mutex_t sensor_list_lock = PTHREAD_MUTEX_INITIALIZER;
-static c_ipmi_sensor_list_t *sensor_list = NULL;
-
-static int c_ipmi_init_in_progress = 0;
-static int c_ipmi_active = 0;
-static pthread_t thread_id = (pthread_t)0;
-
-static const char *config_keys[] = {"Sensor", "IgnoreSelected",
- "NotifySensorAdd", "NotifySensorRemove",
- "NotifySensorNotPresent"};
-static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
-
-static ignorelist_t *ignorelist = NULL;
-
-static int c_ipmi_nofiy_add = 0;
-static int c_ipmi_nofiy_remove = 0;
-static int c_ipmi_nofiy_notpresent = 0;
+static os_handler_t *os_handler = NULL;
+static c_ipmi_instance_t *instances = NULL;
/*
* Misc private functions
*/
-static void c_ipmi_error(const char *func, int status) {
- char errbuf[4096] = {0};
+static void c_ipmi_error(c_ipmi_instance_t *st, const char *func, int status) {
+ char errbuf[ERR_BUF_SIZE] = {0};
- if (IPMI_IS_OS_ERR(status)) {
- sstrerror(IPMI_GET_OS_ERR(status), errbuf, sizeof(errbuf));
- } else if (IPMI_IS_IPMI_ERR(status)) {
- ipmi_get_error_string(IPMI_GET_IPMI_ERR(status), errbuf, sizeof(errbuf));
+ if (IPMI_IS_OS_ERR(status) || IPMI_IS_RMCPP_ERR(status) ||
+ IPMI_IS_IPMI_ERR(status)) {
+ ipmi_get_error_string(status, errbuf, sizeof(errbuf));
}
if (errbuf[0] == 0) {
}
errbuf[sizeof(errbuf) - 1] = 0;
- ERROR("ipmi plugin: %s failed: %s", func, errbuf);
+ ERROR("ipmi plugin: %s failed for `%s`: %s", func, st->name, errbuf);
} /* void c_ipmi_error */
+static void c_ipmi_log(os_handler_t *handler, const char *format,
+ enum ipmi_log_type_e log_type, va_list ap) {
+ char msg[ERR_BUF_SIZE];
+
+ vsnprintf(msg, sizeof(msg), format, ap);
+
+ switch (log_type) {
+ case IPMI_LOG_INFO:
+ INFO("ipmi plugin: %s", msg);
+ break;
+ case IPMI_LOG_WARNING:
+ NOTICE("ipmi plugin: %s", msg);
+ break;
+ case IPMI_LOG_SEVERE:
+ WARNING("ipmi plugin: %s", msg);
+ break;
+ case IPMI_LOG_FATAL:
+ ERROR("ipmi plugin: %s", msg);
+ break;
+ case IPMI_LOG_ERR_INFO:
+ ERROR("ipmi plugin: %s", msg);
+ break;
+#if COLLECT_DEBUG
+ case IPMI_LOG_DEBUG_START:
+ case IPMI_LOG_DEBUG:
+ DEBUG("ipmi plugin: %s", msg);
+ break;
+ case IPMI_LOG_DEBUG_CONT:
+ case IPMI_LOG_DEBUG_END:
+ DEBUG("%s", msg);
+ break;
+#else
+ case IPMI_LOG_DEBUG_START:
+ case IPMI_LOG_DEBUG:
+ case IPMI_LOG_DEBUG_CONT:
+ case IPMI_LOG_DEBUG_END:
+ break;
+#endif
+ }
+} /* void c_ipmi_log */
+
+static notification_t c_ipmi_notification_init(c_ipmi_instance_t const *st,
+ int severity) {
+ notification_t n = {severity, cdtime(), "", "", "ipmi", "", "", "", NULL};
+
+ sstrncpy(n.host, (st->host != NULL) ? st->host : hostname_g, sizeof(n.host));
+ return n;
+} /* notification_t c_ipmi_notification_init */
+
/*
* Sensor handlers
*/
/* Prototype for sensor_list_remove, so sensor_read_handler can call it. */
-static int sensor_list_remove(ipmi_sensor_t *sensor);
+static int sensor_list_remove(c_ipmi_instance_t *st, ipmi_sensor_t *sensor);
static void sensor_read_handler(ipmi_sensor_t *sensor, int err,
enum ipmi_value_present_e value_present,
unsigned int __attribute__((unused)) raw_value,
- double value,
- ipmi_states_t __attribute__((unused)) * states,
+ double value, ipmi_states_t *states,
void *user_data) {
value_list_t vl = VALUE_LIST_INIT;
- c_ipmi_sensor_list_t *list_item = (c_ipmi_sensor_list_t *)user_data;
+ c_ipmi_sensor_list_t *list_item = user_data;
+ c_ipmi_instance_t *st = list_item->instance;
+
+ list_item->use--;
if (err != 0) {
- if ((err & 0xff) == IPMI_NOT_PRESENT_CC) {
+ if (IPMI_IS_IPMI_ERR(err) &&
+ IPMI_GET_IPMI_ERR(err) == IPMI_NOT_PRESENT_CC) {
if (list_item->sensor_not_present == 0) {
list_item->sensor_not_present = 1;
- INFO("ipmi plugin: sensor_read_handler: sensor %s "
+ INFO("ipmi plugin: sensor_read_handler: sensor `%s` of `%s` "
"not present.",
- list_item->sensor_name);
+ list_item->sensor_name, st->name);
- if (c_ipmi_nofiy_notpresent) {
- notification_t n = {
- NOTIF_WARNING, cdtime(), "", "", "ipmi", "", "", "", NULL};
+ if (st->notify_notpresent) {
+ notification_t n = c_ipmi_notification_init(st, NOTIF_WARNING);
- sstrncpy(n.host, hostname_g, sizeof(n.host));
- sstrncpy(n.type_instance, list_item->sensor_name,
+ sstrncpy(n.type_instance, list_item->type_instance,
sizeof(n.type_instance));
sstrncpy(n.type, list_item->sensor_type, sizeof(n.type));
snprintf(n.message, sizeof(n.message), "sensor %s not present",
} else if (IPMI_IS_IPMI_ERR(err) &&
IPMI_GET_IPMI_ERR(err) ==
IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC) {
- INFO("ipmi plugin: sensor_read_handler: Sensor %s not ready",
- list_item->sensor_name);
+ INFO("ipmi plugin: sensor_read_handler: Sensor `%s` of `%s` not ready.",
+ list_item->sensor_name, st->name);
+ } else if (IPMI_IS_IPMI_ERR(err) &&
+ IPMI_GET_IPMI_ERR(err) == IPMI_TIMEOUT_CC) {
+ INFO("ipmi plugin: sensor_read_handler: Sensor `%s` of `%s` timed out.",
+ list_item->sensor_name, st->name);
} else {
+ char errbuf[ERR_BUF_SIZE] = {0};
+ ipmi_get_error_string(err, errbuf, sizeof(errbuf) - 1);
+
if (IPMI_IS_IPMI_ERR(err))
- INFO("ipmi plugin: sensor_read_handler: Removing sensor %s, "
- "because it failed with IPMI error %#x.",
- list_item->sensor_name, IPMI_GET_IPMI_ERR(err));
+ INFO("ipmi plugin: sensor_read_handler: Sensor `%s` of `%s` failed: "
+ "%s.",
+ list_item->sensor_name, st->name, errbuf);
else if (IPMI_IS_OS_ERR(err))
- INFO("ipmi plugin: sensor_read_handler: Removing sensor %s, "
- "because it failed with OS error %#x.",
- list_item->sensor_name, IPMI_GET_OS_ERR(err));
+ INFO("ipmi plugin: sensor_read_handler: Sensor `%s` of `%s` failed: "
+ "%s (%#x).",
+ list_item->sensor_name, st->name, errbuf, IPMI_GET_OS_ERR(err));
else if (IPMI_IS_RMCPP_ERR(err))
- INFO("ipmi plugin: sensor_read_handler: Removing sensor %s, "
- "because it failed with RMCPP error %#x.",
- list_item->sensor_name, IPMI_GET_RMCPP_ERR(err));
+ INFO("ipmi plugin: sensor_read_handler: Sensor `%s` of `%s` failed: "
+ "%s.",
+ list_item->sensor_name, st->name, errbuf);
else if (IPMI_IS_SOL_ERR(err))
- INFO("ipmi plugin: sensor_read_handler: Removing sensor %s, "
- "because it failed with RMCPP error %#x.",
- list_item->sensor_name, IPMI_GET_SOL_ERR(err));
+ INFO("ipmi plugin: sensor_read_handler: Sensor `%s` of `%s` failed: "
+ "%s (%#x).",
+ list_item->sensor_name, st->name, errbuf, IPMI_GET_SOL_ERR(err));
else
- INFO("ipmi plugin: sensor_read_handler: Removing sensor %s, "
- "because it failed with error %#x. of class %#x",
- list_item->sensor_name, err & 0xff, err & 0xffffff00);
- sensor_list_remove(sensor);
+ INFO("ipmi plugin: sensor_read_handler: Sensor `%s` of `%s` failed "
+ "with error %#x. of class %#x",
+ list_item->sensor_name, st->name, err & 0xff, err & 0xffffff00);
}
return;
} else if (list_item->sensor_not_present == 1) {
list_item->sensor_not_present = 0;
- INFO("ipmi plugin: sensor_read_handler: sensor %s present.",
- list_item->sensor_name);
+ INFO("ipmi plugin: sensor_read_handler: sensor `%s` of `%s` present.",
+ list_item->sensor_name, st->name);
- if (c_ipmi_nofiy_notpresent) {
- notification_t n = {NOTIF_OKAY, cdtime(), "", "", "ipmi",
- "", "", "", NULL};
+ if (st->notify_notpresent) {
+ notification_t n = c_ipmi_notification_init(st, NOTIF_OKAY);
- sstrncpy(n.host, hostname_g, sizeof(n.host));
- sstrncpy(n.type_instance, list_item->sensor_name,
+ sstrncpy(n.type_instance, list_item->type_instance,
sizeof(n.type_instance));
sstrncpy(n.type, list_item->sensor_type, sizeof(n.type));
snprintf(n.message, sizeof(n.message), "sensor %s present",
}
if (value_present != IPMI_BOTH_VALUES_PRESENT) {
- INFO("ipmi plugin: sensor_read_handler: Removing sensor %s, "
+ INFO("ipmi plugin: sensor_read_handler: Removing sensor `%s` of `%s`, "
"because it provides %s. If you need this sensor, "
"please file a bug report.",
- list_item->sensor_name,
+ list_item->sensor_name, st->name,
(value_present == IPMI_RAW_VALUE_PRESENT) ? "only the raw value"
: "no value");
- sensor_list_remove(sensor);
+ sensor_list_remove(st, sensor);
+ return;
+ }
+
+ if (!ipmi_is_sensor_scanning_enabled(states)) {
+ DEBUG("ipmi plugin: sensor_read_handler: Skipping sensor `%s` of `%s`, "
+ "it is in 'scanning disabled' state.",
+ list_item->sensor_name, st->name);
+ return;
+ }
+
+ if (ipmi_is_initial_update_in_progress(states)) {
+ DEBUG("ipmi plugin: sensor_read_handler: Skipping sensor `%s` of `%s`, "
+ "it is in 'initial update in progress' state.",
+ list_item->sensor_name, st->name);
return;
}
vl.values = &(value_t){.gauge = value};
vl.values_len = 1;
+ if (st->host != NULL)
+ sstrncpy(vl.host, st->host, sizeof(vl.host));
sstrncpy(vl.plugin, "ipmi", sizeof(vl.plugin));
sstrncpy(vl.type, list_item->sensor_type, sizeof(vl.type));
- sstrncpy(vl.type_instance, list_item->sensor_name, sizeof(vl.type_instance));
+ sstrncpy(vl.type_instance, list_item->type_instance,
+ sizeof(vl.type_instance));
plugin_dispatch_values(&vl);
} /* void sensor_read_handler */
-static int sensor_list_add(ipmi_sensor_t *sensor) {
+static void sensor_get_name(ipmi_sensor_t *sensor, char *buffer, int buf_len) {
+ char temp[DATA_MAX_NAME_LEN] = {0};
+ ipmi_entity_t *ent = ipmi_sensor_get_entity(sensor);
+ const char *entity_id_string = ipmi_entity_get_entity_id_string(ent);
+ char sensor_name[DATA_MAX_NAME_LEN] = "";
+ char *sensor_name_ptr;
+
+ if ((buffer == NULL) || (buf_len == 0))
+ return;
+
+ ipmi_sensor_get_name(sensor, temp, sizeof(temp));
+ temp[sizeof(temp) - 1] = 0;
+
+ if (entity_id_string != NULL && strlen(temp))
+ snprintf(sensor_name, sizeof(sensor_name), "%s %s", temp, entity_id_string);
+ else if (entity_id_string != NULL)
+ sstrncpy(sensor_name, entity_id_string, sizeof(sensor_name));
+ else
+ sstrncpy(sensor_name, temp, sizeof(sensor_name));
+
+ if (strlen(temp)) {
+ sstrncpy(temp, sensor_name, sizeof(temp));
+ sensor_name_ptr = strstr(temp, ").");
+ if (sensor_name_ptr != NULL) {
+ /* If name is something like "foo (123).bar",
+ * change that to "bar (123)".
+ * Both, sensor_name_ptr and sensor_id_ptr point to memory within the
+ * `temp' array, which holds a copy of the current `sensor_name'. */
+ char *sensor_id_ptr;
+
+ /* `sensor_name_ptr' points to ").bar". */
+ sensor_name_ptr[1] = 0;
+ /* `temp' holds "foo (123)\0bar\0". */
+ sensor_name_ptr += 2;
+ /* `sensor_name_ptr' now points to "bar". */
+
+ sensor_id_ptr = strstr(temp, "(");
+ if (sensor_id_ptr != NULL) {
+ /* `sensor_id_ptr' now points to "(123)". */
+ snprintf(sensor_name, sizeof(sensor_name), "%s %s", sensor_name_ptr,
+ sensor_id_ptr);
+ }
+ /* else: don't touch sensor_name. */
+ }
+ }
+ sstrncpy(buffer, sensor_name, buf_len);
+}
+
+static const char *sensor_unit_to_type(ipmi_sensor_t *sensor) {
+ static const c_ipmi_db_type_map_t ipmi_db_type_map[] = {
+ {IPMI_UNIT_TYPE_WATTS, "power"}, {IPMI_UNIT_TYPE_CFM, "flow"}};
+
+ /* check the modifier and rate of the sensor value */
+ if ((ipmi_sensor_get_modifier_unit_use(sensor) != IPMI_MODIFIER_UNIT_NONE) ||
+ (ipmi_sensor_get_rate_unit(sensor) != IPMI_RATE_UNIT_NONE))
+ return NULL;
+
+ /* find the db type by using sensor base unit type */
+ enum ipmi_unit_type_e ipmi_type = ipmi_sensor_get_base_unit(sensor);
+ for (int i = 0; i < STATIC_ARRAY_SIZE(ipmi_db_type_map); i++)
+ if (ipmi_db_type_map[i].type == ipmi_type)
+ return ipmi_db_type_map[i].type_name;
+
+ return NULL;
+} /* const char* sensor_unit_to_type */
+
+static int sensor_list_add(c_ipmi_instance_t *st, ipmi_sensor_t *sensor) {
ipmi_sensor_id_t sensor_id;
c_ipmi_sensor_list_t *list_item;
c_ipmi_sensor_list_t *list_prev;
char buffer[DATA_MAX_NAME_LEN] = {0};
- const char *entity_id_string;
- char sensor_name[DATA_MAX_NAME_LEN];
- char *sensor_name_ptr;
+ char *sensor_name_ptr = buffer;
int sensor_type;
const char *type;
- ipmi_entity_t *ent = ipmi_sensor_get_entity(sensor);
sensor_id = ipmi_sensor_convert_to_id(sensor);
+ sensor_get_name(sensor, buffer, sizeof(buffer));
+
+ DEBUG("ipmi plugin: sensor_list_add: Found sensor `%s` of `%s`,"
+ " Type: %#x"
+ " Event reading type: %#x"
+ " Direction: %#x"
+ " Event support: %#x",
+ sensor_name_ptr, st->name, ipmi_sensor_get_sensor_type(sensor),
+ ipmi_sensor_get_event_reading_type(sensor),
+ ipmi_sensor_get_sensor_direction(sensor),
+ ipmi_sensor_get_event_support(sensor));
+
+ /* Both `ignorelist' and `sensor_name_ptr' may be NULL. */
+ if (ignorelist_match(st->ignorelist, sensor_name_ptr) != 0)
+ return 0;
- ipmi_sensor_get_name(sensor, buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = 0;
+ /* FIXME: Use rate unit or base unit to scale the value */
- entity_id_string = ipmi_entity_get_entity_id_string(ent);
+ sensor_type = ipmi_sensor_get_sensor_type(sensor);
- if (entity_id_string == NULL)
- sstrncpy(sensor_name, buffer, sizeof(sensor_name));
- else
- snprintf(sensor_name, sizeof(sensor_name), "%s %s", buffer,
- entity_id_string);
-
- sstrncpy(buffer, sensor_name, sizeof(buffer));
- sensor_name_ptr = strstr(buffer, ").");
- if (sensor_name_ptr != NULL) {
- /* If name is something like "foo (123).bar",
- * change that to "bar (123)".
- * Both, sensor_name_ptr and sensor_id_ptr point to memory within the
- * `buffer' array, which holds a copy of the current `sensor_name'. */
- char *sensor_id_ptr;
-
- /* `sensor_name_ptr' points to ").bar". */
- sensor_name_ptr[1] = 0;
- /* `buffer' holds "foo (123)\0bar\0". */
- sensor_name_ptr += 2;
- /* `sensor_name_ptr' now points to "bar". */
-
- sensor_id_ptr = strstr(buffer, "(");
- if (sensor_id_ptr != NULL) {
- /* `sensor_id_ptr' now points to "(123)". */
- snprintf(sensor_name, sizeof(sensor_name), "%s %s", sensor_name_ptr,
- sensor_id_ptr);
- }
- /* else: don't touch sensor_name. */
+ /*
+ * ipmitool/lib/ipmi_sdr.c sdr_sensor_has_analog_reading() has a notice
+ * about 'Threshold sensors' and 'analog readings'. Discrete sensor may
+ * have analog data, but discrete sensors support is not implemented
+ * in Collectd yet.
+ *
+ * ipmi_sensor_id_get_reading() supports only 'Threshold' sensors.
+ * See lib/sensor.c:4842, stand_ipmi_sensor_get_reading() for details.
+ */
+ if (!ipmi_sensor_get_is_readable(sensor)) {
+ INFO("ipmi plugin: sensor_list_add: Ignore sensor `%s` of `%s`, "
+ "because it isn't readable! Its type: (%#x, %s). ",
+ sensor_name_ptr, st->name, sensor_type,
+ ipmi_sensor_get_sensor_type_string(sensor));
+ return -1;
}
- sensor_name_ptr = sensor_name;
-
- /* Both `ignorelist' and `plugin_instance' may be NULL. */
- if (ignorelist_match(ignorelist, sensor_name_ptr) != 0)
- return 0;
- /* FIXME: Use rate unit or base unit to scale the value */
+ if (ipmi_sensor_get_event_reading_type(sensor) !=
+ IPMI_EVENT_READING_TYPE_THRESHOLD) {
+ INFO("ipmi plugin: sensor_list_add: Ignore sensor `%s` of `%s`, "
+ "because it is discrete (%#x)! Its type: (%#x, %s). ",
+ sensor_name_ptr, st->name, sensor_type,
+ ipmi_sensor_get_event_reading_type(sensor),
+ ipmi_sensor_get_sensor_type_string(sensor));
+ return -1;
+ }
- sensor_type = ipmi_sensor_get_sensor_type(sensor);
switch (sensor_type) {
case IPMI_SENSOR_TYPE_TEMPERATURE:
type = "temperature";
type = "fanspeed";
break;
+ case IPMI_SENSOR_TYPE_MEMORY:
+ type = "memory";
+ break;
+
default: {
- const char *sensor_type_str;
+ /* try to get collectd DB type based on sensor base unit type */
+ if ((type = sensor_unit_to_type(sensor)) != NULL)
+ break;
- sensor_type_str = ipmi_sensor_get_sensor_type_string(sensor);
- INFO("ipmi plugin: sensor_list_add: Ignore sensor %s, "
- "because I don't know how to handle its type (%#x, %s). "
- "If you need this sensor, please file a bug report.",
- sensor_name_ptr, sensor_type, sensor_type_str);
+ INFO("ipmi plugin: sensor_list_add: Ignore sensor `%s` of `%s`, "
+ "because I don't know how to handle its units (%#x, %#x, %#x). "
+ "Sensor type: (%#x, %s). If you need this sensor, please file "
+ "a bug report at http://collectd.org/.",
+ sensor_name_ptr, st->name, ipmi_sensor_get_base_unit(sensor),
+ ipmi_sensor_get_modifier_unit(sensor),
+ ipmi_sensor_get_rate_unit(sensor), sensor_type,
+ ipmi_sensor_get_sensor_type_string(sensor));
return -1;
}
} /* switch (sensor_type) */
- pthread_mutex_lock(&sensor_list_lock);
+ pthread_mutex_lock(&st->sensor_list_lock);
list_prev = NULL;
- for (list_item = sensor_list; list_item != NULL;
+ for (list_item = st->sensor_list; list_item != NULL;
list_item = list_item->next) {
if (ipmi_cmp_sensor_id(sensor_id, list_item->sensor_id) == 0)
break;
} /* for (list_item) */
if (list_item != NULL) {
- pthread_mutex_unlock(&sensor_list_lock);
+ pthread_mutex_unlock(&st->sensor_list_lock);
return 0;
}
list_item = (c_ipmi_sensor_list_t *)calloc(1, sizeof(c_ipmi_sensor_list_t));
if (list_item == NULL) {
- pthread_mutex_unlock(&sensor_list_lock);
+ pthread_mutex_unlock(&st->sensor_list_lock);
return -1;
}
+ list_item->instance = st;
list_item->sensor_id = ipmi_sensor_convert_to_id(sensor);
if (list_prev != NULL)
list_prev->next = list_item;
else
- sensor_list = list_item;
+ st->sensor_list = list_item;
+
+ /* if sensor provides the percentage value, use "percent" collectd type
+ and add the `percent` to the type instance of the reported value */
+ if (ipmi_sensor_get_percentage(sensor)) {
+ snprintf(list_item->type_instance, sizeof(list_item->type_instance),
+ "percent-%s", sensor_name_ptr);
+ type = "percent";
+ } else {
+ /* use type instance as a name of the sensor */
+ sstrncpy(list_item->type_instance, sensor_name_ptr,
+ sizeof(list_item->type_instance));
+ }
sstrncpy(list_item->sensor_name, sensor_name_ptr,
sizeof(list_item->sensor_name));
sstrncpy(list_item->sensor_type, type, sizeof(list_item->sensor_type));
- pthread_mutex_unlock(&sensor_list_lock);
+ pthread_mutex_unlock(&st->sensor_list_lock);
- if (c_ipmi_nofiy_add && (c_ipmi_init_in_progress == 0)) {
- notification_t n = {NOTIF_OKAY, cdtime(), "", "", "ipmi", "", "", "", NULL};
+ if (st->notify_add && (st->init_in_progress == 0)) {
+ notification_t n = c_ipmi_notification_init(st, NOTIF_OKAY);
- sstrncpy(n.host, hostname_g, sizeof(n.host));
- sstrncpy(n.type_instance, list_item->sensor_name, sizeof(n.type_instance));
+ sstrncpy(n.type_instance, list_item->type_instance,
+ sizeof(n.type_instance));
sstrncpy(n.type, list_item->sensor_type, sizeof(n.type));
snprintf(n.message, sizeof(n.message), "sensor %s added",
list_item->sensor_name);
return 0;
} /* int sensor_list_add */
-static int sensor_list_remove(ipmi_sensor_t *sensor) {
+static int sensor_list_remove(c_ipmi_instance_t *st, ipmi_sensor_t *sensor) {
ipmi_sensor_id_t sensor_id;
c_ipmi_sensor_list_t *list_item;
c_ipmi_sensor_list_t *list_prev;
sensor_id = ipmi_sensor_convert_to_id(sensor);
- pthread_mutex_lock(&sensor_list_lock);
+ pthread_mutex_lock(&st->sensor_list_lock);
list_prev = NULL;
- for (list_item = sensor_list; list_item != NULL;
+ for (list_item = st->sensor_list; list_item != NULL;
list_item = list_item->next) {
if (ipmi_cmp_sensor_id(sensor_id, list_item->sensor_id) == 0)
break;
} /* for (list_item) */
if (list_item == NULL) {
- pthread_mutex_unlock(&sensor_list_lock);
+ pthread_mutex_unlock(&st->sensor_list_lock);
return -1;
}
if (list_prev == NULL)
- sensor_list = list_item->next;
+ st->sensor_list = list_item->next;
else
list_prev->next = list_item->next;
list_prev = NULL;
list_item->next = NULL;
- pthread_mutex_unlock(&sensor_list_lock);
+ pthread_mutex_unlock(&st->sensor_list_lock);
- if (c_ipmi_nofiy_remove && c_ipmi_active) {
- notification_t n = {NOTIF_WARNING, cdtime(), "", "", "ipmi", "", "", "",
- NULL};
+ if (st->notify_remove && st->active) {
+ notification_t n = c_ipmi_notification_init(st, NOTIF_WARNING);
- sstrncpy(n.host, hostname_g, sizeof(n.host));
- sstrncpy(n.type_instance, list_item->sensor_name, sizeof(n.type_instance));
+ sstrncpy(n.type_instance, list_item->type_instance,
+ sizeof(n.type_instance));
sstrncpy(n.type, list_item->sensor_type, sizeof(n.type));
snprintf(n.message, sizeof(n.message), "sensor %s removed",
list_item->sensor_name);
return 0;
} /* int sensor_list_remove */
-static int sensor_list_read_all(void) {
- pthread_mutex_lock(&sensor_list_lock);
+static int sensor_list_read_all(c_ipmi_instance_t *st) {
+ pthread_mutex_lock(&st->sensor_list_lock);
- for (c_ipmi_sensor_list_t *list_item = sensor_list; list_item != NULL;
+ for (c_ipmi_sensor_list_t *list_item = st->sensor_list; list_item != NULL;
list_item = list_item->next) {
+ DEBUG("ipmi plugin: try read sensor `%s` of `%s`, use: %d",
+ list_item->sensor_name, st->name, list_item->use);
+
+ /* Reading already initiated */
+ if (list_item->use)
+ continue;
+
+ list_item->use++;
ipmi_sensor_id_get_reading(list_item->sensor_id, sensor_read_handler,
- /* user data = */ list_item);
+ /* user data = */ (void *)list_item);
} /* for (list_item) */
- pthread_mutex_unlock(&sensor_list_lock);
+ pthread_mutex_unlock(&st->sensor_list_lock);
return 0;
} /* int sensor_list_read_all */
-static int sensor_list_remove_all(void) {
+static int sensor_list_remove_all(c_ipmi_instance_t *st) {
c_ipmi_sensor_list_t *list_item;
- pthread_mutex_lock(&sensor_list_lock);
+ pthread_mutex_lock(&st->sensor_list_lock);
- list_item = sensor_list;
- sensor_list = NULL;
+ list_item = st->sensor_list;
+ st->sensor_list = NULL;
- pthread_mutex_unlock(&sensor_list_lock);
+ pthread_mutex_unlock(&st->sensor_list_lock);
while (list_item != NULL) {
c_ipmi_sensor_list_t *list_next = list_item->next;
return 0;
} /* int sensor_list_remove_all */
+static int sensor_convert_threshold_severity(enum ipmi_thresh_e severity) {
+ switch (severity) {
+ case IPMI_LOWER_NON_CRITICAL:
+ case IPMI_UPPER_NON_CRITICAL:
+ return NOTIF_OKAY;
+ case IPMI_LOWER_CRITICAL:
+ case IPMI_UPPER_CRITICAL:
+ return NOTIF_WARNING;
+ case IPMI_LOWER_NON_RECOVERABLE:
+ case IPMI_UPPER_NON_RECOVERABLE:
+ return NOTIF_FAILURE;
+ default:
+ return NOTIF_OKAY;
+ } /* switch (severity) */
+} /* int sensor_convert_threshold_severity */
+
+static void add_event_common_data(notification_t *n, ipmi_sensor_t *sensor,
+ enum ipmi_event_dir_e dir,
+ ipmi_event_t *event) {
+ ipmi_entity_t *ent = ipmi_sensor_get_entity(sensor);
+
+ plugin_notification_meta_add_string(n, "entity_name",
+ ipmi_entity_get_entity_id_string(ent));
+ plugin_notification_meta_add_signed_int(n, "entity_id",
+ ipmi_entity_get_entity_id(ent));
+ plugin_notification_meta_add_signed_int(n, "entity_instance",
+ ipmi_entity_get_entity_instance(ent));
+ plugin_notification_meta_add_boolean(n, "assert", dir == IPMI_ASSERTION);
+
+ if (event)
+ plugin_notification_meta_add_signed_int(n, "event_type",
+ ipmi_event_get_type(event));
+} /* void add_event_sensor_meta_data */
+
+static int sensor_threshold_event_handler(
+ ipmi_sensor_t *sensor, enum ipmi_event_dir_e dir,
+ enum ipmi_thresh_e threshold, enum ipmi_event_value_dir_e high_low,
+ enum ipmi_value_present_e value_present, unsigned int raw_value,
+ double value, void *cb_data, ipmi_event_t *event) {
+
+ c_ipmi_instance_t *st = cb_data;
+
+ /* From the IPMI specification Chapter 2: Events.
+ * If a callback handles the event, then all future callbacks called due to
+ * the event will receive a NULL for the event. So be ready to handle a NULL
+ * event in all your event handlers. A NULL may also be passed to an event
+ * handler if the callback was not due to an event. */
+ if (event == NULL)
+ return IPMI_EVENT_NOT_HANDLED;
+
+ notification_t n = c_ipmi_notification_init(st, NOTIF_OKAY);
+ /* offset is a table index and it's represented as enum of strings that are
+ organized in the way - high and low for each threshold severity level */
+ unsigned int offset = (2 * threshold) + high_low;
+ unsigned int event_type = ipmi_sensor_get_event_reading_type(sensor);
+ unsigned int sensor_type = ipmi_sensor_get_sensor_type(sensor);
+ const char *event_state =
+ ipmi_get_reading_name(event_type, sensor_type, offset);
+ sensor_get_name(sensor, n.type_instance, sizeof(n.type_instance));
+ if (value_present != IPMI_NO_VALUES_PRESENT)
+ snprintf(n.message, sizeof(n.message),
+ "sensor %s received event: %s, value is %f", n.type_instance,
+ event_state, value);
+ else
+ snprintf(n.message, sizeof(n.message),
+ "sensor %s received event: %s, value not provided",
+ n.type_instance, event_state);
+
+ DEBUG("Threshold event received for sensor %s", n.type_instance);
+
+ sstrncpy(n.type, ipmi_sensor_get_sensor_type_string(sensor), sizeof(n.type));
+ n.severity = sensor_convert_threshold_severity(threshold);
+ n.time = NS_TO_CDTIME_T(ipmi_event_get_timestamp(event));
+
+ plugin_notification_meta_add_string(&n, "severity",
+ ipmi_get_threshold_string(threshold));
+ plugin_notification_meta_add_string(&n, "direction",
+ ipmi_get_value_dir_string(high_low));
+
+ switch (value_present) {
+ case IPMI_BOTH_VALUES_PRESENT:
+ plugin_notification_meta_add_double(&n, "val", value);
+ /* both values present, so fall-through to add raw value too */
+ case IPMI_RAW_VALUE_PRESENT: {
+ char buf[DATA_MAX_NAME_LEN] = {0};
+ snprintf(buf, sizeof(buf), "0x%2.2x", raw_value);
+ plugin_notification_meta_add_string(&n, "raw", buf);
+ } break;
+ default:
+ break;
+ } /* switch (value_present) */
+
+ add_event_common_data(&n, sensor, dir, event);
+
+ plugin_dispatch_notification(&n);
+ plugin_notification_meta_free(n.meta);
+
+ /* Delete handled ipmi event from the list */
+ if (st->sel_clear_event) {
+ ipmi_event_delete(event, NULL, NULL);
+ return IPMI_EVENT_HANDLED;
+ }
+
+ return IPMI_EVENT_NOT_HANDLED;
+} /* int sensor_threshold_event_handler */
+
+static int sensor_discrete_event_handler(ipmi_sensor_t *sensor,
+ enum ipmi_event_dir_e dir, int offset,
+ int severity, int prev_severity,
+ void *cb_data, ipmi_event_t *event) {
+
+ c_ipmi_instance_t *st = cb_data;
+
+ /* From the IPMI specification Chapter 2: Events.
+ * If a callback handles the event, then all future callbacks called due to
+ * the event will receive a NULL for the event. So be ready to handle a NULL
+ * event in all your event handlers. A NULL may also be passed to an event
+ * handler if the callback was not due to an event. */
+ if (event == NULL)
+ return IPMI_EVENT_NOT_HANDLED;
+
+ notification_t n = c_ipmi_notification_init(st, NOTIF_OKAY);
+ unsigned int event_type = ipmi_sensor_get_event_reading_type(sensor);
+ unsigned int sensor_type = ipmi_sensor_get_sensor_type(sensor);
+ const char *event_state =
+ ipmi_get_reading_name(event_type, sensor_type, offset);
+ sensor_get_name(sensor, n.type_instance, sizeof(n.type_instance));
+ snprintf(n.message, sizeof(n.message), "sensor %s received event: %s",
+ n.type_instance, event_state);
+
+ DEBUG("Discrete event received for sensor %s", n.type_instance);
+
+ sstrncpy(n.type, ipmi_sensor_get_sensor_type_string(sensor), sizeof(n.type));
+ n.time = NS_TO_CDTIME_T(ipmi_event_get_timestamp(event));
+
+ plugin_notification_meta_add_signed_int(&n, "offset", offset);
+
+ if (severity != -1)
+ plugin_notification_meta_add_signed_int(&n, "severity", severity);
+
+ if (prev_severity != -1)
+ plugin_notification_meta_add_signed_int(&n, "prevseverity", prev_severity);
+
+ add_event_common_data(&n, sensor, dir, event);
+
+ plugin_dispatch_notification(&n);
+ plugin_notification_meta_free(n.meta);
+
+ /* Delete handled ipmi event from the list */
+ if (st->sel_clear_event) {
+ ipmi_event_delete(event, NULL, NULL);
+ return IPMI_EVENT_HANDLED;
+ }
+
+ return IPMI_EVENT_NOT_HANDLED;
+} /* int sensor_discrete_event_handler */
+
/*
* Entity handlers
*/
-static void entity_sensor_update_handler(
- enum ipmi_update_e op, ipmi_entity_t __attribute__((unused)) * entity,
- ipmi_sensor_t *sensor, void __attribute__((unused)) * user_data) {
- /* TODO: Ignore sensors we cannot read */
+static void
+entity_sensor_update_handler(enum ipmi_update_e op,
+ ipmi_entity_t __attribute__((unused)) * entity,
+ ipmi_sensor_t *sensor, void *user_data) {
+ c_ipmi_instance_t *st = user_data;
if ((op == IPMI_ADDED) || (op == IPMI_CHANGED)) {
/* Will check for duplicate entries.. */
- sensor_list_add(sensor);
+ sensor_list_add(st, sensor);
+
+ if (st->sel_enabled) {
+ int status = 0;
+ /* register threshold event handler */
+ if (ipmi_sensor_get_event_reading_type(sensor) ==
+ IPMI_EVENT_READING_TYPE_THRESHOLD)
+ status = ipmi_sensor_add_threshold_event_handler(
+ sensor, sensor_threshold_event_handler, st);
+ /* register discrete handler if discrete/specific sensor support events */
+ else if (ipmi_sensor_get_event_support(sensor) != IPMI_EVENT_SUPPORT_NONE)
+ status = ipmi_sensor_add_discrete_event_handler(
+ sensor, sensor_discrete_event_handler, st);
+
+ if (status) {
+ char buf[DATA_MAX_NAME_LEN] = {0};
+ sensor_get_name(sensor, buf, sizeof(buf));
+ ERROR("Unable to add sensor %s event handler, status: %d", buf, status);
+ }
+ }
} else if (op == IPMI_DELETED) {
- sensor_list_remove(sensor);
+ sensor_list_remove(st, sensor);
+
+ if (st->sel_enabled) {
+ if (ipmi_sensor_get_event_reading_type(sensor) ==
+ IPMI_EVENT_READING_TYPE_THRESHOLD)
+ ipmi_sensor_remove_threshold_event_handler(
+ sensor, sensor_threshold_event_handler, st);
+ else
+ ipmi_sensor_remove_discrete_event_handler(
+ sensor, sensor_discrete_event_handler, st);
+ }
}
} /* void entity_sensor_update_handler */
/*
* Domain handlers
*/
-static void domain_entity_update_handler(
- enum ipmi_update_e op, ipmi_domain_t __attribute__((unused)) * domain,
- ipmi_entity_t *entity, void __attribute__((unused)) * user_data) {
+static void
+domain_entity_update_handler(enum ipmi_update_e op,
+ ipmi_domain_t __attribute__((unused)) * domain,
+ ipmi_entity_t *entity, void *user_data) {
int status;
+ c_ipmi_instance_t *st = user_data;
if (op == IPMI_ADDED) {
status = ipmi_entity_add_sensor_update_handler(
- entity, entity_sensor_update_handler, /* user data = */ NULL);
+ entity, entity_sensor_update_handler, /* user data = */ (void *)st);
if (status != 0) {
- c_ipmi_error("ipmi_entity_add_sensor_update_handler", status);
+ c_ipmi_error(st, "ipmi_entity_add_sensor_update_handler", status);
}
} else if (op == IPMI_DELETED) {
status = ipmi_entity_remove_sensor_update_handler(
- entity, entity_sensor_update_handler, /* user data = */ NULL);
+ entity, entity_sensor_update_handler, /* user data = */ (void *)st);
if (status != 0) {
- c_ipmi_error("ipmi_entity_remove_sensor_update_handler", status);
+ c_ipmi_error(st, "ipmi_entity_remove_sensor_update_handler", status);
}
}
} /* void domain_entity_update_handler */
+static void smi_event_handler(ipmi_con_t __attribute__((unused)) * ipmi,
+ const ipmi_addr_t __attribute__((unused)) * addr,
+ unsigned int __attribute__((unused)) addr_len,
+ ipmi_event_t *event, void *cb_data) {
+ unsigned int type = ipmi_event_get_type(event);
+ ipmi_domain_t *domain = cb_data;
+
+ DEBUG("%s: Event received: type %u", __FUNCTION__, type);
+
+ if (type != 0x02)
+ /* It's not a standard IPMI event. */
+ return;
+
+ /* force domain to reread SELs */
+ ipmi_domain_reread_sels(domain, NULL, NULL);
+}
+
static void domain_connection_change_handler(ipmi_domain_t *domain, int err,
unsigned int conn_num,
unsigned int port_num,
int still_connected,
void *user_data) {
- int status;
DEBUG("domain_connection_change_handler (domain = %p, err = %i, "
"conn_num = %u, port_num = %u, still_connected = %i, "
- "user_data = %p);\n",
+ "user_data = %p);",
(void *)domain, err, conn_num, port_num, still_connected, user_data);
- status = ipmi_domain_add_entity_update_handler(
- domain, domain_entity_update_handler, /* user data = */ NULL);
- if (status != 0) {
- c_ipmi_error("ipmi_domain_add_entity_update_handler", status);
+ c_ipmi_instance_t *st = user_data;
+
+ if (err != 0)
+ c_ipmi_error(st, "domain_connection_change_handler", err);
+
+ if (!still_connected) {
+
+ if (st->notify_conn && st->connected && st->init_in_progress == 0) {
+ notification_t n = c_ipmi_notification_init(st, NOTIF_FAILURE);
+
+ sstrncpy(n.message, "IPMI connection lost", sizeof(n.plugin));
+
+ plugin_dispatch_notification(&n);
+ }
+
+ st->connected = 0;
+ return;
}
-} /* void domain_connection_change_handler */
-static int thread_init(os_handler_t **ret_os_handler) {
- os_handler_t *os_handler;
- ipmi_con_t *smi_connection = NULL;
- ipmi_domain_id_t domain_id;
- int status;
+ if (st->notify_conn && !st->connected && st->init_in_progress == 0) {
+ notification_t n = c_ipmi_notification_init(st, NOTIF_OKAY);
- os_handler = ipmi_posix_thread_setup_os_handler(SIGIO);
- if (os_handler == NULL) {
- ERROR("ipmi plugin: ipmi_posix_thread_setup_os_handler failed.");
- return -1;
+ sstrncpy(n.message, "IPMI connection restored", sizeof(n.plugin));
+
+ plugin_dispatch_notification(&n);
}
- ipmi_init(os_handler);
+ st->connected = 1;
- status = ipmi_smi_setup_con(/* if_num = */ 0, os_handler,
- /* user data = */ NULL, &smi_connection);
+ int status = ipmi_domain_add_entity_update_handler(
+ domain, domain_entity_update_handler, /* user data = */ st);
if (status != 0) {
- c_ipmi_error("ipmi_smi_setup_con", status);
- return -1;
+ c_ipmi_error(st, "ipmi_domain_add_entity_update_handler", status);
}
- ipmi_open_option_t open_option[1] = {[0] = {.option = IPMI_OPEN_OPTION_ALL,
- {.ival = 1}}};
+ status = st->connection->add_event_handler(st->connection, smi_event_handler,
+ (void *)domain);
+
+ if (status != 0)
+ c_ipmi_error(st, "Failed to register smi event handler", status);
+} /* void domain_connection_change_handler */
+
+static int c_ipmi_thread_init(c_ipmi_instance_t *st) {
+ ipmi_domain_id_t domain_id;
+ int status;
+
+ if (st->connaddr != NULL) {
+ status = ipmi_ip_setup_con(
+ &st->connaddr, &(char *){IPMI_LAN_STD_PORT_STR}, 1, st->authtype,
+ (unsigned int)IPMI_PRIVILEGE_USER, st->username, strlen(st->username),
+ st->password, strlen(st->password), os_handler,
+ /* user data = */ NULL, &st->connection);
+ if (status != 0) {
+ c_ipmi_error(st, "ipmi_ip_setup_con", status);
+ return -1;
+ }
+ } else {
+ status = ipmi_smi_setup_con(/* if_num = */ 0, os_handler,
+ /* user data = */ NULL, &st->connection);
+ if (status != 0) {
+ c_ipmi_error(st, "ipmi_smi_setup_con", status);
+ return -1;
+ }
+ }
+ ipmi_open_option_t opts[] = {
+ {.option = IPMI_OPEN_OPTION_ALL, {.ival = 1}},
+#ifdef IPMI_OPEN_OPTION_USE_CACHE
+ /* OpenIPMI-2.0.17 and later: Disable SDR cache in local file */
+ {.option = IPMI_OPEN_OPTION_USE_CACHE, {.ival = 0}},
+#endif
+ };
+
+ /*
+ * NOTE: Domain names must be unique. There is static `domains_list` common
+ * to all threads inside lib/domain.c and some ops are done by name.
+ */
status = ipmi_open_domain(
- "mydomain", &smi_connection, /* num_con = */ 1,
- domain_connection_change_handler, /* user data = */ NULL,
- /* domain_fully_up_handler = */ NULL, /* user data = */ NULL, open_option,
- sizeof(open_option) / sizeof(open_option[0]), &domain_id);
+ st->name, &st->connection, /* num_con = */ 1,
+ domain_connection_change_handler, /* user data = */ (void *)st,
+ /* domain_fully_up_handler = */ NULL, /* user data = */ NULL, opts,
+ STATIC_ARRAY_SIZE(opts), &domain_id);
if (status != 0) {
- c_ipmi_error("ipmi_open_domain", status);
+ c_ipmi_error(st, "ipmi_open_domain", status);
return -1;
}
- *ret_os_handler = os_handler;
return 0;
-} /* int thread_init */
+} /* int c_ipmi_thread_init */
-static void *thread_main(void __attribute__((unused)) * user_data) {
- int status;
- os_handler_t *os_handler = NULL;
+static void *c_ipmi_thread_main(void *user_data) {
+ c_ipmi_instance_t *st = user_data;
- status = thread_init(&os_handler);
+ int status = c_ipmi_thread_init(st);
if (status != 0) {
- ERROR("ipmi plugin: thread_init failed.\n");
+ ERROR("ipmi plugin: c_ipmi_thread_init failed.");
+ st->active = 0;
return (void *)-1;
}
- while (c_ipmi_active != 0) {
+ while (st->active != 0) {
struct timeval tv = {1, 0};
os_handler->perform_one_op(os_handler, &tv);
}
+ return (void *)0;
+} /* void *c_ipmi_thread_main */
- ipmi_posix_thread_free_os_handler(os_handler);
+static c_ipmi_instance_t *c_ipmi_init_instance() {
+ c_ipmi_instance_t *st;
- return (void *)0;
-} /* void *thread_main */
-
-static int c_ipmi_config(const char *key, const char *value) {
- if (ignorelist == NULL)
- ignorelist = ignorelist_create(/* invert = */ 1);
- if (ignorelist == NULL)
- return 1;
-
- if (strcasecmp("Sensor", key) == 0) {
- ignorelist_add(ignorelist, value);
- } else if (strcasecmp("IgnoreSelected", key) == 0) {
- int invert = 1;
- if (IS_TRUE(value))
- invert = 0;
- ignorelist_set_invert(ignorelist, invert);
- } else if (strcasecmp("NotifySensorAdd", key) == 0) {
- if (IS_TRUE(value))
- c_ipmi_nofiy_add = 1;
- } else if (strcasecmp("NotifySensorRemove", key) == 0) {
- if (IS_TRUE(value))
- c_ipmi_nofiy_remove = 1;
- } else if (strcasecmp("NotifySensorNotPresent", key) == 0) {
- if (IS_TRUE(value))
- c_ipmi_nofiy_notpresent = 1;
- } else {
- return -1;
+ st = calloc(1, sizeof(*st));
+ if (st == NULL) {
+ ERROR("ipmi plugin: calloc failed.");
+ return NULL;
}
- return 0;
-} /* int c_ipmi_config */
+ st->name = strdup("main");
+ if (st->name == NULL) {
+ sfree(st);
+ ERROR("ipmi plugin: strdup() failed.");
+ return NULL;
+ }
-static int c_ipmi_init(void) {
- int status;
+ st->ignorelist = ignorelist_create(/* invert = */ 1);
+ if (st->ignorelist == NULL) {
+ sfree(st->name);
+ sfree(st);
+ ERROR("ipmi plugin: ignorelist_create() failed.");
+ return NULL;
+ }
- /* Don't send `ADD' notifications during startup (~ 1 minute) */
- time_t iv = CDTIME_T_TO_TIME_T(plugin_get_interval());
- c_ipmi_init_in_progress = 1 + (60 / iv);
+ st->sensor_list = NULL;
+ pthread_mutex_init(&st->sensor_list_lock, /* attr = */ NULL);
+
+ st->host = NULL;
+ st->connaddr = NULL;
+ st->username = NULL;
+ st->password = NULL;
+ st->authtype = IPMI_AUTHTYPE_DEFAULT;
+
+ st->next = NULL;
+
+ return st;
+} /* c_ipmi_instance_t *c_ipmi_init_instance */
+
+static void c_ipmi_free_instance(c_ipmi_instance_t *st) {
+ if (st == NULL)
+ return;
- c_ipmi_active = 1;
+ assert(st->next == NULL);
+
+ sfree(st->name);
+ sfree(st->host);
+ sfree(st->connaddr);
+ sfree(st->username);
+ sfree(st->password);
+
+ ignorelist_free(st->ignorelist);
+ pthread_mutex_destroy(&st->sensor_list_lock);
+ sfree(st);
+} /* void c_ipmi_free_instance */
+
+static void c_ipmi_add_instance(c_ipmi_instance_t *instance) {
+ if (instances == NULL) {
+ instances = instance;
+ return;
+ }
+
+ c_ipmi_instance_t *last = instances;
+
+ while (last->next != NULL)
+ last = last->next;
+
+ last->next = instance;
+} /* void c_ipmi_add_instance */
+
+static int c_ipmi_config_add_instance(oconfig_item_t *ci) {
+ int status = 0;
+ c_ipmi_instance_t *st = c_ipmi_init_instance();
+ if (st == NULL)
+ return ENOMEM;
+
+ if (strcasecmp(ci->key, "Instance") == 0)
+ status = cf_util_get_string(ci, &st->name);
- status = plugin_thread_create(&thread_id, /* attr = */ NULL, thread_main,
- /* user data = */ NULL, "ipmi");
if (status != 0) {
- c_ipmi_active = 0;
- thread_id = (pthread_t)0;
- ERROR("ipmi plugin: pthread_create failed.");
- return -1;
+ c_ipmi_free_instance(st);
+ return status;
+ }
+
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp("Sensor", child->key) == 0)
+ ignorelist_add(st->ignorelist, child->values[0].value.string);
+ else if (strcasecmp("IgnoreSelected", child->key) == 0) {
+ _Bool t;
+ status = cf_util_get_boolean(child, &t);
+ if (status != 0)
+ break;
+ ignorelist_set_invert(st->ignorelist, /* invert = */ !t);
+ } else if (strcasecmp("NotifyIPMIConnectionState", child->key) == 0) {
+ status = cf_util_get_boolean(child, &st->notify_conn);
+ } else if (strcasecmp("NotifySensorAdd", child->key) == 0) {
+ status = cf_util_get_boolean(child, &st->notify_add);
+ } else if (strcasecmp("NotifySensorRemove", child->key) == 0) {
+ status = cf_util_get_boolean(child, &st->notify_remove);
+ } else if (strcasecmp("NotifySensorNotPresent", child->key) == 0) {
+ status = cf_util_get_boolean(child, &st->notify_notpresent);
+ } else if (strcasecmp("SELEnabled", child->key) == 0) {
+ status = cf_util_get_boolean(child, &st->sel_enabled);
+ } else if (strcasecmp("SELClearEvent", child->key) == 0) {
+ status = cf_util_get_boolean(child, &st->sel_clear_event);
+ } else if (strcasecmp("Host", child->key) == 0)
+ status = cf_util_get_string(child, &st->host);
+ else if (strcasecmp("Address", child->key) == 0)
+ status = cf_util_get_string(child, &st->connaddr);
+ else if (strcasecmp("Username", child->key) == 0)
+ status = cf_util_get_string(child, &st->username);
+ else if (strcasecmp("Password", child->key) == 0)
+ status = cf_util_get_string(child, &st->password);
+ else if (strcasecmp("AuthType", child->key) == 0) {
+ char tmp[8];
+ status = cf_util_get_string_buffer(child, tmp, sizeof(tmp));
+ if (status != 0)
+ break;
+
+ if (strcasecmp("MD5", tmp) == 0)
+ st->authtype = IPMI_AUTHTYPE_MD5;
+ else if (strcasecmp("rmcp+", tmp) == 0)
+ st->authtype = IPMI_AUTHTYPE_RMCP_PLUS;
+ else
+ WARNING("ipmi plugin: The value \"%s\" is not valid for the "
+ "\"AuthType\" option.",
+ tmp);
+ } else {
+ WARNING("ipmi plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ if (status != 0) {
+ c_ipmi_free_instance(st);
+ return status;
}
+ c_ipmi_add_instance(st);
+
return 0;
-} /* int c_ipmi_init */
+} /* int c_ipmi_config_add_instance */
+
+static int c_ipmi_config(oconfig_item_t *ci) {
+ _Bool have_instance_block = 0;
+
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp("Instance", child->key) == 0) {
+ int status = c_ipmi_config_add_instance(child);
+ if (status != 0)
+ return status;
+
+ have_instance_block = 1;
+ } else if (!have_instance_block) {
+ /* Non-instance option: Assume legacy configuration (without <Instance />
+ * blocks) and call c_ipmi_config_add_instance with the <Plugin /> block.
+ */
+ WARNING("ipmi plugin: Legacy configuration found! Please update your "
+ "config file.");
+ return c_ipmi_config_add_instance(ci);
+ } else {
+ WARNING("ipmi plugin: The configuration option "
+ "\"%s\" is not allowed here. Did you "
+ "forget to add an <Instance /> block "
+ "around the configuration?",
+ child->key);
+ return -1;
+ }
+ } /* for (ci->children) */
+
+ return 0;
+} /* int c_ipmi_config */
-static int c_ipmi_read(void) {
- if ((c_ipmi_active == 0) || (thread_id == (pthread_t)0)) {
+static int c_ipmi_read(user_data_t *user_data) {
+ c_ipmi_instance_t *st = user_data->data;
+
+ if (st->active == 0) {
INFO("ipmi plugin: c_ipmi_read: I'm not active, returning false.");
return -1;
}
- sensor_list_read_all();
+ if (st->connected == 0)
+ return 0;
+
+ sensor_list_read_all(st);
- if (c_ipmi_init_in_progress > 0)
- c_ipmi_init_in_progress--;
+ if (st->init_in_progress > 0)
+ st->init_in_progress--;
else
- c_ipmi_init_in_progress = 0;
+ st->init_in_progress = 0;
return 0;
} /* int c_ipmi_read */
+static int c_ipmi_init(void) {
+ c_ipmi_instance_t *st;
+ char callback_name[3 * DATA_MAX_NAME_LEN];
+
+ if (os_handler != NULL) {
+ return 0;
+ }
+
+ os_handler = ipmi_posix_thread_setup_os_handler(SIGIO);
+ if (os_handler == NULL) {
+ ERROR("ipmi plugin: ipmi_posix_thread_setup_os_handler failed.");
+ return -1;
+ }
+
+ os_handler->set_log_handler(os_handler, c_ipmi_log);
+
+ if (ipmi_init(os_handler) != 0) {
+ ERROR("ipmi plugin: ipmi_init() failed.");
+ os_handler->free_os_handler(os_handler);
+ return -1;
+ };
+
+ if (instances == NULL) {
+ /* No instances were configured, let's start a default instance. */
+ st = c_ipmi_init_instance();
+ if (st == NULL)
+ return ENOMEM;
+
+ c_ipmi_add_instance(st);
+ }
+
+ /* Don't send `ADD' notifications during startup (~ 1 minute) */
+ int cycles = 1 + (int)(TIME_T_TO_CDTIME_T(60) / plugin_get_interval());
+
+ st = instances;
+ while (NULL != st) {
+ /* The `st->name` is used as "domain name" for ipmi_open_domain().
+ * That value should be unique, so we do plugin_register_complex_read()
+ * at first as it checks the uniqueness. */
+ snprintf(callback_name, sizeof(callback_name), "ipmi/%s", st->name);
+
+ user_data_t ud = {
+ .data = st,
+ };
+
+ int status = plugin_register_complex_read(
+ /* group = */ "ipmi",
+ /* name = */ callback_name,
+ /* callback = */ c_ipmi_read,
+ /* interval = */ 0,
+ /* user_data = */ &ud);
+
+ if (status != 0) {
+ st = st->next;
+ continue;
+ }
+
+ st->init_in_progress = cycles;
+ st->active = 1;
+
+ status = plugin_thread_create(&st->thread_id, /* attr = */ NULL,
+ c_ipmi_thread_main,
+ /* user data = */ (void *)st, "ipmi");
+
+ if (status != 0) {
+ st->active = 0;
+ st->thread_id = (pthread_t){0};
+
+ plugin_unregister_read(callback_name);
+
+ ERROR("ipmi plugin: pthread_create failed for `%s`.", callback_name);
+ }
+
+ st = st->next;
+ }
+
+ return 0;
+} /* int c_ipmi_init */
+
static int c_ipmi_shutdown(void) {
- c_ipmi_active = 0;
+ c_ipmi_instance_t *st = instances;
+ instances = NULL;
+
+ while (st != NULL) {
+ c_ipmi_instance_t *next = st->next;
+
+ st->next = NULL;
+ st->active = 0;
+
+ if (!pthread_equal(st->thread_id, (pthread_t){0})) {
+ pthread_join(st->thread_id, NULL);
+ st->thread_id = (pthread_t){0};
+ }
+
+ sensor_list_remove_all(st);
+ c_ipmi_free_instance(st);
- if (thread_id != (pthread_t)0) {
- pthread_join(thread_id, NULL);
- thread_id = (pthread_t)0;
+ st = next;
}
- sensor_list_remove_all();
+ os_handler->free_os_handler(os_handler);
+ os_handler = NULL;
return 0;
} /* int c_ipmi_shutdown */
void module_register(void) {
- plugin_register_config("ipmi", c_ipmi_config, config_keys, config_keys_num);
+ plugin_register_complex_config("ipmi", c_ipmi_config);
plugin_register_init("ipmi", c_ipmi_init);
- plugin_register_read("ipmi", c_ipmi_read);
plugin_register_shutdown("ipmi", c_ipmi_shutdown);
} /* void module_register */
value_copy = strdup(value);
if (value_copy == NULL) {
- char errbuf[1024];
- ERROR("strdup failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("strdup failed: %s", STRERRNO);
return 1;
}
list = realloc(chain_list, (chain_num + 1) * sizeof(ip_chain_t *));
if (list == NULL) {
- char errbuf[1024];
- ERROR("realloc failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("realloc failed: %s", STRERRNO);
sfree(temp.rule.comment);
return 1;
}
chain_list = list;
final = malloc(sizeof(*final));
if (final == NULL) {
- char errbuf[1024];
- ERROR("malloc failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("malloc failed: %s", STRERRNO);
sfree(temp.rule.comment);
return 1;
}
if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, &ipvs_info, &len) ==
-1) {
- char errbuf[1024];
- log_err("ip_vs_get_services: getsockopt() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("ip_vs_get_services: getsockopt() failed: %s", STRERRNO);
return NULL;
}
if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICES, services, &len) ==
-1) {
- char errbuf[1024];
- log_err("ipvs_get_services: getsockopt failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("ipvs_get_services: getsockopt failed: %s", STRERRNO);
free(services);
return NULL;
dests->num_dests = se->num_dests;
if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_DESTS, dests, &len) == -1) {
- char errbuf[1024];
- log_err("ipvs_get_dests: getsockopt() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("ipvs_get_dests: getsockopt() failed: %s", STRERRNO);
free(dests);
return NULL;
}
struct ip_vs_getinfo ipvs_info;
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
- char errbuf[1024];
- log_err("cipvs_init: socket() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("cipvs_init: socket() failed: %s", STRERRNO);
return -1;
}
if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_INFO, &ipvs_info, &len) ==
-1) {
- char errbuf[1024];
- log_err("cipvs_init: getsockopt() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("cipvs_init: getsockopt() failed: %s", STRERRNO);
close(sockfd);
sockfd = -1;
return -1;
*/
fh = fopen("/proc/interrupts", "r");
if (fh == NULL) {
- char errbuf[1024];
- ERROR("irq plugin: fopen (/proc/interrupts): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("irq plugin: fopen (/proc/interrupts): %s", STRERRNO);
return -1;
}
vm_args.nOptions = (jint)jvm_argc;
for (size_t i = 0; i < jvm_argc; i++) {
- DEBUG("java plugin: cjni_create_jvm: jvm_argv[%zu] = %s", i, jvm_argv[i]);
+ DEBUG("java plugin: cjni_create_jvm: jvm_argv[%" PRIsz "] = %s", i,
+ jvm_argv[i]);
vm_args.options[i].optionString = jvm_argv[i];
}
}
}
- DEBUG("java plugin: jvm_argc = %zu;", jvm_argc);
- DEBUG("java plugin: java_classes_list_len = %zu;", java_classes_list_len);
+ DEBUG("java plugin: jvm_argc = %" PRIsz ";", jvm_argc);
+ DEBUG("java plugin: java_classes_list_len = %" PRIsz ";",
+ java_classes_list_len);
if ((success == 0) && (errors > 0)) {
ERROR("java plugin: All statements failed.");
* Florian octo Forster <octo at collectd.org>
**/
-#if HAVE_CONFIG_H
#include "config.h"
-#endif
#if !defined(__GNUC__) || !__GNUC__
#define __attribute__(x) /**/
#ifndef LIBCOLLECTD_COLLECTDCLIENT_H
#define LIBCOLLECTD_COLLECTDCLIENT_H 1
-#include "lcc_features.h"
+#include "collectd/lcc_features.h"
+#include "collectd/types.h"
/* COLLECTD_TRACE is the environment variable used to control trace output. When
* set to something non-zero, all lines sent to / received from the daemon are
/*
* Includes (for data types)
*/
-#include <stdint.h>
#include <inttypes.h>
+#include <stdint.h>
#include <time.h>
-/*
- * Defines
- */
-#define LCC_NAME_LEN 64
-#define LCC_DEFAULT_PORT "25826"
-
-/*
- * Types
- */
-#define LCC_TYPE_COUNTER 0
-#define LCC_TYPE_GAUGE 1
-#define LCC_TYPE_DERIVE 2
-#define LCC_TYPE_ABSOLUTE 3
-
LCC_BEGIN_DECLS
-typedef uint64_t counter_t;
-typedef double gauge_t;
-typedef uint64_t derive_t;
-typedef uint64_t absolute_t;
-
-union value_u {
- counter_t counter;
- gauge_t gauge;
- derive_t derive;
- absolute_t absolute;
-};
-typedef union value_u value_t;
-
-struct lcc_identifier_s {
- char host[LCC_NAME_LEN];
- char plugin[LCC_NAME_LEN];
- char plugin_instance[LCC_NAME_LEN];
- char type[LCC_NAME_LEN];
- char type_instance[LCC_NAME_LEN];
-};
-typedef struct lcc_identifier_s lcc_identifier_t;
-#define LCC_IDENTIFIER_INIT \
- { "localhost", "", "", "", "" }
-
-struct lcc_value_list_s {
- value_t *values;
- int *values_types;
- size_t values_len;
- double time;
- double interval;
- lcc_identifier_t identifier;
-};
-typedef struct lcc_value_list_s lcc_value_list_t;
-#define LCC_VALUE_LIST_INIT \
- { NULL, NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
-
struct lcc_connection_s;
typedef struct lcc_connection_s lcc_connection_t;
#ifndef LIBCOLLECTDCLIENT_NETWORK_H
#define LIBCOLLECTDCLIENT_NETWORK_H 1
+#include "collectd/client.h"
+
#include <inttypes.h>
#include <stdint.h>
-#include "client.h"
-
#define NET_DEFAULT_V4_ADDR "239.192.74.66"
#define NET_DEFAULT_V6_ADDR "ff18::efc0:4a42"
#define NET_DEFAULT_PORT "25826"
#ifndef LIBCOLLECTDCLIENT_NETWORK_BUFFER_H
#define LIBCOLLECTDCLIENT_NETWORK_BUFFER_H 1
-/* FIXME */
-#include "client.h"
-#include "network.h"
+#include "config.h"
+
+#include "collectd/network.h" /* for lcc_security_level_t */
+#include "collectd/types.h"
/* Ethernet frame - (IPv6 header + UDP header) */
#define LCC_NETWORK_BUFFER_SIZE_DEFAULT 1452
--- /dev/null
+/**
+ * Copyright 2017 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef LIBCOLLECTD_NETWORK_PARSE_H
+#define LIBCOLLECTD_NETWORK_PARSE_H 1
+
+#include "collectd/lcc_features.h"
+
+#include "collectd/network.h" /* for lcc_security_level_t */
+#include "collectd/types.h"
+
+#include <stdint.h>
+
+LCC_BEGIN_DECLS
+
+typedef struct {
+ /* writer is the callback used to send incoming lcc_value_list_t to. */
+ lcc_value_list_writer_t writer;
+
+ /* password_lookup is used to look up the password for a given username. */
+ lcc_password_lookup_t password_lookup;
+
+ /* security_level is the minimal required security level. */
+ lcc_security_level_t security_level;
+} lcc_network_parse_options_t;
+
+/* lcc_network_parse parses data received from the network and calls "w" with
+ * the parsed lcc_value_list_ts. */
+int lcc_network_parse(void *buffer, size_t buffer_size,
+ lcc_network_parse_options_t opts);
+
+LCC_END_DECLS
+
+#endif /* LIBCOLLECTD_NETWORK_PARSE_H */
--- /dev/null
+/**
+ * Copyright 2017 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef LIBCOLLECTD_SERVER_H
+#define LIBCOLLECTD_SERVER_H 1
+
+#include "collectd/lcc_features.h"
+
+#include "collectd/network.h" /* for lcc_security_level_t */
+#include "collectd/network_parse.h" /* for lcc_network_parse_options_t */
+#include "collectd/types.h"
+
+#include <stdint.h>
+
+#ifndef LCC_NETWORK_BUFFER_SIZE
+#define LCC_NETWORK_BUFFER_SIZE 1452
+#endif
+
+LCC_BEGIN_DECLS
+
+/* lcc_network_parser_t is a callback that parses received network packets. It
+ * is expected to call lcc_network_parse_options_t.writer with each
+ * lcc_value_list_t it parses that has the required security level. */
+typedef int (*lcc_network_parser_t)(void *payload, size_t payload_size,
+ lcc_network_parse_options_t opts);
+
+/* lcc_listener_t holds parameters for running a collectd server. */
+typedef struct {
+ /* conn is a UDP socket for the server to listen on. If set to <0 node and
+ * service will be used to open a new UDP socket. If >=0, it is the caller's
+ * job to clean up the socket. */
+ int conn;
+
+ /* node is the local address to listen on if conn is <0. Defaults to "::" (any
+ * address). */
+ char *node;
+
+ /* service is the local address to listen on if conn is <0. Defaults to
+ * LCC_DEFAULT_PORT. */
+ char *service;
+
+ /* parser is the callback used to parse incoming network packets. Defaults to
+ * lcc_network_parse() if set to NULL. */
+ lcc_network_parser_t parser;
+
+ /* parse_options contains options for parser and is passed on verbatimely. */
+ lcc_network_parse_options_t parse_options;
+
+ /* buffer_size determines the maximum packet size to accept. Defaults to
+ * LCC_NETWORK_BUFFER_SIZE if set to zero. */
+ uint16_t buffer_size;
+
+ /* interface is the name of the interface to use when subscribing to a
+ * multicast group. Has no effect when using unicast. */
+ char *interface;
+} lcc_listener_t;
+
+/* lcc_listen_and_write listens on the provided UDP socket (or opens one using
+ * srv.addr if srv.conn is less than zero), parses the received packets and
+ * writes them to the provided lcc_value_list_writer_t. Returns non-zero on
+ * failure and does not return otherwise. */
+int lcc_listen_and_write(lcc_listener_t srv);
+
+LCC_END_DECLS
+
+#endif /* LIBCOLLECTD_SERVER_H */
--- /dev/null
+/**
+ * libcollectdclient - src/libcollectdclient/collectd/types.h
+ * Copyright (C) 2008-2017 Florian octo Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#ifndef LIBCOLLECTD_COLLECTD_TYPES_H
+#define LIBCOLLECTD_COLLECTD_TYPES_H 1
+
+#include "collectd/lcc_features.h"
+
+#include <stdint.h> /* for uint64_t */
+#include <sys/types.h> /* for size_t */
+
+/*
+ * Defines
+ */
+#define LCC_NAME_LEN 64
+#define LCC_DEFAULT_PORT "25826"
+
+/*
+ * Types
+ */
+#define LCC_TYPE_COUNTER 0
+#define LCC_TYPE_GAUGE 1
+#define LCC_TYPE_DERIVE 2
+#define LCC_TYPE_ABSOLUTE 3
+
+LCC_BEGIN_DECLS
+
+typedef uint64_t counter_t;
+typedef double gauge_t;
+typedef uint64_t derive_t;
+typedef uint64_t absolute_t;
+
+union value_u {
+ counter_t counter;
+ gauge_t gauge;
+ derive_t derive;
+ absolute_t absolute;
+};
+typedef union value_u value_t;
+
+struct lcc_identifier_s {
+ char host[LCC_NAME_LEN];
+ char plugin[LCC_NAME_LEN];
+ char plugin_instance[LCC_NAME_LEN];
+ char type[LCC_NAME_LEN];
+ char type_instance[LCC_NAME_LEN];
+};
+typedef struct lcc_identifier_s lcc_identifier_t;
+#define LCC_IDENTIFIER_INIT \
+ { "localhost", "", "", "", "" }
+
+struct lcc_value_list_s {
+ value_t *values;
+ int *values_types;
+ size_t values_len;
+ double time;
+ double interval;
+ lcc_identifier_t identifier;
+};
+typedef struct lcc_value_list_s lcc_value_list_t;
+#define LCC_VALUE_LIST_INIT \
+ { NULL, NULL, 0, 0, 0, LCC_IDENTIFIER_INIT }
+
+/* lcc_value_list_writer_t is a write callback to which value lists are
+ * dispatched. */
+typedef int (*lcc_value_list_writer_t)(lcc_value_list_t const *);
+
+/* lcc_password_lookup_t is a callback for looking up the password for a given
+ * user. Must return NULL if the user is not known. */
+typedef char const *(*lcc_password_lookup_t)(char const *);
+
+LCC_END_DECLS
+
+#endif /* LIBCOLLECTD_COLLECTD_TYPES_H */
static int nb_add_values(char **ret_buffer, /* {{{ */
size_t *ret_buffer_len, const lcc_value_list_t *vl) {
+ if ((vl == NULL) || (vl->values_len < 1)) {
+ return EINVAL;
+ }
+
char *packet_ptr;
size_t packet_len;
--- /dev/null
+/**
+ * Copyright 2017 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "config.h"
+
+#if !defined(__GNUC__) || !__GNUC__
+#define __attribute__(x) /**/
+#endif
+
+#include "collectd/lcc_features.h"
+#include "collectd/network_parse.h"
+#include "globals.h"
+
+#include <errno.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* for be{16,64}toh */
+#if HAVE_ENDIAN_H
+#include <endian.h>
+#elif HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#else /* fallback */
+__attribute__((const)) static uint16_t be16toh(uint16_t n) {
+ uint8_t tmp[2];
+ memmove(tmp, &n, sizeof(tmp));
+
+ return ((uint16_t)tmp[0] << 8) | ((uint16_t)tmp[1] << 0);
+}
+
+__attribute__((const)) static uint64_t be64toh(uint64_t n) {
+ uint8_t tmp[8];
+ memmove(tmp, &n, sizeof(tmp));
+
+ return ((uint64_t)tmp[0] << 56) | ((uint64_t)tmp[1] << 48) |
+ ((uint64_t)tmp[2] << 40) | ((uint64_t)tmp[3] << 32) |
+ ((uint64_t)tmp[4] << 24) | ((uint64_t)tmp[5] << 16) |
+ ((uint64_t)tmp[6] << 8) | ((uint64_t)tmp[7] << 0);
+}
+#endif
+
+#if HAVE_GCRYPT_H
+#define GCRYPT_NO_DEPRECATED
+#include <gcrypt.h>
+#endif
+
+#include <stdio.h>
+#define DEBUG(...) printf(__VA_ARGS__)
+
+#if HAVE_GCRYPT_H
+#if GCRYPT_VERSION_NUMBER < 0x010600
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+#endif
+#endif
+
+/* forward declaration because parse_sign_sha256()/parse_encrypt_aes256() and
+ * network_parse() need to call each other. */
+static int network_parse(void *data, size_t data_size, lcc_security_level_t sl,
+ lcc_network_parse_options_t const *opts);
+
+#if HAVE_GCRYPT_H
+static int init_gcrypt() {
+ /* http://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html
+ * Because you can't know in a library whether another library has
+ * already initialized the library */
+ if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P))
+ return (0);
+
+/* http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
+ * To ensure thread-safety, it's important to set GCRYCTL_SET_THREAD_CBS
+ * *before* initalizing Libgcrypt with gcry_check_version(), which itself must
+ * be called before any other gcry_* function. GCRYCTL_ANY_INITIALIZATION_P
+ * above doesn't count, as it doesn't implicitly initalize Libgcrypt.
+ *
+ * tl;dr: keep all these gry_* statements in this exact order please. */
+#if GCRYPT_VERSION_NUMBER < 0x010600
+ if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread)) {
+ return -1;
+ }
+#endif
+
+ gcry_check_version(NULL);
+
+ if (gcry_control(GCRYCTL_INIT_SECMEM, 32768)) {
+ return -1;
+ }
+
+ gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
+ return 0;
+}
+#endif
+
+typedef struct {
+ uint8_t *data;
+ size_t len;
+} buffer_t;
+
+static int buffer_next(buffer_t *b, void *out, size_t n) {
+ if (b->len < n) {
+ return -1;
+ }
+ memmove(out, b->data, n);
+
+ b->data += n;
+ b->len -= n;
+
+ return 0;
+}
+
+static int buffer_uint16(buffer_t *b, uint16_t *out) {
+ uint16_t tmp;
+ if (buffer_next(b, &tmp, sizeof(tmp)) != 0)
+ return -1;
+
+ *out = be16toh(tmp);
+ return 0;
+}
+
+#define TYPE_HOST 0x0000
+#define TYPE_TIME 0x0001
+#define TYPE_TIME_HR 0x0008
+#define TYPE_PLUGIN 0x0002
+#define TYPE_PLUGIN_INSTANCE 0x0003
+#define TYPE_TYPE 0x0004
+#define TYPE_TYPE_INSTANCE 0x0005
+#define TYPE_VALUES 0x0006
+#define TYPE_INTERVAL 0x0007
+#define TYPE_INTERVAL_HR 0x0009
+#define TYPE_SIGN_SHA256 0x0200
+#define TYPE_ENCR_AES256 0x0210
+
+static int parse_int(void *payload, size_t payload_size, uint64_t *out) {
+ uint64_t tmp;
+
+ if (payload_size != sizeof(tmp))
+ return EINVAL;
+
+ memmove(&tmp, payload, sizeof(tmp));
+ *out = be64toh(tmp);
+ return 0;
+}
+
+static int parse_string(void *payload, size_t payload_size, char *out,
+ size_t out_size) {
+ char *in = payload;
+
+ if ((payload_size < 1) || (in[payload_size - 1] != 0) ||
+ (payload_size > out_size))
+ return EINVAL;
+
+ strncpy(out, in, out_size);
+ return 0;
+}
+
+static int parse_identifier(uint16_t type, void *payload, size_t payload_size,
+ lcc_value_list_t *state) {
+ char buf[LCC_NAME_LEN];
+
+ if (parse_string(payload, payload_size, buf, sizeof(buf)) != 0)
+ return EINVAL;
+
+ switch (type) {
+ case TYPE_HOST:
+ memmove(state->identifier.host, buf, LCC_NAME_LEN);
+ break;
+ case TYPE_PLUGIN:
+ memmove(state->identifier.plugin, buf, LCC_NAME_LEN);
+ break;
+ case TYPE_PLUGIN_INSTANCE:
+ memmove(state->identifier.plugin_instance, buf, LCC_NAME_LEN);
+ break;
+ case TYPE_TYPE:
+ memmove(state->identifier.type, buf, LCC_NAME_LEN);
+ break;
+ case TYPE_TYPE_INSTANCE:
+ memmove(state->identifier.type_instance, buf, LCC_NAME_LEN);
+ break;
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static int parse_time(uint16_t type, void *payload, size_t payload_size,
+ lcc_value_list_t *state) {
+ uint64_t tmp = 0;
+ if (parse_int(payload, payload_size, &tmp))
+ return EINVAL;
+
+ double t = (double)tmp;
+ switch (type) {
+ case TYPE_INTERVAL:
+ state->interval = t;
+ break;
+ case TYPE_INTERVAL_HR:
+ state->interval = t / 1073741824.0;
+ break;
+ case TYPE_TIME:
+ state->time = t;
+ break;
+ case TYPE_TIME_HR:
+ state->time = t / 1073741824.0;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static double ntohd(double val) /* {{{ */
+{
+ static int config = 0;
+
+ union {
+ uint8_t byte[8];
+ double floating;
+ } in = {
+ .floating = val,
+ };
+ union {
+ uint8_t byte[8];
+ double floating;
+ } out = {
+ .byte = {0},
+ };
+
+ if (config == 0) {
+ double d = 8.642135e130;
+ uint8_t b[8];
+
+ memcpy(b, &d, sizeof(b));
+
+ if ((b[0] == 0x2f) && (b[1] == 0x25) && (b[2] == 0xc0) && (b[3] == 0xc7) &&
+ (b[4] == 0x43) && (b[5] == 0x2b) && (b[6] == 0x1f) && (b[7] == 0x5b))
+ config = 1; /* need nothing */
+ else if ((b[7] == 0x2f) && (b[6] == 0x25) && (b[5] == 0xc0) &&
+ (b[4] == 0xc7) && (b[3] == 0x43) && (b[2] == 0x2b) &&
+ (b[1] == 0x1f) && (b[0] == 0x5b))
+ config = 2; /* endian flip */
+ else if ((b[4] == 0x2f) && (b[5] == 0x25) && (b[6] == 0xc0) &&
+ (b[7] == 0xc7) && (b[0] == 0x43) && (b[1] == 0x2b) &&
+ (b[2] == 0x1f) && (b[3] == 0x5b))
+ config = 3; /* int swap */
+ else
+ config = 4;
+ }
+
+ if (memcmp((char[]){0, 0, 0, 0, 0, 0, 0xf8, 0x7f}, in.byte, 8) == 0) {
+ return NAN;
+ } else if (config == 1) {
+ return val;
+ } else if (config == 2) {
+ in.floating = val;
+ out.byte[0] = in.byte[7];
+ out.byte[1] = in.byte[6];
+ out.byte[2] = in.byte[5];
+ out.byte[3] = in.byte[4];
+ out.byte[4] = in.byte[3];
+ out.byte[5] = in.byte[2];
+ out.byte[6] = in.byte[1];
+ out.byte[7] = in.byte[0];
+ return (out.floating);
+ } else if (config == 3) {
+ in.floating = val;
+ out.byte[0] = in.byte[4];
+ out.byte[1] = in.byte[5];
+ out.byte[2] = in.byte[6];
+ out.byte[3] = in.byte[7];
+ out.byte[4] = in.byte[0];
+ out.byte[5] = in.byte[1];
+ out.byte[6] = in.byte[2];
+ out.byte[7] = in.byte[3];
+ return out.floating;
+ } else {
+ /* If in doubt, just copy the value back to the caller. */
+ return val;
+ }
+} /* }}} double ntohd */
+
+static int parse_values(void *payload, size_t payload_size,
+ lcc_value_list_t *state) {
+ buffer_t *b = &(buffer_t){
+ .data = payload, .len = payload_size,
+ };
+
+ uint16_t n;
+ if (buffer_uint16(b, &n))
+ return EINVAL;
+
+ if (((size_t)n * 9) != b->len)
+ return EINVAL;
+
+ state->values_len = (size_t)n;
+ state->values = calloc(sizeof(*state->values), state->values_len);
+ state->values_types = calloc(sizeof(*state->values_types), state->values_len);
+ if ((state->values == NULL) || (state->values_types == NULL)) {
+ return ENOMEM;
+ }
+
+ for (uint16_t i = 0; i < n; i++) {
+ uint8_t tmp;
+ if (buffer_next(b, &tmp, sizeof(tmp)))
+ return EINVAL;
+ state->values_types[i] = (int)tmp;
+ }
+
+ for (uint16_t i = 0; i < n; i++) {
+ uint64_t tmp;
+ if (buffer_next(b, &tmp, sizeof(tmp)))
+ return EINVAL;
+
+ if (state->values_types[i] == LCC_TYPE_GAUGE) {
+ union {
+ uint64_t i;
+ double d;
+ } conv = {.i = tmp};
+ state->values[i].gauge = ntohd(conv.d);
+ continue;
+ }
+
+ tmp = be64toh(tmp);
+ switch (state->values_types[i]) {
+ case LCC_TYPE_COUNTER:
+ state->values[i].counter = (counter_t)tmp;
+ break;
+ case LCC_TYPE_DERIVE:
+ state->values[i].derive = (derive_t)tmp;
+ break;
+ case LCC_TYPE_ABSOLUTE:
+ state->values[i].absolute = (absolute_t)tmp;
+ break;
+ default:
+ return EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+#if HAVE_GCRYPT_H
+static int verify_sha256(void *payload, size_t payload_size,
+ char const *username, char const *password,
+ uint8_t hash_provided[32]) {
+ gcry_md_hd_t hd = NULL;
+
+ gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+ if (err != 0) {
+ return (int)err;
+ }
+
+ err = gcry_md_setkey(hd, password, strlen(password));
+ if (err != 0) {
+ gcry_md_close(hd);
+ return (int)err;
+ }
+
+ gcry_md_write(hd, username, strlen(username));
+ gcry_md_write(hd, payload, payload_size);
+
+ unsigned char *hash_calculated = gcry_md_read(hd, GCRY_MD_SHA256);
+ if (!hash_calculated) {
+ gcry_md_close(hd);
+ return -1;
+ }
+
+ int ret = memcmp(hash_provided, hash_calculated, 32);
+
+ gcry_md_close(hd);
+ hash_calculated = NULL;
+
+ return !!ret;
+}
+#else /* !HAVE_GCRYPT_H */
+static int verify_sha256(void *payload, size_t payload_size,
+ char const *username, char const *password,
+ uint8_t hash_provided[32]) {
+ return ENOTSUP;
+}
+#endif
+
+static int parse_sign_sha256(void *signature, size_t signature_len,
+ void *payload, size_t payload_size,
+ lcc_network_parse_options_t const *opts) {
+ if (opts->password_lookup == NULL) {
+ /* The sender signed the packet but we can't verify it. Handle it as if it
+ * were unsigned, i.e. security level NONE. */
+ return network_parse(payload, payload_size, NONE, opts);
+ }
+
+ buffer_t *b = &(buffer_t){
+ .data = signature, .len = signature_len,
+ };
+
+ uint8_t hash[32];
+ if (buffer_next(b, hash, sizeof(hash)))
+ return EINVAL;
+
+ char username[b->len + 1];
+ memset(username, 0, sizeof(username));
+ if (buffer_next(b, username, sizeof(username) - 1)) {
+ return EINVAL;
+ }
+
+ char const *password = opts->password_lookup(username);
+ if (!password)
+ return network_parse(payload, payload_size, NONE, opts);
+
+ int status = verify_sha256(payload, payload_size, username, password, hash);
+ if (status != 0)
+ return status;
+
+ return network_parse(payload, payload_size, SIGN, opts);
+}
+
+#if HAVE_GCRYPT_H
+static int decrypt_aes256(buffer_t *b, void *iv, size_t iv_size,
+ char const *password) {
+ gcry_cipher_hd_t cipher = NULL;
+
+ if (gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB,
+ /* flags = */ 0))
+ return -1;
+
+ uint8_t pwhash[32] = {0};
+ gcry_md_hash_buffer(GCRY_MD_SHA256, pwhash, password, strlen(password));
+
+ fprintf(stderr, "sizeof(iv) = %" PRIsz "\n", sizeof(iv));
+ if (gcry_cipher_setkey(cipher, pwhash, sizeof(pwhash)) ||
+ gcry_cipher_setiv(cipher, iv, iv_size) ||
+ gcry_cipher_decrypt(cipher, b->data, b->len, /* in = */ NULL,
+ /* in_size = */ 0)) {
+ gcry_cipher_close(cipher);
+ return -1;
+ }
+
+ gcry_cipher_close(cipher);
+ return 0;
+}
+
+static int parse_encrypt_aes256(void *data, size_t data_size,
+ lcc_network_parse_options_t const *opts) {
+ if (opts->password_lookup == NULL) {
+ /* Without a password source it's (hopefully) impossible to decrypt the
+ * network packet. */
+ return ENOENT;
+ }
+
+ buffer_t *b = &(buffer_t){
+ .data = data, .len = data_size,
+ };
+
+ uint16_t username_len;
+ if (buffer_uint16(b, &username_len))
+ return EINVAL;
+ if ((size_t)username_len > data_size)
+ return ENOMEM;
+ char username[((size_t)username_len) + 1];
+ memset(username, 0, sizeof(username));
+ if (buffer_next(b, username, (size_t)username_len))
+ return EINVAL;
+
+ char const *password = opts->password_lookup(username);
+ if (!password)
+ return ENOENT;
+
+ uint8_t iv[16];
+ if (buffer_next(b, iv, sizeof(iv)))
+ return EINVAL;
+
+ int status = decrypt_aes256(b, iv, sizeof(iv), password);
+ if (status != 0)
+ return status;
+
+ uint8_t hash_provided[20];
+ if (buffer_next(b, hash_provided, sizeof(hash_provided))) {
+ return -1;
+ }
+
+ uint8_t hash_calculated[20];
+ gcry_md_hash_buffer(GCRY_MD_SHA1, hash_calculated, b->data, b->len);
+
+ if (memcmp(hash_provided, hash_calculated, sizeof(hash_provided)) != 0) {
+ return -1;
+ }
+
+ return network_parse(b->data, b->len, ENCRYPT, opts);
+}
+#else /* !HAVE_GCRYPT_H */
+static int parse_encrypt_aes256(void *data, size_t data_size,
+ lcc_network_parse_options_t const *opts) {
+ return ENOTSUP;
+}
+#endif
+
+static int network_parse(void *data, size_t data_size, lcc_security_level_t sl,
+ lcc_network_parse_options_t const *opts) {
+ buffer_t *b = &(buffer_t){
+ .data = data, .len = data_size,
+ };
+
+ lcc_value_list_t state = {0};
+
+ while (b->len > 0) {
+ uint16_t type = 0, sz = 0;
+ if (buffer_uint16(b, &type) || buffer_uint16(b, &sz)) {
+ DEBUG("lcc_network_parse(): reading type and/or length failed.\n");
+ return EINVAL;
+ }
+
+ if ((sz < 5) || (((size_t)sz - 4) > b->len)) {
+ DEBUG("lcc_network_parse(): invalid 'sz' field: sz = %" PRIu16
+ ", b->len = %" PRIsz "\n",
+ sz, b->len);
+ return EINVAL;
+ }
+ sz -= 4;
+
+ uint8_t payload[sz];
+ if (buffer_next(b, payload, sizeof(payload)))
+ return EINVAL;
+
+ switch (type) {
+ case TYPE_HOST:
+ case TYPE_PLUGIN:
+ case TYPE_PLUGIN_INSTANCE:
+ case TYPE_TYPE:
+ case TYPE_TYPE_INSTANCE: {
+ if (parse_identifier(type, payload, sizeof(payload), &state)) {
+ DEBUG("lcc_network_parse(): parse_identifier failed.\n");
+ return EINVAL;
+ }
+ break;
+ }
+
+ case TYPE_INTERVAL:
+ case TYPE_INTERVAL_HR:
+ case TYPE_TIME:
+ case TYPE_TIME_HR: {
+ if (parse_time(type, payload, sizeof(payload), &state)) {
+ DEBUG("lcc_network_parse(): parse_time failed.\n");
+ return EINVAL;
+ }
+ break;
+ }
+
+ case TYPE_VALUES: {
+ lcc_value_list_t vl = state;
+ if (parse_values(payload, sizeof(payload), &vl)) {
+ free(vl.values);
+ free(vl.values_types);
+ DEBUG("lcc_network_parse(): parse_values failed.\n");
+ return EINVAL;
+ }
+
+ int status = 0;
+
+ /* Write metrics if they have the required security level. */
+ if (sl >= opts->security_level)
+ status = opts->writer(&vl);
+
+ free(vl.values);
+ free(vl.values_types);
+
+ if (status != 0)
+ return status;
+ break;
+ }
+
+ case TYPE_SIGN_SHA256: {
+ int status =
+ parse_sign_sha256(payload, sizeof(payload), b->data, b->len, opts);
+ if (status != 0) {
+ DEBUG("lcc_network_parse(): parse_sign_sha256() = %d\n", status);
+ return -1;
+ }
+ /* parse_sign_sha256, if successful, consumes all remaining data. */
+ b->data = NULL;
+ b->len = 0;
+ break;
+ }
+
+ case TYPE_ENCR_AES256: {
+ int status = parse_encrypt_aes256(payload, sizeof(payload), opts);
+ if (status != 0) {
+ DEBUG("lcc_network_parse(): parse_encrypt_aes256() = %d\n", status);
+ return -1;
+ }
+ break;
+ }
+
+ default: {
+ DEBUG("lcc_network_parse(): ignoring unknown type %" PRIu16 "\n", type);
+ return EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int lcc_network_parse(void *data, size_t data_size,
+ lcc_network_parse_options_t opts) {
+ if (opts.password_lookup) {
+#if HAVE_GCRYPT_H
+ int status;
+ if ((status = init_gcrypt())) {
+ return status;
+ }
+#else
+ return ENOTSUP;
+#endif
+ }
+
+ return network_parse(data, data_size, NONE, &opts);
+}
--- /dev/null
+/**
+ * Copyright 2017 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "collectd/lcc_features.h"
+
+#include "collectd/network_buffer.h" /* for LCC_NETWORK_BUFFER_SIZE_DEFAULT */
+
+#include <assert.h>
+
+#include "network_parse.c" /* sic */
+
+char *raw_packet_data[] = {
+ "0000000e6c6f63616c686f7374000008000c1513676ac3a6e0970009000c00000002800000"
+ "000002000973776170000004000973776170000005000966726565000006000f0001010000"
+ "0080ff610f420008000c1513676ac3a8fc120004000c737761705f696f0000050007696e00"
+ "0006000f00010200000000000000000008000c1513676ac3a9077d000500086f7574000006"
+ "000f00010200000000000000000008000c1513676ac3bd2a8c0002000e696e746572666163"
+ "65000003000965746830000004000e69665f6f637465747300000500050000060018000202"
+ "02000000000000000000000000000000000008000c1513676ac3bd5a970004000e69665f65"
+ "72726f7273000006001800020202000000000000000000000000000000000008000c151367"
+ "6ac3bd7fea000300076c6f000004000e69665f6f6374657473000006001800020202000000"
+ "000009e79c000000000009e79c0008000c1513676ac3bdaae60003000a776c616e30000006"
+ "001800020202000000001009fa5400000000011cf6670008000c1513676ac3bdb0e0000400"
+ "0e69665f6572726f7273000006001800020202000000000000000000000000000000000008"
+ "000c1513676ac3bd3d6d0003000965746830000004000f69665f7061636b65747300000600"
+ "1800020202000000000000000000000000000000000008000c1513676ac3bdae290003000a"
+ "776c616e300000060018000202020000000000032f8f00000000000205e50008000c151367"
+ "6ac3bdbb7b0003000c646f636b657230000006001800020202000000000000000000000000"
+ "000000000008000c1513676ac3bda0db000300076c6f000004000e69665f6572726f727300"
+ "0006001800020202000000000000000000000000000000000008000c1513676ac3bdbde800"
+ "03000c646f636b657230000006001800020202000000000000000000000000000000000008"
+ "000c1513676ac3bd8d8e000300076c6f000004000f69665f7061636b657473000006001800"
+ "0202020000000000000c9c0000000000000c9c0008000c1513676ac3bdb90b0003000c646f"
+ "636b657230000004000e69665f6f6374657473000006001800020202000000000000000000"
+ "000000000000000008000c1513676ac469b10f0002000e70726f6365737365730000030005"
+ "000004000d70735f7374617465000005000c7a6f6d62696573000006000f00010100000000"
+ "000000000008000c1513676ac469a4a30005000d736c656570696e67000006000f00010100"
+ "00000000006e400008000c1513676ac469c6320005000b706167696e67000006000f000101"
+ "00000000000000000008000c1513676ac469f06e0005000c626c6f636b6564000006000f00"
+ "010100000000000000000008000c1513676ac4698af40005000c72756e6e696e6700000600"
+ "0f00010100000000000000000008000c1513676ac469bbe10005000c73746f707065640000"
+ "06000f00010100000000000000000008000c1513676ac46b8e710004000e666f726b5f7261"
+ "74650000050005000006000f0001020000000000001bcf0008000c1513676d437f12960002"
+ "00086370750000030006300000040008637075000005000b73797374656d000006000f0001"
+ "0200000000000021870008000c1513676d437f36020005000969646c65000006000f000102"
+ "000000000005847a0008000c1513676d437f979b0005000977616974000006000f00010200"
+ "000000000005210008000c1513676d43802ff60005000c736f6674697271000006000f0001"
+ "02000000000000001f0008000c1513676d43803b3a0005000a737465616c000006000f0001"
+ "020000000000000000",
+ "0000000e6c6f63616c686f7374000008000c1513676d4380551f0009000c00000002800000"
+ "00000200086370750000030006310000040008637075000005000975736572000006000f00"
+ "01020000000000007cad0008000c1513676d43805dbe000500096e696365000006000f0001"
+ "0200000000000001de0008000c1513676d4380697d0005000b73797374656d000006000f00"
+ "01020000000000001ce80008000c1513676d438072bd0005000969646c65000006000f0001"
+ "02000000000005931c0008000c1513676d43807c430005000977616974000006000f000102"
+ "000000000000094b0008000c1513676d43808cee0005000c736f6674697271000006000f00"
+ "010200000000000000120008000c1513676d4380843a0005000e696e746572727570740000"
+ "06000f00010200000000000000000008000c1513676d438096230005000a737465616c0000"
+ "06000f00010200000000000000000008000c1513676d4380aa9c0003000632000005000975"
+ "736572000006000f00010200000000000089580008000c1513676d4380b29f000500096e69"
+ "6365000006000f00010200000000000003610008000c1513676d4380c44c0005000969646c"
+ "65000006000f000102000000000005873d0008000c1513676d4380bc0f0005000b73797374"
+ "656d000006000f000102000000000000201d0008000c1513676d4380cea400050009776169"
+ "74000006000f00010200000000000005810008000c1513676d4380d7370005000e696e7465"
+ "7272757074000006000f00010200000000000000000008000c1513676d4380ea830005000a"
+ "737465616c000006000f00010200000000000000000008000c1513676d437eef6200030006"
+ "3000000500096e696365000006000f00010200000000000003920008000c1513676d4380e0"
+ "260003000632000005000c736f6674697271000006000f0001020000000000000016000800"
+ "0c1513676d438101410003000633000005000975736572000006000f000102000000000000"
+ "7d8a0008000c1513676d438109f5000500096e696365000006000f00010200000000000004"
+ "350008000c1513676d4380244b0003000630000005000e696e74657272757074000006000f"
+ "00010200000000000000000008000c1513676d438122070003000633000005000969646c65"
+ "000006000f0001020000000000058eb60008000c1513676d43812e83000500097761697400"
+ "0006000f0001020000000000000ca80008000c1513676d438141480005000c736f66746972"
+ "71000006000f000102000000000000001e0008000c1513676d43814a5d0005000a73746561"
+ "6c000006000f00010200000000000000000008000c1513676d4381149e0005000b73797374"
+ "656d000006000f0001020000000000001b9a0008000c1513676d437ea86000030006300000"
+ "05000975736572000006000f00010200000000000089a80008000c1513676d438138190003"
+ "000633000005000e696e74657272757074000006000f00010200000000000000000008000c"
+ "1513676d438a9ca00002000e696e74657266616365000003000965746830000004000e6966"
+ "5f6f6374657473000005000500000600180002020200000000000000000000000000000000"
+ "0008000c1513676d438aea760004000f69665f7061636b6574730000060018000202020000"
+ "00000000000000000000000000000008000c1513676d438b214d0004000e69665f6572726f"
+ "727300000600180002020200000000000000000000000000000000",
+ "0000000e6c6f63616c686f7374000008000c1513676d438aac590009000c00000002800000"
+ "000002000764660000030009726f6f74000004000f64665f636f6d706c6578000005000966"
+ "726565000006000f0001010000004c077e57420008000c1513676d438b6ada0005000d7265"
+ "736572766564000006000f00010100000000338116420008000c1513676d438b7a17000200"
+ "0e696e7465726661636500000300076c6f000004000e69665f6f6374657473000005000500"
+ "0006001800020202000000000009ecf5000000000009ecf50008000c1513676d438b757800"
+ "02000764660000030009726f6f74000004000f64665f636f6d706c65780000050009757365"
+ "64000006000f000101000000e0a41b26420008000c1513676d438b8ed20002000e696e7465"
+ "726661636500000300076c6f000004000e69665f6572726f72730000050005000006001800"
+ "020202000000000000000000000000000000000008000c1513676d438b86bf0004000f6966"
+ "5f7061636b6574730000060018000202020000000000000c9d0000000000000c9d0008000c"
+ "1513676d438bb3e60003000a776c616e300000060018000202020000000000032fab000000"
+ "00000205ed0008000c1513676d438bd62e0003000c646f636b657230000004000e69665f6f"
+ "6374657473000006001800020202000000000000000000000000000000000008000c151367"
+ "6d438bbc8f0003000a776c616e30000004000e69665f6572726f7273000006001800020202"
+ "000000000000000000000000000000000008000c1513676d438bdf030003000c646f636b65"
+ "7230000004000f69665f7061636b6574730000060018000202020000000000000000000000"
+ "00000000000008000c1513676d438baaf10003000a776c616e30000004000e69665f6f6374"
+ "65747300000600180002020200000000100a042300000000011cfa460008000c1513676d43"
+ "8c5f100002000764660000030009626f6f74000004000f64665f636f6d706c657800000500"
+ "0966726565000006000f0001010000000010e198410008000c1513676d438c689c0005000d"
+ "7265736572766564000006000f00010100000000804c68410008000c1513676d438c70ce00"
+ "05000975736564000006000f0001010000000020ea9e410008000c1513676d438be7bc0002"
+ "000e696e74657266616365000003000c646f636b657230000004000e69665f6572726f7273"
+ "0000050005000006001800020202000000000000000000000000000000000008000c151367"
+ "6d43beca8c0002000c656e74726f70790000030005000004000c656e74726f707900000600"
+ "0f0001010000000000088f400008000c1513676d43bf1d13000200096c6f61640000040009"
+ "6c6f6164000006002100030101019a9999999999a93f666666666666d63f5c8fc2f5285cdf"
+ "3f0008000c1513676d43c02b85000200096469736b00000300087364610000040010646973"
+ "6b5f6f63746574730000060018000202020000000075887800000000005b6f3c000008000c"
+ "1513676d43c06d1f0004000d6469736b5f6f7073000006001800020202000000000003cbbd"
+ "000000000001c0510008000c1513676d43c08b6a0004000e6469736b5f74696d6500000600"
+ "1800020202000000000000003f00000000000001720008000c1513676d43c0a5fb00040010"
+ "6469736b5f6d65726765640000060018000202020000000000001285000000000000f80100"
+ "08000c1513676d43c0c8b4000300097364613100000400106469736b5f6f63746574730000"
+ "060018000202020000000001107c000000000000003c00",
+ "0000000e6c6f63616c686f7374000008000c1513676d43c0d00a0009000c00000002800000"
+ "00000200096469736b000003000973646131000004000d6469736b5f6f7073000006001800"
+ "020202000000000000029b00000000000000080008000c1513676d43c0d7b20004000e6469"
+ "736b5f74696d650000060018000202020000000000000004000000000000000f0008000c15"
+ "13676d43c0df73000400106469736b5f6d6572676564000006001800020202000000000000"
+ "0fb400000000000000010008000c1513676d43c0f87c000300097364613200000400106469"
+ "736b5f6f637465747300000600180002020200000000000008000000000000000000000800"
+ "0c1513676d43c1003e0004000d6469736b5f6f707300000600180002020200000000000000"
+ "0200000000000000000008000c1513676d43c107bf000400106469736b5f6d657267656400"
+ "0006001800020202000000000000000000000000000000000008000c1513676d43c12fa400"
+ "03000973646135000004000d6469736b5f6f7073000006001800020202000000000003c867"
+ "000000000001aef20008000c1513676d43c13d5e000400106469736b5f6d65726765640000"
+ "0600180002020200000000000002d1000000000000f8000008000c1513676d43c136a90004"
+ "000e6469736b5f74696d65000006001800020202000000000000003f000000000000011c00"
+ "08000c1513676d43c1740500030009646d2d3000000400106469736b5f6f63746574730000"
+ "060018000202020000000074596400000000005b6f00000008000c1513676d43c179c70004"
+ "000d6469736b5f6f7073000006001800020202000000000003cae4000000000002b0f30008"
+ "000c1513676d43c18abe000400106469736b5f6d6572676564000006001800020202000000"
+ "000000000000000000000000000008000c1513676d43c181b90004000e6469736b5f74696d"
+ "650000060018000202020000000000000040000000000000013e0008000c1513676d43c1a9"
+ "5e00030009646d2d3100000400106469736b5f6f6374657473000006001800020202000000"
+ "00000e000000000000000000000008000c1513676d43c1b7ea0004000e6469736b5f74696d"
+ "65000006001800020202000000000000000200000000000000000008000c1513676d43c1b0"
+ "3e0004000d6469736b5f6f707300000600180002020200000000000000e000000000000000"
+ "000008000c1513676d43c1c00d000400106469736b5f6d6572676564000006001800020202"
+ "000000000000000000000000000000000008000c1513676d43c12818000300097364613500"
+ "000400106469736b5f6f637465747300000600180002020200000000746c6400000000005b"
+ "6f00000008000c1513676d43d320a80002000c62617474657279000003000630000004000b"
+ "636861726765000006000f0001018fc2f5285c2f58400008000c1513676d43d36fd6000400"
+ "0c63757272656e74000006000f00010100000000000000800008000c1513676d43d3cdb600"
+ "04000c766f6c74616765000006000f000101736891ed7cbf28400008000c1513676d43d59d"
+ "d60002000869727100000300050000040008697271000005000630000006000f0001020000"
+ "0000000000110008000c1513676d43d5d2cf0005000631000006000f000102000000000000"
+ "00100008000c1513676d43d5fe820005000638000006000f00010200000000000000010008"
+ "000c1513676d43d635440005000639000006000f00010200000000000035210008000c1513"
+ "676d43d66265000500073132000006000f0001020000000000000790",
+ "0000000e6c6f63616c686f7374000008000c1513676d43d68e940009000c00000002800000"
+ "0000020008697271000004000869727100000500073136000006000f000102000000000000"
+ "00210008000c1513676d43d69be20002000a7573657273000004000a757365727300000500"
+ "05000006000f00010100000000000010400008000c1513676d43d6aa5d0002000869727100"
+ "0004000869727100000500073233000006000f00010200000000000000250008000c151367"
+ "6d43d6c7dc000500073431000006000f000102000000000000ff7d0008000c1513676d43d6"
+ "e23d000500073432000006000f00010200000000000008070008000c1513676d43d9aa3a00"
+ "0500073437000006000f0001020000000000079a260008000c1513676d43d9cca900050007"
+ "3438000006000f00010200000000000000c70008000c1513676d43d9ea5d00050007343900"
+ "0006000f00010200000000000004c20008000c1513676d43da050e00050007353000000600"
+ "0f000102000000000000001c0008000c1513676d43da1efa000500084e4d49000006000f00"
+ "010200000000000000000008000c1513676d43da3c82000500084c4f43000006000f000102"
+ "000000000018d3080008000c1513676d43da544e00050008535055000006000f0001020000"
+ "0000000000000008000c1513676d43da6cca00050008504d49000006000f00010200000000"
+ "000000000008000c1513676d43da885400050008495749000006000f000102000000000000"
+ "a9da0008000c1513676d43daa23a00050008525452000006000f0001020000000000000003"
+ "0008000c1513676d43dabaed00050008524553000006000f00010200000000000ac8360008"
+ "000c1513676d43dad4150005000843414c000006000f000102000000000000191f0008000c"
+ "1513676d43daeef300050008544c42000006000f000102000000000003dbdc0008000c1513"
+ "676d43db11410005000854524d000006000f00010200000000000000000008000c1513676d"
+ "43db292c00050008544852000006000f00010200000000000000000008000c1513676d43db"
+ "411d000500084d4345000006000f00010200000000000000000008000c1513676d43db5b59"
+ "000500084d4350000006000f000102000000000000003c0008000c1513676d43db68010005"
+ "0008455252000006000f00010200000000000000000008000c1513676d43db758a00050008"
+ "4d4953000006000f00010200000000000000000008000c1513676d43dd2e800002000b6d65"
+ "6d6f7279000004000b6d656d6f7279000005000975736564000006000f00010100000000fe"
+ "bbe0410008000c1513676d43dd3f4b0005000d6275666665726564000006000f0001010000"
+ "000070fbc8410008000c1513676d43dd48700005000b636163686564000006000f00010100"
+ "000000c008df410008000c1513676d43dd51c60005000966726565000006000f0001010000"
+ "0080481d05420008000c1513676d43dec7e300020009737761700000040009737761700000"
+ "05000975736564000006000f00010100000000000000000008000c1513676d43ded4490005"
+ "000966726565000006000f00010100000080ff610f420008000c1513676d43dedcfd000500"
+ "0b636163686564000006000f00010100000000000000000008000c1513676d43d715e30002"
+ "0008697271000004000869727100000500073434000006000f0001020000000000031b6100"
+ "08000c1513676d43d73116000500073435000006000f00010200000000000000180008000c"
+ "1513676d43ee00150002000973776170000004000c737761705f696f0000050007696e0000"
+ "06000f0001020000000000000000",
+};
+
+static int decode_string(char const *in, uint8_t *out, size_t *out_size) {
+ size_t in_size = strlen(in);
+ if (*out_size < (in_size / 2))
+ return -1;
+ *out_size = in_size / 2;
+
+ for (size_t i = 0; i < *out_size; i++) {
+ char tmp[] = {in[2 * i], in[2 * i + 1], 0};
+ out[i] = (uint8_t)strtoul(tmp, NULL, 16);
+ }
+
+ return 0;
+}
+
+static int nop_writer(lcc_value_list_t const *vl) {
+ if (!strlen(vl->identifier.host) || !strlen(vl->identifier.plugin) ||
+ !strlen(vl->identifier.type)) {
+ return EINVAL;
+ }
+ return 0;
+}
+
+static int test_network_parse() {
+ int ret = 0;
+
+ for (size_t i = 0; i < sizeof(raw_packet_data) / sizeof(raw_packet_data[0]);
+ i++) {
+ uint8_t buffer[LCC_NETWORK_BUFFER_SIZE_DEFAULT];
+ size_t buffer_size = sizeof(buffer);
+ if (decode_string(raw_packet_data[i], buffer, &buffer_size)) {
+ fprintf(stderr, "lcc_network_parse(raw_packet_data[%" PRIsz "]):"
+ " decoding string failed\n",
+ i);
+ return -1;
+ }
+
+ int status =
+ lcc_network_parse(buffer, buffer_size, (lcc_network_parse_options_t){
+ .writer = nop_writer,
+ });
+ if (status != 0) {
+ fprintf(stderr,
+ "lcc_network_parse(raw_packet_data[%" PRIsz "]) = %d, want 0\n",
+ i, status);
+ ret = status;
+ }
+
+ printf("ok - lcc_network_parse(raw_packet_data[%" PRIsz "])\n", i);
+ }
+
+ return ret;
+}
+
+static int test_parse_time() {
+ int ret = 0;
+
+ struct {
+ uint64_t in;
+ double want;
+ } cases[] = {
+ {1439980823, 1439980823.0},
+ {1439981005, 1439981005.0},
+ {1439981150, 1439981150.0},
+ };
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ lcc_value_list_t vl = LCC_VALUE_LIST_INIT;
+
+ uint64_t be = htobe64(cases[i].in);
+ int status = parse_time(TYPE_TIME, &be, sizeof(be), &vl);
+ if ((status != 0) || (vl.time != cases[i].want)) {
+ fprintf(stderr, "parse_time(%" PRIu64 ") = (%.0f, %d), want (%.0f, 0)\n",
+ cases[i].in, vl.time, status, cases[i].want);
+ ret = -1;
+ }
+ }
+
+ struct {
+ uint64_t in;
+ double want;
+ } cases_hr[] = {
+ {1546167635576736987, 1439980823.152453627},
+ {1546167831554815222, 1439981005.671262017},
+ {1546167986577716567, 1439981150.047589622},
+ };
+
+ for (size_t i = 0; i < sizeof(cases_hr) / sizeof(cases_hr[0]); i++) {
+ lcc_value_list_t vl = LCC_VALUE_LIST_INIT;
+
+ uint64_t be = htobe64(cases_hr[i].in);
+ int status = parse_time(TYPE_TIME_HR, &be, sizeof(be), &vl);
+ if ((status != 0) || (vl.time != cases_hr[i].want)) {
+ fprintf(stderr, "parse_time(%" PRIu64 ") = (%.9f, %d), want (%.9f, 0)\n",
+ cases_hr[i].in, vl.time, status, cases_hr[i].want);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+static int test_parse_string() {
+ int ret = 0;
+
+ struct {
+ uint8_t *in;
+ size_t in_len;
+ char *want;
+ } cases[] = {
+ {(uint8_t[]){0}, 1, ""},
+ {(uint8_t[]){'t', 'e', 's', 't', 0}, 5, "test"},
+ {(uint8_t[]){'t', 'e', 's', 't'}, 4, NULL}, // null byte missing
+ {(uint8_t[]){'t', 'e', 's', 't', 'x', 0}, 6,
+ NULL}, // output buffer too small
+ };
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ char got[5] = {0};
+
+ int status = parse_string(cases[i].in, cases[i].in_len, got, sizeof(got));
+ if (cases[i].want == NULL) {
+ if (status == 0) {
+ fprintf(stderr, "parse_string() = (\"%s\", 0), want error\n", got);
+ ret = -1;
+ }
+ } else /* if cases[i].want != NULL */ {
+ if (status != 0) {
+ fprintf(stderr, "parse_string() = %d, want 0\n", status);
+ ret = -1;
+ } else if (strcmp(got, cases[i].want) != 0) {
+ fprintf(stderr, "parse_string() = (\"%s\", 0), want (\"%s\", 0)\n", got,
+ cases[i].want);
+ ret = -1;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int test_parse_values() {
+ int ret = 0;
+
+ uint8_t testcase[] = {
+ // 0, 6, // pkg type
+ // 0, 33, // pkg len
+ 0, 3, // num values
+ 1, 2, 1, // gauge, derive, gauge
+ 0, 0, 0, 0, 0, 0, 0x45, 0x40, // 42.0
+ 0, 0, 0, 0, 0, 0, 0x7a, 0x69, // 31337
+ 0, 0, 0, 0, 0, 0, 0xf8, 0x7f, // NaN
+ };
+
+ lcc_value_list_t vl = LCC_VALUE_LIST_INIT;
+ int status = parse_values(testcase, sizeof(testcase), &vl);
+ if (status != 0) {
+ fprintf(stderr, "parse_values() = %d, want 0\n", status);
+ return -1;
+ }
+
+ if (vl.values_len != 3) {
+ fprintf(stderr, "parse_values(): vl.values_len = %" PRIsz ", want 3\n",
+ vl.values_len);
+ return -1;
+ }
+
+ int want_types[] = {LCC_TYPE_GAUGE, LCC_TYPE_DERIVE, LCC_TYPE_GAUGE};
+ for (size_t i = 0; i < sizeof(want_types) / sizeof(want_types[0]); i++) {
+ if (vl.values_types[i] != want_types[i]) {
+ fprintf(stderr,
+ "parse_values(): vl.values_types[%" PRIsz "] = %d, want %d\n", i,
+ vl.values_types[i], want_types[i]);
+ ret = -1;
+ }
+ }
+
+ if (vl.values[0].gauge != 42.0) {
+ fprintf(stderr, "parse_values(): vl.values[0] = %g, want 42\n",
+ vl.values[0].gauge);
+ ret = -1;
+ }
+ if (vl.values[1].derive != 31337) {
+ fprintf(stderr, "parse_values(): vl.values[1] = %" PRIu64 ", want 31337\n",
+ vl.values[1].derive);
+ ret = -1;
+ }
+ if (!isnan(vl.values[2].gauge)) {
+ fprintf(stderr, "parse_values(): vl.values[2] = %g, want NaN\n",
+ vl.values[2].gauge);
+ ret = -1;
+ }
+
+ free(vl.values);
+ free(vl.values_types);
+
+ return ret;
+}
+
+#if HAVE_GCRYPT_H
+static int test_verify_sha256() {
+ int ret = 0;
+
+ int status = verify_sha256(
+ (char[]){'c', 'o', 'l', 'l', 'e', 'c', 't', 'd'}, 8, "admin", "admin",
+ (uint8_t[]){
+ 0xcd, 0xa5, 0x9a, 0x37, 0xb0, 0x81, 0xc2, 0x31, 0x24, 0x2a, 0x6d,
+ 0xbd, 0xfb, 0x44, 0xdb, 0xd7, 0x41, 0x2a, 0xf4, 0x29, 0x83, 0xde,
+ 0xa5, 0x11, 0x96, 0xd2, 0xe9, 0x30, 0x21, 0xae, 0xc5, 0x45,
+ });
+ if (status != 0) {
+ fprintf(stderr, "verify_sha256() = %d, want 0\n", status);
+ ret = -1;
+ }
+
+ status = verify_sha256(
+ (char[]){'c', 'o', 'l', 'l', 'E', 'c', 't', 'd'}, 8, "admin", "admin",
+ (uint8_t[]){
+ 0xcd, 0xa5, 0x9a, 0x37, 0xb0, 0x81, 0xc2, 0x31, 0x24, 0x2a, 0x6d,
+ 0xbd, 0xfb, 0x44, 0xdb, 0xd7, 0x41, 0x2a, 0xf4, 0x29, 0x83, 0xde,
+ 0xa5, 0x11, 0x96, 0xd2, 0xe9, 0x30, 0x21, 0xae, 0xc5, 0x45,
+ });
+ if (status != 1) {
+ fprintf(stderr, "verify_sha256() = %d, want 1\n", status);
+ ret = -1;
+ }
+
+ return ret;
+}
+#endif
+
+#if HAVE_GCRYPT_H
+static int test_decrypt_aes256() {
+ char const *iv_str = "4cbe2a747c9f9dcfa0e66f0c2fa74875";
+ uint8_t iv[16] = {0};
+ size_t iv_len = sizeof(iv);
+
+ char const *ciphertext_str =
+ "8f023b0b15178f8428da1221a5f653e840f065db4aff032c22e5a3df";
+ uint8_t ciphertext[28] = {0};
+ size_t ciphertext_len = sizeof(ciphertext);
+
+ if (decode_string(iv_str, iv, &iv_len) ||
+ decode_string(ciphertext_str, ciphertext, &ciphertext_len)) {
+ fprintf(stderr, "test_decrypt_aes256: decode_string failed.\n");
+ return -1;
+ }
+ assert(iv_len == sizeof(iv));
+ assert(ciphertext_len == sizeof(ciphertext));
+
+ int status = decrypt_aes256(
+ &(buffer_t){
+ .data = ciphertext, .len = ciphertext_len,
+ },
+ iv, iv_len, "admin");
+ if (status != 0) {
+ fprintf(stderr, "decrypt_aes256() = %d, want 0\n", status);
+ return -1;
+ }
+
+ char const *want = "collectd";
+ char got[9] = {0};
+ memmove(got, &ciphertext[20], sizeof(got) - 1);
+ if (strcmp(got, want) != 0) {
+ fprintf(stderr, "decrypt_aes256() = \"%s\", want \"%s\"\n", got, want);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+int main(void) {
+ int ret = 0;
+
+ int status;
+ if ((status = test_network_parse())) {
+ ret = status;
+ }
+ if ((status = test_parse_time())) {
+ ret = status;
+ }
+ if ((status = test_parse_string())) {
+ ret = status;
+ }
+ if ((status = test_parse_values())) {
+ ret = status;
+ }
+
+#if HAVE_GCRYPT_H
+ if ((status = test_verify_sha256())) {
+ ret = status;
+ }
+ if ((status = test_decrypt_aes256())) {
+ ret = status;
+ }
+#endif
+
+ return ret;
+}
--- /dev/null
+/**
+ * Copyright 2017 Florian Forster
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "config.h"
+
+#if !defined(__GNUC__) || !__GNUC__
+#define __attribute__(x) /**/
+#endif
+
+#include "collectd/lcc_features.h"
+#include "collectd/network_parse.h" /* for lcc_network_parse_options_t */
+#include "collectd/server.h"
+
+#include <errno.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <stdio.h>
+#define DEBUG(...) printf(__VA_ARGS__)
+
+static _Bool is_multicast(struct addrinfo const *ai) {
+ if (ai->ai_family == AF_INET) {
+ struct sockaddr_in *addr = (struct sockaddr_in *)ai->ai_addr;
+ return IN_MULTICAST(ntohl(addr->sin_addr.s_addr));
+ } else if (ai->ai_family == AF_INET6) {
+ struct sockaddr_in6 *addr = (struct sockaddr_in6 *)ai->ai_addr;
+ return IN6_IS_ADDR_MULTICAST(&addr->sin6_addr);
+ }
+ return 0;
+}
+
+static int server_multicast_join(lcc_listener_t *srv,
+ struct sockaddr_storage *group, int loop_back,
+ int ttl) {
+ if (group->ss_family == AF_INET) {
+ struct sockaddr_in *sa = (struct sockaddr_in *)group;
+
+ int status = setsockopt(srv->conn, IPPROTO_IP, IP_MULTICAST_LOOP,
+ &loop_back, sizeof(loop_back));
+ if (status == -1) {
+ DEBUG("setsockopt(IP_MULTICAST_LOOP, %d) = %d\n", loop_back, errno);
+ return errno;
+ }
+
+ status =
+ setsockopt(srv->conn, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
+ if (status == -1)
+ return errno;
+
+#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
+ struct ip_mreqn mreq = {
+ .imr_address.s_addr = INADDR_ANY,
+ .imr_multiaddr.s_addr = sa->sin_addr.s_addr,
+ .imr_ifindex = if_nametoindex(srv->interface),
+ };
+#else
+ struct ip_mreq mreq = {
+ .imr_multiaddr.s_addr = sa->sin_addr.s_addr,
+ };
+#endif
+ status = setsockopt(srv->conn, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq));
+ if (status == -1)
+ return errno;
+ } else if (group->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sa = (struct sockaddr_in6 *)group;
+
+ int status = setsockopt(srv->conn, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+ &loop_back, sizeof(loop_back));
+ if (status == -1)
+ return errno;
+
+ status = setsockopt(srv->conn, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl,
+ sizeof(ttl));
+ if (status == -1)
+ return errno;
+
+ struct ipv6_mreq mreq6 = {
+ .ipv6mr_interface = if_nametoindex(srv->interface),
+ };
+ memmove(&mreq6.ipv6mr_multiaddr, &sa->sin6_addr, sizeof(struct in6_addr));
+
+ status = setsockopt(srv->conn, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
+ sizeof(mreq6));
+ if (status == -1)
+ return errno;
+ } else {
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static int server_bind_socket(lcc_listener_t *srv, struct addrinfo const *ai) {
+ /* allow multiple sockets to use the same PORT number */
+ if (setsockopt(srv->conn, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) ==
+ -1) {
+ return errno;
+ }
+
+ if (bind(srv->conn, ai->ai_addr, ai->ai_addrlen) == -1) {
+ return -1;
+ }
+
+ if (is_multicast(ai)) {
+ int status = server_multicast_join(srv, (void *)ai->ai_addr, /* loop = */ 1,
+ /* ttl = */ 16);
+ if (status != 0)
+ return status;
+ }
+
+ return 0;
+}
+
+static int server_open(lcc_listener_t *srv) {
+ struct addrinfo *res = NULL;
+ int status = getaddrinfo(srv->node ? srv->node : "::",
+ srv->service ? srv->service : LCC_DEFAULT_PORT,
+ &(struct addrinfo){
+ .ai_flags = AI_ADDRCONFIG,
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM,
+ },
+ &res);
+ if (status != 0)
+ return status;
+
+ for (struct addrinfo *ai = res; ai != NULL; ai = ai->ai_next) {
+ srv->conn = socket(ai->ai_family, ai->ai_socktype, 0);
+ if (srv->conn == -1)
+ continue;
+
+ status = server_bind_socket(srv, ai);
+ if (status != 0) {
+ close(srv->conn);
+ srv->conn = -1;
+ continue;
+ }
+
+ break;
+ }
+
+ freeaddrinfo(res);
+
+ if (srv->conn >= 0)
+ return 0;
+ return status != 0 ? status : -1;
+}
+
+int lcc_listen_and_write(lcc_listener_t srv) {
+ _Bool close_socket = 0;
+
+ if (srv.conn < 0) {
+ int status = server_open(&srv);
+ if (status != 0)
+ return status;
+ close_socket = 1;
+ }
+
+ if (srv.buffer_size == 0)
+ srv.buffer_size = LCC_NETWORK_BUFFER_SIZE;
+
+ if (srv.parser == NULL)
+ srv.parser = lcc_network_parse;
+
+ int ret = 0;
+ while (42) {
+ char buffer[srv.buffer_size];
+ ssize_t len = recv(srv.conn, buffer, sizeof(buffer), /* flags = */ 0);
+ if (len == -1) {
+ ret = errno;
+ break;
+ } else if (len == 0) {
+ break;
+ }
+
+ (void)srv.parser(buffer, (size_t)len, srv.parse_options);
+ }
+
+ if (close_socket) {
+ close(srv.conn);
+ srv.conn = -1;
+ }
+
+ return ret;
+}
#include "aux_types.h"
static char *unquote (const char *orig);
-static int yyerror (const char *s);
+static void yyerror(const char *s);
/* Lexer variables */
extern int yylineno;
argument_list argument
{
$$ = $1;
+ oconfig_value_t *tmp = realloc($$.argument,
+ ($$.argument_num+1) * sizeof(*$$.argument));
+ if (tmp == NULL) {
+ yyerror("realloc failed");
+ YYERROR;
+ }
+ $$.argument = tmp;
+ $$.argument[$$.argument_num] = $2;
$$.argument_num++;
- $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
- $$.argument[$$.argument_num-1] = $2;
}
| argument
{
- $$.argument = malloc (sizeof (oconfig_value_t));
+ $$.argument = calloc(1, sizeof(*$$.argument));
+ if ($$.argument == NULL) {
+ yyerror("calloc failed");
+ YYERROR;
+ }
$$.argument[0] = $1;
$$.argument_num = 1;
}
option:
identifier argument_list EOL
{
- memset (&$$, '\0', sizeof ($$));
+ memset(&$$, 0, sizeof($$));
$$.key = $1;
$$.values = $2.argument;
$$.values_num = $2.argument_num;
block_begin:
OPENBRAC identifier CLOSEBRAC EOL
{
- memset (&$$, '\0', sizeof ($$));
+ memset(&$$, 0, sizeof($$));
$$.key = $2;
}
|
OPENBRAC identifier argument_list CLOSEBRAC EOL
{
- memset (&$$, '\0', sizeof ($$));
+ memset(&$$, 0, sizeof($$));
$$.key = $2;
$$.values = $3.argument;
$$.values_num = $3.argument_num;
block:
block_begin statement_list block_end
{
- if (strcmp ($1.key, $3) != 0)
+ if (strcmp($1.key, $3) != 0)
{
- printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
- yyerror ("Block not closed..\n");
- exit (1);
+ printf("block_begin = %s; block_end = %s;\n", $1.key, $3);
+ yyerror("block not closed");
+ YYERROR;
}
free ($3); $3 = NULL;
$$ = $1;
}
| block_begin block_end
{
- if (strcmp ($1.key, $2) != 0)
+ if (strcmp($1.key, $2) != 0)
{
- printf ("block_begin = %s; block_end = %s;\n", $1.key, $2);
- yyerror ("Block not closed..\n");
- exit (1);
+ printf("block_begin = %s; block_end = %s;\n", $1.key, $2);
+ yyerror("block not closed");
+ YYERROR;
}
free ($2); $2 = NULL;
$$ = $1;
$$ = $1;
if (($2.values_num > 0) || ($2.children_num > 0))
{
+ oconfig_item_t *tmp = realloc($$.statement,
+ ($$.statement_num+1) * sizeof(*tmp));
+ if (tmp == NULL) {
+ yyerror("realloc failed");
+ YYERROR;
+ }
+ $$.statement = tmp;
+ $$.statement[$$.statement_num] = $2;
$$.statement_num++;
- $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
- $$.statement[$$.statement_num-1] = $2;
}
}
| statement
{
if (($1.values_num > 0) || ($1.children_num > 0))
{
- $$.statement = malloc (sizeof (oconfig_item_t));
+ $$.statement = calloc(1, sizeof(*$$.statement));
+ if ($$.statement == NULL) {
+ yyerror("calloc failed");
+ YYERROR;
+ }
$$.statement[0] = $1;
$$.statement_num = 1;
}
entire_file:
statement_list
{
- ci_root = calloc (1, sizeof (*ci_root));
+ ci_root = calloc(1, sizeof(*ci_root));
+ if (ci_root == NULL) {
+ yyerror("calloc failed");
+ YYERROR;
+ }
ci_root->children = $1.statement;
ci_root->children_num = $1.statement_num;
}
| /* epsilon */
{
- ci_root = calloc (1, sizeof (*ci_root));
- ci_root->children = NULL;
- ci_root->children_num = 0;
+ ci_root = calloc(1, sizeof(*ci_root));
+ if (ci_root == NULL) {
+ yyerror("calloc failed");
+ YYERROR;
+ }
}
;
%%
-static int yyerror (const char *s)
+static void yyerror(const char *s)
{
const char *text;
- if (*yytext == '\n')
+ if (yytext == NULL)
+ text = "<empty>";
+ else if (*yytext == '\n')
text = "<newline>";
else
text = yytext;
- fprintf (stderr, "Parse error in file `%s', line %i near `%s': %s\n",
+ fprintf(stderr, "Parse error in file `%s', line %i near `%s': %s\n",
c_file, yylineno, text, s);
- return (-1);
} /* int yyerror */
static char *unquote (const char *orig)
len -= 2;
memmove (ret, ret + 1, len);
- ret[len] = '\0';
+ ret[len] = 0;
for (int i = 0; i < len; i++)
{
}
static void load_submit(gauge_t snum, gauge_t mnum, gauge_t lnum) {
int cores = 0;
- char errbuf[1024];
#ifdef _SC_NPROCESSORS_ONLN
if (report_relative_load) {
if ((cores = sysconf(_SC_NPROCESSORS_ONLN)) < 1) {
- WARNING("load: sysconf failed : %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("load: sysconf failed : %s", STRERRNO);
}
}
#endif
if (getloadavg(load, 3) == 3)
load_submit(load[LOADAVG_1MIN], load[LOADAVG_5MIN], load[LOADAVG_15MIN]);
else {
- char errbuf[1024];
- WARNING("load: getloadavg failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("load: getloadavg failed: %s", STRERRNO);
}
/* #endif HAVE_GETLOADAVG */
int numfields;
if ((loadavg = fopen("/proc/loadavg", "r")) == NULL) {
- char errbuf[1024];
- WARNING("load: fopen: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("load: fopen: %s", STRERRNO);
return -1;
}
if (fgets(buffer, 16, loadavg) == NULL) {
- char errbuf[1024];
- WARNING("load: fgets: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("load: fgets: %s", STRERRNO);
fclose(loadavg);
return -1;
}
if (fclose(loadavg)) {
- char errbuf[1024];
- WARNING("load: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("load: fclose: %s", STRERRNO);
}
numfields = strsplit(buffer, fields, 8);
if (perfstat_cpu_total(NULL, &cputotal, sizeof(perfstat_cpu_total_t), 1) <
0) {
- char errbuf[1024];
- WARNING("load: perfstat_cpu : %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("load: perfstat_cpu : %s", STRERRNO);
return -1;
}
}
if (fh == NULL) {
- char errbuf[1024];
fprintf(stderr, "log_logstash plugin: fopen (%s) failed: %s\n", log_file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
} else {
fprintf(fh, "%s\n", buf);
if (do_close) {
}
if (fh == NULL) {
- char errbuf[1024];
fprintf(stderr, "logfile plugin: fopen (%s) failed: %s\n", log_file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
} else {
if (print_timestamp)
fprintf(fh, "[%s] %s%s\n", timestamp_str, level_str, msg);
sizeof(perfstat_partition_total_t),
/* number = */ 1 /* (must be 1) */);
if (status != 1) {
- char errbuf[1024];
- ERROR("lpar plugin: perfstat_partition_total failed: %s (%i)",
- sstrerror(errno, errbuf, sizeof(errbuf)), status);
+ ERROR("lpar plugin: perfstat_partition_total failed: %s (%i)", STRERRNO,
+ status);
return -1;
}
&lparstats, sizeof(perfstat_partition_total_t),
/* number = */ 1 /* (must be 1) */);
if (status != 1) {
- char errbuf[1024];
- ERROR("lpar plugin: perfstat_partition_total failed: %s (%i)",
- sstrerror(errno, errbuf, sizeof(errbuf)), status);
+ ERROR("lpar plugin: perfstat_partition_total failed: %s (%i)", STRERRNO,
+ status);
return -1;
}
* Benjamin Gilbert <bgilbert at backtick.net>
**/
-#include <lvm2app.h>
-
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#include <lvm2app.h>
+
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif /* HAVE_SYS_CAPABILITY_H */
+
#define NO_VALUE UINT64_MAX
#define PERCENT_SCALE_FACTOR 1e-8
return 0;
} /*lvm_read */
+static int c_lvm_init(void) {
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_ADMIN)
+ if (check_capability(CAP_SYS_ADMIN) != 0) {
+ if (getuid() == 0)
+ WARNING("lvm plugin: Running collectd as root, but the "
+ "CAP_SYS_ADMIN capability is missing. The plugin's read "
+ "function will probably fail. Is your init system dropping "
+ "capabilities?");
+ else
+ WARNING("lvm plugin: collectd doesn't have the CAP_SYS_ADMIN "
+ "capability. If you don't want to run collectd as root, try "
+ "running \"setcap cap_sys_admin=ep\" on the collectd binary.");
+ }
+#endif
+ return 0;
+}
+
void module_register(void) {
+ plugin_register_init("lvm", c_lvm_init);
plugin_register_read("lvm", lvm_read);
} /* void module_register */
.ai_socktype = SOCK_STREAM};
if ((ai_return = getaddrinfo(host, port, &ai_hints, &ai_list)) != 0) {
- char errbuf[1024];
ERROR("mbmon: getaddrinfo (%s, %s): %s", host, port,
- (ai_return == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(ai_return));
+ (ai_return == EAI_SYSTEM) ? STRERRNO : gai_strerror(ai_return));
return -1;
}
/* create our socket descriptor */
if ((fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype,
ai_ptr->ai_protocol)) < 0) {
- char errbuf[1024];
- ERROR("mbmon: socket: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("mbmon: socket: %s", STRERRNO);
continue;
}
/* connect to the mbmon daemon */
if (connect(fd, (struct sockaddr *)ai_ptr->ai_addr, ai_ptr->ai_addrlen)) {
- char errbuf[1024];
- INFO("mbmon: connect (%s, %s): %s", host, port,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ INFO("mbmon: connect (%s, %s): %s", host, port, STRERRNO);
close(fd);
fd = -1;
continue;
while ((status = read(fd, buffer + buffer_fill, buffer_size - buffer_fill)) !=
0) {
if (status == -1) {
- char errbuf[1024];
if ((errno == EAGAIN) || (errno == EINTR))
continue;
- ERROR("mbmon: Error reading from socket: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("mbmon: Error reading from socket: %s", STRERRNO);
close(fd);
return -1;
}
* collectd - src/mcelog.c
* MIT License
*
- * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * Copyright(c) 2016-2017 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"),
* Krzysztof Matczak <krzysztofx.matczak@intel.com>
*/
-#include "common.h"
#include "collectd.h"
+#include "common.h"
+#include "utils_llist.h"
+
#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#define MCELOG_DIMM_NAME "DMI_NAME"
#define MCELOG_CORRECTED_ERR "corrected memory errors"
#define MCELOG_UNCORRECTED_ERR "uncorrected memory errors"
+#define MCELOG_CORRECTED_ERR_TIMED "corrected memory timed errors"
+#define MCELOG_UNCORRECTED_ERR_TIMED "uncorrected memory timed errors"
+#define MCELOG_CORRECTED_ERR_TYPE_INS "corrected_memory_errors"
+#define MCELOG_UNCORRECTED_ERR_TYPE_INS "uncorrected_memory_errors"
typedef struct mcelog_config_s {
- char logfile[PATH_MAX]; /* mcelog logfile */
- pthread_t tid; /* poll thread id */
+ char logfile[PATH_MAX]; /* mcelog logfile */
+ pthread_t tid; /* poll thread id */
+ llist_t *dimms_list; /* DIMMs list */
+ pthread_mutex_t dimms_lock; /* lock for dimms cache */
+ _Bool persist;
} mcelog_config_t;
typedef struct socket_adapter_s socket_adapter_t;
typedef struct mcelog_memory_rec_s {
int corrected_err_total; /* x total*/
int corrected_err_timed; /* x in 24h*/
- char corrected_err_timed_period[DATA_MAX_NAME_LEN];
+ char corrected_err_timed_period[DATA_MAX_NAME_LEN / 2];
int uncorrected_err_total; /* x total*/
int uncorrected_err_timed; /* x in 24h*/
- char uncorrected_err_timed_period[DATA_MAX_NAME_LEN];
- char location[DATA_MAX_NAME_LEN]; /* SOCKET x CHANNEL x DIMM x*/
- char dimm_name[DATA_MAX_NAME_LEN]; /* DMI_NAME "DIMM_F1" */
+ char uncorrected_err_timed_period[DATA_MAX_NAME_LEN / 2];
+ char location[DATA_MAX_NAME_LEN / 2]; /* SOCKET x CHANNEL x DIMM x*/
+ char dimm_name[DATA_MAX_NAME_LEN / 2]; /* DMI_NAME "DIMM_F1" */
} mcelog_memory_rec_t;
static int socket_close(socket_adapter_t *self);
static int socket_reinit(socket_adapter_t *self);
static int socket_receive(socket_adapter_t *self, FILE **p_file);
-static mcelog_config_t g_mcelog_config = {.logfile = "/var/log/mcelog"};
+static mcelog_config_t g_mcelog_config = {
+ .logfile = "/var/log/mcelog", .persist = 0,
+};
static socket_adapter_t socket_adapter = {
.sock_fd = -1,
};
static _Bool mcelog_thread_running;
+static _Bool mcelog_apply_defaults;
+
+static void mcelog_free_dimms_list_records(llist_t *dimms_list) {
+
+ for (llentry_t *e = llist_head(dimms_list); e != NULL; e = e->next) {
+ sfree(e->key);
+ sfree(e->value);
+ }
+}
+
+/* Create or get dimm by dimm name/location */
+static llentry_t *mcelog_dimm(const mcelog_memory_rec_t *rec,
+ llist_t *dimms_list) {
+
+ char dimm_name[DATA_MAX_NAME_LEN];
+
+ if (strlen(rec->dimm_name) > 0) {
+ snprintf(dimm_name, sizeof(dimm_name), "%s_%s", rec->location,
+ rec->dimm_name);
+ } else
+ sstrncpy(dimm_name, rec->location, sizeof(dimm_name));
+
+ llentry_t *dimm_le = llist_search(g_mcelog_config.dimms_list, dimm_name);
+
+ if (dimm_le != NULL)
+ return dimm_le;
+
+ /* allocate new linked list entry */
+ mcelog_memory_rec_t *dimm_mr = calloc(1, sizeof(*dimm_mr));
+ if (dimm_mr == NULL) {
+ ERROR(MCELOG_PLUGIN ": Error allocating dimm memory item");
+ return NULL;
+ }
+ char *p_name = strdup(dimm_name);
+ if (p_name == NULL) {
+ ERROR(MCELOG_PLUGIN ": strdup: error");
+ free(dimm_mr);
+ return NULL;
+ }
+
+ /* add new dimm */
+ dimm_le = llentry_create(p_name, dimm_mr);
+ if (dimm_le == NULL) {
+ ERROR(MCELOG_PLUGIN ": llentry_create(): error");
+ free(dimm_mr);
+ free(p_name);
+ return NULL;
+ }
+ pthread_mutex_lock(&g_mcelog_config.dimms_lock);
+ llist_append(g_mcelog_config.dimms_list, dimm_le);
+ pthread_mutex_unlock(&g_mcelog_config.dimms_lock);
+
+ return dimm_le;
+}
+
+static void mcelog_update_dimm_stats(llentry_t *dimm,
+ const mcelog_memory_rec_t *rec) {
+ pthread_mutex_lock(&g_mcelog_config.dimms_lock);
+ memcpy(dimm->value, rec, sizeof(mcelog_memory_rec_t));
+ pthread_mutex_unlock(&g_mcelog_config.dimms_lock);
+}
static int mcelog_config(oconfig_item_t *ci) {
+ int use_logfile = 0, use_memory = 0;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
- if (strcasecmp("McelogClientSocket", child->key) == 0) {
- if (cf_util_get_string_buffer(child, socket_adapter.unix_sock.sun_path,
- sizeof(socket_adapter.unix_sock.sun_path)) <
- 0) {
- ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".",
+ if (strcasecmp("McelogLogfile", child->key) == 0) {
+ use_logfile = 1;
+ if (use_memory) {
+ ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\", Memory "
+ "option is already configured.",
child->key);
return -1;
}
- } else if (strcasecmp("McelogLogfile", child->key) == 0) {
if (cf_util_get_string_buffer(child, g_mcelog_config.logfile,
sizeof(g_mcelog_config.logfile)) < 0) {
ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".",
child->key);
return -1;
}
+ memset(socket_adapter.unix_sock.sun_path, 0,
+ sizeof(socket_adapter.unix_sock.sun_path));
+ } else if (strcasecmp("Memory", child->key) == 0) {
+ if (use_logfile) {
+ ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\", Logfile "
+ "option is already configured.",
+ child->key);
+ return -1;
+ }
+ use_memory = 1;
+ for (int j = 0; j < child->children_num; j++) {
+ oconfig_item_t *mem_child = child->children + j;
+ if (strcasecmp("McelogClientSocket", mem_child->key) == 0) {
+ if (cf_util_get_string_buffer(
+ mem_child, socket_adapter.unix_sock.sun_path,
+ sizeof(socket_adapter.unix_sock.sun_path)) < 0) {
+ ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".",
+ mem_child->key);
+ return -1;
+ }
+ } else if (strcasecmp("PersistentNotification", mem_child->key) == 0) {
+ if (cf_util_get_boolean(mem_child, &g_mcelog_config.persist) < 0) {
+ ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".",
+ mem_child->key);
+ return -1;
+ }
+ } else {
+ ERROR(MCELOG_PLUGIN ": Invalid Memory configuration option: \"%s\".",
+ mem_child->key);
+ return -1;
+ }
+ }
+ memset(g_mcelog_config.logfile, 0, sizeof(g_mcelog_config.logfile));
} else {
ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".",
child->key);
return -1;
}
}
+
+ if (!use_logfile && !use_memory)
+ mcelog_apply_defaults = 1;
+
return 0;
}
int ret = 0;
pthread_rwlock_rdlock(&self->lock);
if (fcntl(self->sock_fd, F_GETFL) != -1) {
- char errbuf[MCELOG_BUFF_SIZE];
if (shutdown(self->sock_fd, SHUT_RDWR) != 0) {
- ERROR(MCELOG_PLUGIN ": Socket shutdown failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR(MCELOG_PLUGIN ": Socket shutdown failed: %s", STRERRNO);
ret = -1;
}
if (close(self->sock_fd) != 0) {
- ERROR(MCELOG_PLUGIN ": Socket close failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR(MCELOG_PLUGIN ": Socket close failed: %s", STRERRNO);
ret = -1;
}
}
const size_t len) {
int ret = 0;
pthread_rwlock_rdlock(&self->lock);
- if (swrite(self->sock_fd, msg, len) < 0)
+ if (swrite(self->sock_fd, msg, len) != 0)
ret = -1;
pthread_rwlock_unlock(&self->lock);
return ret;
}
static int socket_reinit(socket_adapter_t *self) {
- char errbuff[MCELOG_BUFF_SIZE];
int ret = -1;
cdtime_t interval = plugin_get_interval();
struct timeval socket_timeout = CDTIME_T_TO_TIMEVAL(interval);
self->sock_fd =
socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (self->sock_fd < 0) {
- ERROR(MCELOG_PLUGIN ": Could not create a socket. %s",
- sstrerror(errno, errbuff, sizeof(errbuff)));
+ ERROR(MCELOG_PLUGIN ": Could not create a socket. %s", STRERRNO);
pthread_rwlock_unlock(&self->lock);
return ret;
}
pthread_rwlock_rdlock(&self->lock);
if (connect(self->sock_fd, (struct sockaddr *)&(self->unix_sock),
sizeof(self->unix_sock)) < 0) {
- ERROR(MCELOG_PLUGIN ": Failed to connect to mcelog server. %s",
- sstrerror(errno, errbuff, sizeof(errbuff)));
+ ERROR(MCELOG_PLUGIN ": Failed to connect to mcelog server. %s", STRERRNO);
self->close(self);
ret = -1;
} else {
return ret;
}
-static int mcelog_prepare_notification(notification_t *n,
- const mcelog_memory_rec_t *mr) {
- if (n == NULL || mr == NULL)
- return -1;
+static int mcelog_dispatch_mem_notifications(const mcelog_memory_rec_t *mr) {
+ notification_t n = {.severity = NOTIF_WARNING,
+ .time = cdtime(),
+ .plugin = MCELOG_PLUGIN,
+ .type = "errors"};
- if ((mr->location[0] != '\0') &&
- (plugin_notification_meta_add_string(n, MCELOG_SOCKET_STR, mr->location) <
- 0)) {
- ERROR(MCELOG_PLUGIN ": add memory location meta data failed");
- return -1;
- }
- if ((mr->dimm_name[0] != '\0') &&
- (plugin_notification_meta_add_string(n, MCELOG_DIMM_NAME, mr->dimm_name) <
- 0)) {
- ERROR(MCELOG_PLUGIN ": add DIMM name meta data failed");
- plugin_notification_meta_free(n->meta);
- return -1;
- }
- if (plugin_notification_meta_add_signed_int(n, MCELOG_CORRECTED_ERR,
- mr->corrected_err_total) < 0) {
- ERROR(MCELOG_PLUGIN ": add corrected errors meta data failed");
- plugin_notification_meta_free(n->meta);
- return -1;
- }
- if (plugin_notification_meta_add_signed_int(
- n, "corrected memory timed errors", mr->corrected_err_timed) < 0) {
- ERROR(MCELOG_PLUGIN ": add corrected timed errors meta data failed");
- plugin_notification_meta_free(n->meta);
+ int dispatch_corrected_notifs = 0, dispatch_uncorrected_notifs = 0;
+
+ if (mr == NULL)
return -1;
- }
- if ((mr->corrected_err_timed_period[0] != '\0') &&
- (plugin_notification_meta_add_string(n, "corrected errors time period",
- mr->corrected_err_timed_period) <
- 0)) {
- ERROR(MCELOG_PLUGIN ": add corrected errors period meta data failed");
- plugin_notification_meta_free(n->meta);
+
+ llentry_t *dimm = mcelog_dimm(mr, g_mcelog_config.dimms_list);
+ if (dimm == NULL) {
+ ERROR(MCELOG_PLUGIN
+ ": Error adding/getting dimm memory item to/from cache");
return -1;
}
- if (plugin_notification_meta_add_signed_int(n, MCELOG_UNCORRECTED_ERR,
- mr->uncorrected_err_total) < 0) {
- ERROR(MCELOG_PLUGIN ": add corrected errors meta data failed");
- plugin_notification_meta_free(n->meta);
- return -1;
+ mcelog_memory_rec_t *mr_old = dimm->value;
+ if (!g_mcelog_config.persist) {
+
+ if (mr_old->corrected_err_total != mr->corrected_err_total ||
+ mr_old->corrected_err_timed != mr->corrected_err_timed)
+ dispatch_corrected_notifs = 1;
+
+ if (mr_old->uncorrected_err_total != mr->uncorrected_err_total ||
+ mr_old->uncorrected_err_timed != mr->uncorrected_err_timed)
+ dispatch_uncorrected_notifs = 1;
+
+ if (!dispatch_corrected_notifs && !dispatch_uncorrected_notifs) {
+ DEBUG("%s: No new notifications to dispatch", MCELOG_PLUGIN);
+ return 0;
+ }
+ } else {
+ dispatch_corrected_notifs = 1;
+ dispatch_uncorrected_notifs = 1;
}
- if (plugin_notification_meta_add_signed_int(n,
- "uncorrected memory timed errors",
- mr->uncorrected_err_timed) < 0) {
- ERROR(MCELOG_PLUGIN ": add corrected timed errors meta data failed");
- plugin_notification_meta_free(n->meta);
- return -1;
+
+ sstrncpy(n.host, hostname_g, sizeof(n.host));
+
+ if (mr->dimm_name[0] != '\0')
+ snprintf(n.plugin_instance, sizeof(n.plugin_instance), "%s_%s",
+ mr->location, mr->dimm_name);
+ else
+ sstrncpy(n.plugin_instance, mr->location, sizeof(n.plugin_instance));
+
+ if (dispatch_corrected_notifs &&
+ (mr->corrected_err_total > 0 || mr->corrected_err_timed > 0)) {
+ /* Corrected Error Notifications */
+ plugin_notification_meta_add_signed_int(&n, MCELOG_CORRECTED_ERR,
+ mr->corrected_err_total);
+ plugin_notification_meta_add_signed_int(&n, MCELOG_CORRECTED_ERR_TIMED,
+ mr->corrected_err_timed);
+ snprintf(n.message, sizeof(n.message), MCELOG_CORRECTED_ERR);
+ sstrncpy(n.type_instance, MCELOG_CORRECTED_ERR_TYPE_INS,
+ sizeof(n.type_instance));
+ plugin_dispatch_notification(&n);
+ if (n.meta)
+ plugin_notification_meta_free(n.meta);
+ n.meta = NULL;
}
- if ((mr->uncorrected_err_timed_period[0] != '\0') &&
- (plugin_notification_meta_add_string(n, "uncorrected errors time period",
- mr->uncorrected_err_timed_period) <
- 0)) {
- ERROR(MCELOG_PLUGIN ": add corrected errors period meta data failed");
- plugin_notification_meta_free(n->meta);
- return -1;
+
+ if (dispatch_uncorrected_notifs &&
+ (mr->uncorrected_err_total > 0 || mr->uncorrected_err_timed > 0)) {
+ /* Uncorrected Error Notifications */
+ plugin_notification_meta_add_signed_int(&n, MCELOG_UNCORRECTED_ERR,
+ mr->uncorrected_err_total);
+ plugin_notification_meta_add_signed_int(&n, MCELOG_UNCORRECTED_ERR_TIMED,
+ mr->uncorrected_err_timed);
+ snprintf(n.message, sizeof(n.message), MCELOG_UNCORRECTED_ERR);
+ sstrncpy(n.type_instance, MCELOG_UNCORRECTED_ERR_TYPE_INS,
+ sizeof(n.type_instance));
+ n.severity = NOTIF_FAILURE;
+ plugin_dispatch_notification(&n);
+ if (n.meta)
+ plugin_notification_meta_free(n.meta);
+ n.meta = NULL;
}
return 0;
return -1;
}
+ llentry_t *dimm = mcelog_dimm(mr, g_mcelog_config.dimms_list);
+ if (dimm == NULL) {
+ ERROR(MCELOG_PLUGIN
+ ": Error adding/getting dimm memory item to/from cache");
+ return -1;
+ }
+
value_list_t vl = {
.values_len = 1,
.values = &(value_t){.derive = (derive_t)mr->corrected_err_total},
.time = cdtime(),
.plugin = MCELOG_PLUGIN,
.type = "errors",
- .type_instance = "corrected_memory_errors"};
+ .type_instance = MCELOG_CORRECTED_ERR_TYPE_INS};
+
+ mcelog_update_dimm_stats(dimm, mr);
if (mr->dimm_name[0] != '\0')
snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s_%s",
vl.values = &(value_t){.derive = (derive_t)mr->corrected_err_timed};
plugin_dispatch_values(&vl);
- sstrncpy(vl.type_instance, "uncorrected_memory_errors",
+ sstrncpy(vl.type_instance, MCELOG_UNCORRECTED_ERR_TYPE_INS,
sizeof(vl.type_instance));
vl.values = &(value_t){.derive = (derive_t)mr->uncorrected_err_total};
plugin_dispatch_values(&vl);
if ((res = poll(&poll_fd, 1, MCELOG_POLL_TIMEOUT)) <= 0) {
if (res != 0 && errno != EINTR) {
- char errbuf[MCELOG_BUFF_SIZE];
- ERROR("mcelog: poll failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("mcelog: poll failed: %s", STRERRNO);
}
pthread_rwlock_unlock(&self->lock);
return res;
}
static void *poll_worker(__attribute__((unused)) void *arg) {
- char errbuf[MCELOG_BUFF_SIZE];
mcelog_thread_running = 1;
FILE **pp_file = calloc(1, sizeof(*pp_file));
if (pp_file == NULL) {
- ERROR("mcelog: memory allocation failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("mcelog: memory allocation failed: %s", STRERRNO);
pthread_exit((void *)1);
}
continue;
}
- notification_t n = {.severity = NOTIF_OKAY,
- .time = cdtime(),
- .message = "Got memory errors info.",
- .plugin = MCELOG_PLUGIN,
- .type_instance = "memory_erros"};
-
- if (mcelog_prepare_notification(&n, &memory_record) == 0)
- mcelog_dispatch_notification(&n);
+ if (mcelog_dispatch_mem_notifications(&memory_record) != 0)
+ ERROR(MCELOG_PLUGIN ": Failed to submit memory errors notification");
if (mcelog_submit(&memory_record) != 0)
ERROR(MCELOG_PLUGIN ": Failed to submit memory errors");
memset(&memory_record, 0, sizeof(memory_record));
}
static int mcelog_init(void) {
+ if (mcelog_apply_defaults) {
+ INFO(MCELOG_PLUGIN
+ ": No configuration selected defaulting to memory errors.");
+ memset(g_mcelog_config.logfile, 0, sizeof(g_mcelog_config.logfile));
+ }
+ g_mcelog_config.dimms_list = llist_create();
+ int err = pthread_mutex_init(&g_mcelog_config.dimms_lock, NULL);
+ if (err < 0) {
+ ERROR(MCELOG_PLUGIN ": plugin: failed to initialize cache lock");
+ return -1;
+ }
+
if (socket_adapter.reinit(&socket_adapter) != 0) {
ERROR(MCELOG_PLUGIN ": Cannot connect to client socket");
return -1;
}
- if (plugin_thread_create(&g_mcelog_config.tid, NULL, poll_worker, NULL,
- NULL) != 0) {
- ERROR(MCELOG_PLUGIN ": Error creating poll thread.");
- return -1;
+ if (strlen(socket_adapter.unix_sock.sun_path)) {
+ if (plugin_thread_create(&g_mcelog_config.tid, NULL, poll_worker, NULL,
+ NULL) != 0) {
+ ERROR(MCELOG_PLUGIN ": Error creating poll thread.");
+ return -1;
+ }
}
return 0;
}
ret = -1;
}
}
-
+ pthread_mutex_lock(&g_mcelog_config.dimms_lock);
+ mcelog_free_dimms_list_records(g_mcelog_config.dimms_list);
+ llist_destroy(g_mcelog_config.dimms_list);
+ g_mcelog_config.dimms_list = NULL;
+ pthread_mutex_unlock(&g_mcelog_config.dimms_lock);
+ pthread_mutex_destroy(&g_mcelog_config.dimms_lock);
ret = socket_adapter.close(&socket_adapter) || ret;
pthread_rwlock_destroy(&(socket_adapter.lock));
return -ret;
} /* void md_submit */
static void md_process(const int minor, const char *path) {
- char errbuf[1024];
int fd;
struct stat st;
mdu_array_info_t array;
fd = open(path, O_RDONLY);
if (fd < 0) {
- WARNING("md: open(%s): %s", path, sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("md: open(%s): %s", path, STRERRNO);
return;
}
if (fstat(fd, &st) < 0) {
- WARNING("md: Unable to fstat file descriptor for %s: %s", path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("md: Unable to fstat file descriptor for %s: %s", path, STRERRNO);
close(fd);
return;
}
/* Retrieve md information */
if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) {
- WARNING("md: Unable to retrieve array info from %s: %s", path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("md: Unable to retrieve array info from %s: %s", path, STRERRNO);
close(fd);
return;
}
fh = fopen(PROC_DISKSTATS, "r");
if (fh == NULL) {
- char errbuf[1024];
- WARNING("md: Unable to open %s: %s", PROC_DISKSTATS,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("md: Unable to open %s: %s", PROC_DISKSTATS, STRERRNO);
return -1;
}
typedef struct web_page_s web_page_t;
struct web_page_s /* {{{ */
{
+ char *plugin_name;
char *instance;
char *server;
memcached_free(wp->memc);
wp->memc = NULL;
+ sfree(wp->plugin_name);
sfree(wp->instance);
sfree(wp->server);
sfree(wp->key);
status = cmc_config_add_string("Server", &page->server, child);
else if (strcasecmp("Key", child->key) == 0)
status = cmc_config_add_string("Key", &page->key, child);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cmc_config_add_string("Plugin", &page->plugin_name, child);
else if (strcasecmp("Match", child->key) == 0)
/* Be liberal with failing matches => don't set `status'. */
cmc_config_add_match(page, child);
vl.values = &value;
vl.values_len = 1;
- sstrncpy(vl.plugin, "memcachec", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (wp->plugin_name != NULL) ? wp->plugin_name : "memcachec",
+ sizeof (vl.plugin));
sstrncpy(vl.plugin_instance, wp->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, wm->type, sizeof(vl.type));
sstrncpy(vl.type_instance, wm->instance, sizeof(vl.type_instance));
* Copyright (C) 2009 Doug MacEachern
* Copyright (C) 2009 Franck Lombardi
* Copyright (C) 2012 Nicolas Szalay
+ * Copyright (C) 2017 Pavel Rochnyak
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Doug MacEachern <dougm at hyperic.com>
* Franck Lombardi
* Nicolas Szalay
+ * Pavel Rochnyak <pavel2000 ngs.ru>
**/
#include "collectd.h"
#include <netinet/tcp.h>
#include <sys/un.h>
+#include <poll.h>
+
#define MEMCACHED_DEF_HOST "127.0.0.1"
#define MEMCACHED_DEF_PORT "11211"
+#define MEMCACHED_CONNECT_TIMEOUT 10000
+#define MEMCACHED_IO_TIMEOUT 5000
+
+struct prev_s {
+ derive_t hits;
+ derive_t gets;
+ derive_t incr_hits;
+ derive_t incr_misses;
+ derive_t decr_hits;
+ derive_t decr_misses;
+};
+
+typedef struct prev_s prev_t;
struct memcached_s {
char *name;
char *socket;
char *connhost;
char *connport;
+ int fd;
+ prev_t prev;
};
typedef struct memcached_s memcached_t;
if (st == NULL)
return;
+ if (st->fd >= 0) {
+ shutdown(st->fd, SHUT_RDWR);
+ close(st->fd);
+ st->fd = -1;
+ }
+
sfree(st->name);
sfree(st->host);
sfree(st->socket);
static int memcached_connect_unix(memcached_t *st) {
struct sockaddr_un serv_addr = {0};
- int fd;
serv_addr.sun_family = AF_UNIX;
sstrncpy(serv_addr.sun_path, st->socket, sizeof(serv_addr.sun_path));
/* create our socket descriptor */
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
- char errbuf[1024];
ERROR("memcached plugin: memcached_connect_unix: socket(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
if (status != 0) {
shutdown(fd, SHUT_RDWR);
close(fd);
- fd = -1;
+ return -1;
+ }
+
+ /* switch to non-blocking mode */
+ int flags = fcntl(fd, F_GETFL);
+ status = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ if (status != 0) {
+ close(fd);
+ return -1;
}
return fd;
static int memcached_connect_inet(memcached_t *st) {
struct addrinfo *ai_list;
- int status;
int fd = -1;
struct addrinfo ai_hints = {.ai_family = AF_UNSPEC,
.ai_flags = AI_ADDRCONFIG,
.ai_socktype = SOCK_STREAM};
- status = getaddrinfo(st->connhost, st->connport, &ai_hints, &ai_list);
+ int status = getaddrinfo(st->connhost, st->connport, &ai_hints, &ai_list);
if (status != 0) {
- char errbuf[1024];
ERROR("memcached plugin: memcached_connect_inet: "
"getaddrinfo(%s,%s) failed: %s",
st->connhost, st->connport,
- (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(status));
+ (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
return -1;
}
/* create our socket descriptor */
fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (fd < 0) {
- char errbuf[1024];
WARNING("memcached plugin: memcached_connect_inet: "
"socket(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
+ continue;
+ }
+
+ /* switch socket to non-blocking mode */
+ int flags = fcntl(fd, F_GETFL);
+ status = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+ if (status != 0) {
+ close(fd);
+ fd = -1;
continue;
}
/* connect to the memcached daemon */
status = (int)connect(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
- if (status != 0) {
+ if (status != 0 && errno != EINPROGRESS) {
shutdown(fd, SHUT_RDWR);
close(fd);
fd = -1;
continue;
}
- /* A socket could be opened and connecting succeeded. We're done. */
+ /* Wait until connection establishes */
+ struct pollfd pollfd = {
+ .fd = fd, .events = POLLOUT,
+ };
+ do
+ status = poll(&pollfd, 1, MEMCACHED_CONNECT_TIMEOUT);
+ while (status < 0 && errno == EINTR);
+ if (status <= 0) {
+ close(fd);
+ fd = -1;
+ continue;
+ }
+
+ /* Check if all is good */
+ int socket_error;
+ status = getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&socket_error,
+ &(socklen_t){sizeof(socket_error)});
+ if (status != 0 || socket_error != 0) {
+ close(fd);
+ fd = -1;
+ continue;
+ }
+ /* A socket is opened and connection succeeded. We're done. */
break;
}
return fd;
} /* int memcached_connect_inet */
-static int memcached_connect(memcached_t *st) {
+static void memcached_connect(memcached_t *st) {
+ if (st->fd >= 0)
+ return;
+
if (st->socket != NULL)
- return memcached_connect_unix(st);
+ st->fd = memcached_connect_unix(st);
else
- return memcached_connect_inet(st);
+ st->fd = memcached_connect_inet(st);
+
+ if (st->fd >= 0)
+ INFO("memcached plugin: Instance \"%s\": connection established.",
+ st->name);
}
static int memcached_query_daemon(char *buffer, size_t buffer_size,
memcached_t *st) {
- int fd, status;
+ int status;
size_t buffer_fill;
- fd = memcached_connect(st);
- if (fd < 0) {
+ memcached_connect(st);
+ if (st->fd < 0) {
ERROR("memcached plugin: Instance \"%s\" could not connect to daemon.",
st->name);
return -1;
}
- status = (int)swrite(fd, "stats\r\n", strlen("stats\r\n"));
+ struct pollfd pollfd = {
+ .fd = st->fd, .events = POLLOUT,
+ };
+
+ do
+ status = poll(&pollfd, 1, MEMCACHED_IO_TIMEOUT);
+ while (status < 0 && errno == EINTR);
+
+ if (status <= 0) {
+ ERROR("memcached plugin: poll() failed for write() call.");
+ close(st->fd);
+ st->fd = -1;
+ return -1;
+ }
+
+ status = (int)swrite(st->fd, "stats\r\n", strlen("stats\r\n"));
if (status != 0) {
- char errbuf[1024];
- ERROR("memcached plugin: write(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- shutdown(fd, SHUT_RDWR);
- close(fd);
+ ERROR("memcached plugin: Instance \"%s\": write(2) failed: %s", st->name,
+ STRERRNO);
+ shutdown(st->fd, SHUT_RDWR);
+ close(st->fd);
+ st->fd = -1;
return -1;
}
memset(buffer, 0, buffer_size);
buffer_fill = 0;
- while ((status = (int)recv(fd, buffer + buffer_fill,
- buffer_size - buffer_fill, /* flags = */ 0)) !=
- 0) {
+ pollfd.events = POLLIN;
+ while (1) {
+ do
+ status = poll(&pollfd, 1, MEMCACHED_IO_TIMEOUT);
+ while (status < 0 && errno == EINTR);
+
+ if (status <= 0) {
+ ERROR("memcached plugin: Instance \"%s\": Timeout reading from socket",
+ st->name);
+ close(st->fd);
+ st->fd = -1;
+ return -1;
+ }
+
+ do
+ status = (int)recv(st->fd, buffer + buffer_fill,
+ buffer_size - buffer_fill, /* flags = */ 0);
+ while (status < 0 && errno == EINTR);
+
char const end_token[5] = {'E', 'N', 'D', '\r', '\n'};
if (status < 0) {
- char errbuf[1024];
- if ((errno == EAGAIN) || (errno == EINTR))
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
continue;
- ERROR("memcached: Error reading from socket: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- shutdown(fd, SHUT_RDWR);
- close(fd);
+ ERROR("memcached plugin: Instance \"%s\": Error reading from socket: %s",
+ st->name, STRERRNO);
+ shutdown(st->fd, SHUT_RDWR);
+ close(st->fd);
+ st->fd = -1;
+ return -1;
+ } else if (status == 0) {
+ ERROR("memcached plugin: Instance \"%s\": Connection closed by peer",
+ st->name);
+ close(st->fd);
+ st->fd = -1;
return -1;
}
buffer_fill += (size_t)status;
if (buffer_fill > buffer_size) {
buffer_fill = buffer_size;
- WARNING("memcached plugin: Message was truncated.");
+ WARNING("memcached plugin: Instance \"%s\": Message was truncated.",
+ st->name);
+ shutdown(st->fd, SHUT_RDWR);
+ close(st->fd);
+ st->fd = -1;
break;
}
status = 0;
if (buffer_fill == 0) {
- WARNING("memcached plugin: No data returned by memcached.");
+ WARNING("memcached plugin: Instance \"%s\": No data returned by memcached.",
+ st->name);
status = -1;
}
- shutdown(fd, SHUT_RDWR);
- close(fd);
return status;
} /* int memcached_query_daemon */
plugin_dispatch_values(&vl);
}
+static gauge_t calculate_ratio_percent(derive_t part, derive_t total,
+ derive_t *prev_part,
+ derive_t *prev_total) {
+ if ((*prev_part == 0) || (*prev_total == 0) || (part < *prev_part) ||
+ (total < *prev_total)) {
+ *prev_part = part;
+ *prev_total = total;
+ return NAN;
+ }
+
+ derive_t num = part - *prev_part;
+ derive_t denom = total - *prev_total;
+
+ *prev_part = part;
+ *prev_total = total;
+
+ if (denom == 0)
+ return NAN;
+
+ if (num == 0)
+ return 0;
+
+ return 100.0 * (gauge_t)num / (gauge_t)denom;
+}
+
+static gauge_t calculate_ratio_percent2(derive_t part1, derive_t part2,
+ derive_t *prev1, derive_t *prev2) {
+ if ((*prev1 == 0) || (*prev2 == 0) || (part1 < *prev1) || (part2 < *prev2)) {
+ *prev1 = part1;
+ *prev2 = part2;
+ return NAN;
+ }
+
+ derive_t num = part1 - *prev1;
+ derive_t denom = part2 - *prev2 + num;
+
+ *prev1 = part1;
+ *prev2 = part2;
+
+ if (denom == 0)
+ return NAN;
+
+ if (num == 0)
+ return 0;
+
+ return 100.0 * (gauge_t)num / (gauge_t)denom;
+}
+
static int memcached_read(user_data_t *user_data) {
char buf[4096];
char *fields[3];
- char *ptr;
char *line;
- char *saveptr;
- int fields_num;
-
- gauge_t bytes_used = NAN;
- gauge_t bytes_total = NAN;
- gauge_t hits = NAN;
- gauge_t gets = NAN;
- gauge_t incr_hits = NAN;
- derive_t incr = 0;
- gauge_t decr_hits = NAN;
- derive_t decr = 0;
+
+ derive_t bytes_used = 0;
+ derive_t bytes_total = 0;
+ derive_t get_hits = 0;
+ derive_t cmd_get = 0;
+ derive_t incr_hits = 0;
+ derive_t incr_misses = 0;
+ derive_t decr_hits = 0;
+ derive_t decr_misses = 0;
derive_t rusage_user = 0;
derive_t rusage_syst = 0;
derive_t octets_rx = 0;
derive_t octets_tx = 0;
- memcached_t *st;
- st = user_data->data;
+ memcached_t *st = user_data->data;
+ prev_t *prev = &st->prev;
/* get data from daemon */
if (memcached_query_daemon(buf, sizeof(buf), st) < 0) {
#define FIELD_IS(cnst) \
(((sizeof(cnst) - 1) == name_len) && (strcmp(cnst, fields[1]) == 0))
- ptr = buf;
- saveptr = NULL;
+ char *ptr = buf;
+ char *saveptr = NULL;
while ((line = strtok_r(ptr, "\n\r", &saveptr)) != NULL) {
- int name_len;
-
ptr = NULL;
- fields_num = strsplit(line, fields, 3);
- if (fields_num != 3)
+ if (strsplit(line, fields, 3) != 3)
continue;
- name_len = strlen(fields[1]);
+ int name_len = strlen(fields[1]);
if (name_len == 0)
continue;
* CPU time consumed by the memcached process
*/
if (FIELD_IS("rusage_user")) {
- rusage_user = atoll(fields[2]);
+ /* Convert to useconds */
+ rusage_user = atof(fields[2]) * 1000000;
} else if (FIELD_IS("rusage_system")) {
- rusage_syst = atoll(fields[2]);
+ rusage_syst = atof(fields[2]) * 1000000;
}
/*
* Number of bytes used and available (total - used)
*/
else if (FIELD_IS("bytes")) {
- bytes_used = atof(fields[2]);
+ bytes_used = atoll(fields[2]);
} else if (FIELD_IS("limit_maxbytes")) {
- bytes_total = atof(fields[2]);
+ bytes_total = atoll(fields[2]);
}
/*
else if (FIELD_IS("curr_connections")) {
submit_gauge("memcached_connections", "current", atof(fields[2]), st);
} else if (FIELD_IS("listen_disabled_num")) {
- submit_derive("connections", "listen_disabled", atof(fields[2]), st);
+ submit_derive("total_events", "listen_disabled", atoll(fields[2]), st);
+ }
+ /*
+ * Total number of connections opened since the server started running
+ * Report this as connection rate.
+ */
+ else if (FIELD_IS("total_connections")) {
+ submit_derive("connections", "opened", atoll(fields[2]), st);
}
/*
const char *name = fields[1] + 4;
submit_derive("memcached_command", name, atoll(fields[2]), st);
if (strcmp(name, "get") == 0)
- gets = atof(fields[2]);
+ cmd_get = atoll(fields[2]);
}
/*
* Increment/Decrement
*/
else if (FIELD_IS("incr_misses")) {
- derive_t incr_count = atoll(fields[2]);
- submit_derive("memcached_ops", "incr_misses", incr_count, st);
- incr += incr_count;
+ incr_misses = atoll(fields[2]);
+ submit_derive("memcached_ops", "incr_misses", incr_misses, st);
} else if (FIELD_IS("incr_hits")) {
- derive_t incr_count = atoll(fields[2]);
- submit_derive("memcached_ops", "incr_hits", incr_count, st);
- incr_hits = atof(fields[2]);
- incr += incr_count;
+ incr_hits = atoll(fields[2]);
+ submit_derive("memcached_ops", "incr_hits", incr_hits, st);
} else if (FIELD_IS("decr_misses")) {
- derive_t decr_count = atoll(fields[2]);
- submit_derive("memcached_ops", "decr_misses", decr_count, st);
- decr += decr_count;
+ decr_misses = atoll(fields[2]);
+ submit_derive("memcached_ops", "decr_misses", decr_misses, st);
} else if (FIELD_IS("decr_hits")) {
- derive_t decr_count = atoll(fields[2]);
- submit_derive("memcached_ops", "decr_hits", decr_count, st);
- decr_hits = atof(fields[2]);
- decr += decr_count;
+ decr_hits = atoll(fields[2]);
+ submit_derive("memcached_ops", "decr_hits", decr_hits, st);
}
/*
* - evictions
*/
else if (FIELD_IS("get_hits")) {
- submit_derive("memcached_ops", "hits", atoll(fields[2]), st);
- hits = atof(fields[2]);
+ get_hits = atoll(fields[2]);
+ submit_derive("memcached_ops", "hits", get_hits, st);
} else if (FIELD_IS("get_misses")) {
submit_derive("memcached_ops", "misses", atoll(fields[2]), st);
} else if (FIELD_IS("evictions")) {
}
} /* while ((line = strtok_r (ptr, "\n\r", &saveptr)) != NULL) */
- if (!isnan(bytes_used) && !isnan(bytes_total) && (bytes_used <= bytes_total))
+ if ((bytes_total > 0) && (bytes_used <= bytes_total))
submit_gauge2("df", "cache", bytes_used, bytes_total - bytes_used, st);
if ((rusage_user != 0) || (rusage_syst != 0))
if ((octets_rx != 0) || (octets_tx != 0))
submit_derive2("memcached_octets", NULL, octets_rx, octets_tx, st);
- if (!isnan(gets) && !isnan(hits)) {
- gauge_t rate = NAN;
-
- if (gets != 0.0)
- rate = 100.0 * hits / gets;
-
- submit_gauge("percent", "hitratio", rate, st);
+ if ((cmd_get != 0) && (get_hits != 0)) {
+ gauge_t ratio =
+ calculate_ratio_percent(get_hits, cmd_get, &prev->hits, &prev->gets);
+ submit_gauge("percent", "hitratio", ratio, st);
}
- if (!isnan(incr_hits) && incr != 0) {
- gauge_t incr_rate = 100.0 * incr_hits / incr;
- submit_gauge("percent", "incr_hitratio", incr_rate, st);
- submit_derive("memcached_ops", "incr", incr, st);
+ if ((incr_hits != 0) && (incr_misses != 0)) {
+ gauge_t ratio = calculate_ratio_percent2(
+ incr_hits, incr_misses, &prev->incr_hits, &prev->incr_misses);
+ submit_gauge("percent", "incr_hitratio", ratio, st);
+ submit_derive("memcached_ops", "incr", incr_hits + incr_misses, st);
}
- if (!isnan(decr_hits) && decr != 0) {
- gauge_t decr_rate = 100.0 * decr_hits / decr;
- submit_gauge("percent", "decr_hitratio", decr_rate, st);
- submit_derive("memcached_ops", "decr", decr, st);
+ if ((decr_hits != 0) && (decr_misses != 0)) {
+ gauge_t ratio = calculate_ratio_percent2(
+ decr_hits, decr_misses, &prev->decr_hits, &prev->decr_misses);
+ submit_gauge("percent", "decr_hitratio", ratio, st);
+ submit_derive("memcached_ops", "decr", decr_hits + decr_misses, st);
}
return 0;
} /* int memcached_read */
-static int memcached_add_read_callback(memcached_t *st) {
- char callback_name[3 * DATA_MAX_NAME_LEN];
- int status;
-
- snprintf(callback_name, sizeof(callback_name), "memcached/%s",
- (st->name != NULL) ? st->name : "__legacy__");
-
+static int memcached_set_defaults(memcached_t *st) {
/* If no <Address> used then:
* - Connect to the destination specified by <Host>, if present.
* If not, use the default address.
assert(st->connhost != NULL);
assert(st->connport != NULL);
- status = plugin_register_complex_read(
+ st->prev.hits = 0;
+ st->prev.gets = 0;
+ st->prev.incr_hits = 0;
+ st->prev.incr_misses = 0;
+ st->prev.decr_hits = 0;
+ st->prev.decr_misses = 0;
+
+ return 0;
+} /* int memcached_set_defaults */
+
+static int memcached_add_read_callback(memcached_t *st) {
+ char callback_name[3 * DATA_MAX_NAME_LEN];
+
+ if (memcached_set_defaults(st) != 0) {
+ memcached_free(st);
+ return -1;
+ }
+
+ snprintf(callback_name, sizeof(callback_name), "memcached/%s",
+ (st->name != NULL) ? st->name : "__legacy__");
+
+ return plugin_register_complex_read(
/* group = */ "memcached",
/* name = */ callback_name,
/* callback = */ memcached_read,
&(user_data_t){
.data = st, .free_func = memcached_free,
});
-
- return status;
} /* int memcached_add_read_callback */
/* Configuration handling functiions
* </Plugin>
*/
static int config_add_instance(oconfig_item_t *ci) {
- memcached_t *st;
int status = 0;
/* Disable automatic generation of default instance in the init callback. */
memcached_have_instances = 1;
- st = calloc(1, sizeof(*st));
+ memcached_t *st = calloc(1, sizeof(*st));
if (st == NULL) {
ERROR("memcached plugin: calloc failed.");
return ENOMEM;
st->connhost = NULL;
st->connport = NULL;
+ st->fd = -1;
+
if (strcasecmp(ci->key, "Instance") == 0)
status = cf_util_get_string(ci, &st->name);
break;
}
- if (status == 0)
- status = memcached_add_read_callback(st);
-
if (status != 0) {
memcached_free(st);
return -1;
}
- return 0;
-}
+ return memcached_add_read_callback(st);
+} /* int config_add_instance */
static int memcached_config(oconfig_item_t *ci) {
- int status = 0;
_Bool have_instance_block = 0;
for (int i = 0; i < ci->children_num; i++) {
child->key);
} /* for (ci->children) */
- return status;
-}
+ return 0;
+} /* int memcached_config */
static int memcached_init(void) {
- memcached_t *st;
- int status;
if (memcached_have_instances)
return 0;
/* No instances were configured, lets start a default instance. */
- st = calloc(1, sizeof(*st));
+ memcached_t *st = calloc(1, sizeof(*st));
if (st == NULL)
return ENOMEM;
st->name = NULL;
st->connhost = NULL;
st->connport = NULL;
- status = memcached_add_read_callback(st);
+ st->fd = -1;
+
+ int status = memcached_add_read_callback(st);
if (status == 0)
memcached_have_instances = 1;
- else
- memcached_free(st);
return status;
} /* int memcached_init */
gauge_t mem_slab_unreclaimable = 0;
if ((fh = fopen("/proc/meminfo", "r")) == NULL) {
- char errbuf[1024];
- WARNING("memory: fopen: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("memory: fopen: %s", STRERRNO);
return -1;
}
}
if (fclose(fh)) {
- char errbuf[1024];
- WARNING("memory: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("memory: fclose: %s", STRERRNO);
}
if (mem_total < (mem_free + mem_buffered + mem_cached + mem_slab_total))
size = sizeof(vmtotal);
if (sysctl(mib, 2, &vmtotal, &size, NULL, 0) < 0) {
- char errbuf[1024];
- WARNING("memory plugin: sysctl failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("memory plugin: sysctl failed: %s", STRERRNO);
return -1;
}
perfstat_memory_total_t pmemory = {0};
if (perfstat_memory_total(NULL, &pmemory, sizeof(pmemory), 1) < 0) {
- char errbuf[1024];
- WARNING("memory plugin: perfstat_memory_total failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("memory plugin: perfstat_memory_total failed: %s", STRERRNO);
return -1;
}
vl.values = &(value_t){.gauge = value};
vl.values_len = 1;
- strncpy(vl.host, hostname_g, sizeof(vl.host));
strncpy(vl.plugin, "mic", sizeof(vl.plugin));
snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
strncpy(vl.type, "temperature", sizeof(vl.type));
vl.values = &(value_t){.derive = value};
vl.values_len = 1;
- strncpy(vl.host, hostname_g, sizeof(vl.host));
strncpy(vl.plugin, "mic", sizeof(vl.plugin));
if (core < 0) /* global aggregation */
snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
vl.values = &(value_t){.gauge = value};
vl.values_len = 1;
- strncpy(vl.host, hostname_g, sizeof(vl.host));
strncpy(vl.plugin, "mic", sizeof(vl.plugin));
snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
strncpy(vl.type, type, sizeof(vl.type));
enum mb_register_type_e /* {{{ */
{ REG_TYPE_INT16,
REG_TYPE_INT32,
+ REG_TYPE_INT32_CDAB,
REG_TYPE_UINT16,
REG_TYPE_UINT32,
- REG_TYPE_FLOAT }; /* }}} */
+ REG_TYPE_UINT32_CDAB,
+ REG_TYPE_FLOAT,
+ REG_TYPE_FLOAT_CDAB }; /* }}} */
+
enum mb_mreg_type_e /* {{{ */
{ MREG_HOLDING,
MREG_INPUT }; /* }}} */
}
if (ds->ds_num != 1) {
- ERROR("Modbus plugin: The type \"%s\" has %zu data sources. "
+ ERROR("Modbus plugin: The type \"%s\" has %" PRIsz " data sources. "
"I can only handle data sets with only one data source.",
data->type, ds->ds_num);
return -1;
if ((ds->ds[0].type != DS_TYPE_GAUGE) &&
(data->register_type != REG_TYPE_INT32) &&
- (data->register_type != REG_TYPE_UINT32)) {
+ (data->register_type != REG_TYPE_INT32_CDAB) &&
+ (data->register_type != REG_TYPE_UINT32) &&
+ (data->register_type != REG_TYPE_UINT32_CDAB)) {
NOTICE(
"Modbus plugin: The data source of type \"%s\" is %s, not gauge. "
"This will most likely result in problems, because the register type "
}
if ((data->register_type == REG_TYPE_INT32) ||
+ (data->register_type == REG_TYPE_INT32_CDAB) ||
(data->register_type == REG_TYPE_UINT32) ||
- (data->register_type == REG_TYPE_FLOAT))
+ (data->register_type == REG_TYPE_UINT32_CDAB) ||
+ (data->register_type == REG_TYPE_FLOAT) ||
+ (data->register_type == REG_TYPE_FLOAT_CDAB))
values_num = 2;
else
values_num = 1;
}
if (status != values_num) {
ERROR("Modbus plugin: modbus read function (%s/%s) failed. "
- " status = %i, values_num = %i. Giving up.",
- host->host, host->node, status, values_num);
+ " status = %i, start_addr = %i, values_num = %i. Giving up.",
+ host->host, host->node, status, data->register_base, values_num);
#if LEGACY_LIBMODBUS
modbus_close(&host->connection);
#else
CAST_TO_VALUE_T(ds, vt, float_value);
mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_FLOAT_CDAB) {
+ float float_value;
+ value_t vt;
+
+ float_value = mb_register_to_float(values[1], values[0]);
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned float value is %g",
+ (double)float_value);
+
+ CAST_TO_VALUE_T(ds, vt, float_value);
+ mb_submit(host, slave, data, vt);
} else if (data->register_type == REG_TYPE_INT32) {
union {
uint32_t u32;
CAST_TO_VALUE_T(ds, vt, v.i32);
mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_INT32_CDAB) {
+ union {
+ uint32_t u32;
+ int32_t i32;
+ } v;
+ value_t vt;
+
+ v.u32 = (((uint32_t)values[1]) << 16) | ((uint32_t)values[0]);
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned int32 value is %" PRIi32,
+ v.i32);
+
+ CAST_TO_VALUE_T(ds, vt, v.i32);
+ mb_submit(host, slave, data, vt);
} else if (data->register_type == REG_TYPE_INT16) {
union {
uint16_t u16;
CAST_TO_VALUE_T(ds, vt, v32);
mb_submit(host, slave, data, vt);
+ } else if (data->register_type == REG_TYPE_UINT32_CDAB) {
+ uint32_t v32;
+ value_t vt;
+
+ v32 = (((uint32_t)values[1]) << 16) | ((uint32_t)values[0]);
+ DEBUG("Modbus plugin: mb_read_data: "
+ "Returned uint32 value is %" PRIu32,
+ v32);
+
+ CAST_TO_VALUE_T(ds, vt, v32);
+ mb_submit(host, slave, data, vt);
} else /* if (data->register_type == REG_TYPE_UINT16) */
{
value_t vt;
data.register_type = REG_TYPE_INT16;
else if (strcasecmp("Int32", tmp) == 0)
data.register_type = REG_TYPE_INT32;
+ else if (strcasecmp("Int32LE", tmp) == 0)
+ data.register_type = REG_TYPE_INT32_CDAB;
else if (strcasecmp("Uint16", tmp) == 0)
data.register_type = REG_TYPE_UINT16;
else if (strcasecmp("Uint32", tmp) == 0)
data.register_type = REG_TYPE_UINT32;
+ else if (strcasecmp("Uint32LE", tmp) == 0)
+ data.register_type = REG_TYPE_UINT32_CDAB;
else if (strcasecmp("Float", tmp) == 0)
data.register_type = REG_TYPE_FLOAT;
+ else if (strcasecmp("FloatLE", tmp) == 0)
+ data.register_type = REG_TYPE_FLOAT_CDAB;
else {
ERROR("Modbus plugin: The register type \"%s\" is unknown.", tmp);
status = -1;
status = getaddrinfo(address, /* service = */ NULL, &ai_hints, &ai_list);
if (status != 0) {
- char errbuf[1024];
ERROR("Modbus plugin: getaddrinfo failed: %s",
- (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(status));
+ (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
return status;
}
status = mosquitto_reconnect(conf->mosq);
if (status != MOSQ_ERR_SUCCESS) {
- char errbuf[1024];
ERROR("mqtt_connect_broker: mosquitto_connect failed: %s",
- (status == MOSQ_ERR_ERRNO) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : mosquitto_strerror(status));
+ (status == MOSQ_ERR_ERRNO) ? STRERRNO : mosquitto_strerror(status));
return -1;
}
status =
mosquitto_username_pw_set(conf->mosq, conf->username, conf->password);
if (status != MOSQ_ERR_SUCCESS) {
- char errbuf[1024];
ERROR("mqtt plugin: mosquitto_username_pw_set failed: %s",
- (status == MOSQ_ERR_ERRNO)
- ? sstrerror(errno, errbuf, sizeof(errbuf))
- : mosquitto_strerror(status));
+ (status == MOSQ_ERR_ERRNO) ? STRERRNO : mosquitto_strerror(status));
mosquitto_destroy(conf->mosq);
conf->mosq = NULL;
mosquitto_connect(conf->mosq, conf->host, conf->port, MQTT_KEEPALIVE);
#endif
if (status != MOSQ_ERR_SUCCESS) {
- char errbuf[1024];
ERROR("mqtt plugin: mosquitto_connect failed: %s",
- (status == MOSQ_ERR_ERRNO) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : mosquitto_strerror(status));
+ (status == MOSQ_ERR_ERRNO) ? STRERRNO : mosquitto_strerror(status));
mosquitto_destroy(conf->mosq);
conf->mosq = NULL;
#endif
conf->qos, conf->retain);
if (status != MOSQ_ERR_SUCCESS) {
- char errbuf[1024];
c_complain(LOG_ERR, &conf->complaint_cantpublish,
"mqtt plugin: mosquitto_publish failed: %s",
- (status == MOSQ_ERR_ERRNO)
- ? sstrerror(errno, errbuf, sizeof(errbuf))
- : mosquitto_strerror(status));
+ (status == MOSQ_ERR_ERRNO) ? STRERRNO
+ : mosquitto_strerror(status));
/* Mark our connection "down" regardless of the error as a safety
* measure; we will try to reconnect the next time we have to publish a
* message */
* StoreRates true
* Retain false
* QoS 0
- * CACert "ca.pem" Enables TLS if set
- * CertificateFile "client-cert.pem" optional
- * CertificateKeyFile "client-key.pem" optional
- * TLSProtocol "tlsv1.2" optional
+ * CACert "ca.pem" Enables TLS if set
+ * CertificateFile "client-cert.pem" optional
+ * CertificateKeyFile "client-key.pem" optional
+ * TLSProtocol "tlsv1.2" optional
* </Publish>
*/
static int mqtt_config_publisher(oconfig_item_t *ci) {
* User "guest"
* Password "secret"
* Topic "collectd/#"
+ * CACert "ca.pem" Enables TLS if set
+ * CertificateFile "client-cert.pem" optional
+ * CertificateKeyFile "client-key.pem" optional
+ * TLSProtocol "tlsv1.2" optional
* </Subscribe>
*/
static int mqtt_config_subscriber(oconfig_item_t *ci) {
cf_util_get_string(child, &conf->topic);
else if (strcasecmp("CleanSession", child->key) == 0)
cf_util_get_boolean(child, &conf->clean_session);
+ else if (strcasecmp("CACert", child->key) == 0)
+ cf_util_get_string(child, &conf->cacertificatefile);
+ else if (strcasecmp("CertificateFile", child->key) == 0)
+ cf_util_get_string(child, &conf->certificatefile);
+ else if (strcasecmp("CertificateKeyFile", child->key) == 0)
+ cf_util_get_string(child, &conf->certificatekeyfile);
+ else if (strcasecmp("TLSProtocol", child->key) == 0)
+ cf_util_get_string(child, &conf->tlsprotocol);
+ else if (strcasecmp("CipherSuite", child->key) == 0)
+ cf_util_get_string(child, &conf->ciphersuite);
else
ERROR("mqtt plugin: Unknown config option: %s", child->key);
}
/* args = */ subscribers[i],
/* name = */ "mqtt");
if (status != 0) {
- char errbuf[1024];
- ERROR("mqtt plugin: pthread_create failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("mqtt plugin: pthread_create failed: %s", STRERRNO);
continue;
}
}
--- /dev/null
+/*
+ * Partial header file imported from the linux kernel
+ * (arch/x86/include/asm/msr-index.h)
+ * as it is not provided by the kernel sources anymore
+ *
+ * Only the minimal blocks of macro have been included
+ * ----
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * ----
+ */
+
+#ifndef _ASM_X86_MSR_INDEX_H
+#define _ASM_X86_MSR_INDEX_H
+
+/*
+ * CPU model specific register (MSR) numbers.
+ *
+ * Do not add new entries to this file unless the definitions are shared
+ * between multiple compilation units.
+ */
+
+/* Intel MSRs. Some also available on other CPUs */
+
+/* C-state Residency Counters */
+#define MSR_PKG_C3_RESIDENCY 0x000003f8
+#define MSR_PKG_C6_RESIDENCY 0x000003f9
+#define MSR_ATOM_PKG_C6_RESIDENCY 0x000003fa
+#define MSR_PKG_C7_RESIDENCY 0x000003fa
+#define MSR_CORE_C3_RESIDENCY 0x000003fc
+#define MSR_CORE_C6_RESIDENCY 0x000003fd
+#define MSR_CORE_C7_RESIDENCY 0x000003fe
+#define MSR_KNL_CORE_C6_RESIDENCY 0x000003ff
+#define MSR_PKG_C2_RESIDENCY 0x0000060d
+#define MSR_PKG_C8_RESIDENCY 0x00000630
+#define MSR_PKG_C9_RESIDENCY 0x00000631
+#define MSR_PKG_C10_RESIDENCY 0x00000632
+
+/* Run Time Average Power Limiting (RAPL) Interface */
+
+#define MSR_RAPL_POWER_UNIT 0x00000606
+
+#define MSR_PKG_POWER_LIMIT 0x00000610
+#define MSR_PKG_ENERGY_STATUS 0x00000611
+#define MSR_PKG_PERF_STATUS 0x00000613
+#define MSR_PKG_POWER_INFO 0x00000614
+
+#define MSR_DRAM_POWER_LIMIT 0x00000618
+#define MSR_DRAM_ENERGY_STATUS 0x00000619
+#define MSR_DRAM_PERF_STATUS 0x0000061b
+#define MSR_DRAM_POWER_INFO 0x0000061c
+
+#define MSR_PP0_POWER_LIMIT 0x00000638
+#define MSR_PP0_ENERGY_STATUS 0x00000639
+#define MSR_PP0_POLICY 0x0000063a
+#define MSR_PP0_PERF_STATUS 0x0000063b
+
+#define MSR_PP1_POWER_LIMIT 0x00000640
+#define MSR_PP1_ENERGY_STATUS 0x00000641
+#define MSR_PP1_POLICY 0x00000642
+
+
+
+/* Intel defined MSRs. */
+#define MSR_IA32_TSC 0x00000010
+#define MSR_SMI_COUNT 0x00000034
+
+#define MSR_IA32_MPERF 0x000000e7
+#define MSR_IA32_APERF 0x000000e8
+
+#define MSR_IA32_THERM_STATUS 0x0000019c
+
+#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2
+
+#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1
+
+
+#endif /* _ASM_X86_MSR_INDEX_H */
tcflush(fd, TCIFLUSH);
if (gettimeofday(&time_end, NULL) < 0) {
- char errbuf[1024];
- ERROR("multimeter plugin: gettimeofday failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("multimeter plugin: gettimeofday failed: %s", STRERRNO);
return -1;
}
time_end.tv_sec++;
struct timeval time_now;
status = swrite(fd, "D", 1);
- if (status < 0) {
+ if (status != 0) {
ERROR("multimeter plugin: swrite failed.");
return -1;
}
FD_SET(fd, &rfds);
if (gettimeofday(&time_now, NULL) < 0) {
- char errbuf[1024];
ERROR("multimeter plugin: "
"gettimeofday failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
if (timeval_cmp(time_end, time_now, &timeout) < 0)
continue;
} else /* status == -1 */
{
- char errbuf[1024];
ERROR("multimeter plugin: "
"select failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
break;
}
}
}
db->is_connected = 0;
+ /* Close the old connection before initializing a new one. */
+ if (db->con != NULL) {
+ mysql_close(db->con);
+ db->con = NULL;
+ }
+
+ db->con = mysql_init(NULL);
if (db->con == NULL) {
- db->con = mysql_init(NULL);
- if (db->con == NULL) {
- ERROR("mysql plugin: mysql_init failed: %s", mysql_error(db->con));
- return NULL;
- }
+ ERROR("mysql plugin: mysql_init failed: %s", mysql_error(db->con));
+ return NULL;
}
/* Configure TCP connect timeout (default: 0) */
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*stats.stats64)) < 0) {
ERROR("netlink plugin: link_filter_cb: IFLA_STATS64 mnl_attr_validate2 "
- "failed.");
+ "failed: %s",
+ STRERRNO);
return MNL_CB_ERROR;
}
stats.stats64 = mnl_attr_get_payload(attr);
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*stats.stats32)) < 0) {
ERROR("netlink plugin: link_filter_cb: IFLA_STATS mnl_attr_validate2 "
- "failed.");
+ "failed: %s",
+ STRERRNO);
return MNL_CB_ERROR;
}
stats.stats32 = mnl_attr_get_payload(attr);
if (mnl_attr_get_type(attr) == TCA_STATS_BASIC) {
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*q_stats->bs)) < 0) {
ERROR("netlink plugin: qos_attr_cb: TCA_STATS_BASIC mnl_attr_validate2 "
- "failed.");
+ "failed: %s",
+ STRERRNO);
return MNL_CB_ERROR;
}
q_stats->bs = mnl_attr_get_payload(attr);
if ((tm->tcm_ifindex >= 0) && ((size_t)tm->tcm_ifindex >= iflist_len)) {
ERROR("netlink plugin: qos_filter_cb: tm->tcm_ifindex = %i "
- ">= iflist_len = %zu",
+ ">= iflist_len = %" PRIsz,
tm->tcm_ifindex, iflist_len);
return MNL_CB_ERROR;
}
if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*ts)) < 0) {
ERROR("netlink plugin: qos_filter_cb: TCA_STATS mnl_attr_validate2 "
- "failed.");
+ "failed: %s",
+ STRERRNO);
return MNL_CB_ERROR;
}
ts = mnl_attr_get_payload(attr);
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret < 0) {
- ERROR("netlink plugin: ir_read: mnl_socket_recvfrom failed.");
- return -1;
+ ERROR("netlink plugin: ir_read: mnl_socket_recvfrom failed: %s", STRERRNO);
+ return (-1);
}
/* `link_filter_cb' will update `iflist' which is used here to iterate
continue;
}
- DEBUG("netlink plugin: ir_read: querying %s from %s (%zu).",
+ DEBUG("netlink plugin: ir_read: querying %s from %s (%" PRIsz ").",
type_name[type_index], iflist[ifindex], ifindex);
nlh = mnl_nlmsg_put_header(buf);
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret < 0) {
- ERROR("netlink plugin: ir_read:mnl_socket_recvfrom failed.");
+ ERROR("netlink plugin: ir_read: mnl_socket_recvfrom failed: %s",
+ STRERRNO);
continue;
}
-
} /* for (type_index) */
} /* for (if_index) */
if (buffer_len < 15) {
NOTICE("network plugin: packet is too short: "
- "buffer_len = %zu",
+ "buffer_len = %" PRIsz,
buffer_len);
return -1;
}
if (buffer_len < exp_size) {
WARNING("network plugin: parse_part_values: "
"Packet too short: "
- "Chunk of size %zu expected, "
- "but buffer has only %zu bytes left.",
+ "Chunk of size %" PRIsz " expected, "
+ "but buffer has only %" PRIsz " bytes left.",
exp_size, buffer_len);
return -1;
}
if (buffer_len < exp_size) {
WARNING("network plugin: parse_part_number: "
"Packet too short: "
- "Chunk of size %zu expected, "
- "but buffer has only %zu bytes left.",
+ "Chunk of size %" PRIsz " expected, "
+ "but buffer has only %" PRIsz " bytes left.",
exp_size, buffer_len);
return -1;
}
if (buffer_len < header_size) {
WARNING("network plugin: parse_part_string: "
"Packet too short: "
- "Chunk of at least size %zu expected, "
- "but buffer has only %zu bytes left.",
+ "Chunk of at least size %" PRIsz " expected, "
+ "but buffer has only %" PRIsz " bytes left.",
header_size, buffer_len);
return -1;
}
WARNING("network plugin: parse_part_string: "
"Packet too big: "
"Chunk of size %" PRIu16 " received, "
- "but buffer has only %zu bytes left.",
+ "but buffer has only %" PRIsz " bytes left.",
pkg_length, buffer_len);
return -1;
}
if (output_len < payload_size) {
WARNING("network plugin: parse_part_string: "
"Buffer too small: "
- "Output buffer holds %zu bytes, "
+ "Output buffer holds %" PRIsz " bytes, "
"which is too small to hold the received "
- "%zu byte string.",
+ "%" PRIsz " byte string.",
output_len, payload_size);
return -1;
}
part_size - buffer_offset,
/* in = */ NULL, /* in len = */ 0);
if (err != 0) {
- sfree(pea.username);
ERROR("network plugin: gcry_cipher_decrypt returned: %s. Username: %s",
gcry_strerror(err), pea.username);
+ sfree(pea.username);
return -1;
}
parse_packet(se, buffer + buffer_offset, payload_len, flags | PP_ENCRYPTED,
pea.username);
- /* XXX: Free pea.username?!? */
-
/* Update return values */
*ret_buffer = buffer + part_size;
*ret_buffer_len = buffer_len - part_size;
if (setsockopt(se->data.client.fd, IPPROTO_IP, optname, &network_config_ttl,
sizeof(network_config_ttl)) != 0) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (ipv4-ttl): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (ipv4-ttl): %s", STRERRNO);
return -1;
}
} else if (ai->ai_family == AF_INET6) {
if (setsockopt(se->data.client.fd, IPPROTO_IPV6, optname,
&network_config_ttl, sizeof(network_config_ttl)) != 0) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt(ipv6-ttl): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt(ipv6-ttl): %s", STRERRNO);
return -1;
}
}
if (setsockopt(se->data.client.fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq,
sizeof(mreq)) != 0) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (ipv4-multicast-if): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (ipv4-multicast-if): %s", STRERRNO);
return -1;
}
if (IN6_IS_ADDR_MULTICAST(&addr->sin6_addr)) {
if (setsockopt(se->data.client.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
&se->interface, sizeof(se->interface)) != 0) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (ipv6-multicast-if): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (ipv6-multicast-if): %s", STRERRNO);
return -1;
}
if (setsockopt(se->data.client.fd, SOL_SOCKET, SO_BINDTODEVICE,
interface_name, sizeof(interface_name)) == -1) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (bind-if): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (bind-if): %s", STRERRNO);
return -1;
}
/* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
/* allow multiple sockets to use the same PORT number */
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (reuseaddr): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (reuseaddr): %s", STRERRNO);
return -1;
}
DEBUG("fd = %i; calling `bind'", fd);
if (bind(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
- char errbuf[1024];
- ERROR("bind: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("bind: %s", STRERRNO);
return -1;
}
if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) ==
-1) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (multicast-loop): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (multicast-loop): %s", STRERRNO);
return -1;
}
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) ==
-1) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (add-membership): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (add-membership): %s", STRERRNO);
return -1;
}
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop,
sizeof(loop)) == -1) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (ipv6-multicast-loop): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (ipv6-multicast-loop): %s", STRERRNO);
return -1;
}
if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) == -1) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (ipv6-add-membership): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (ipv6-add-membership): %s", STRERRNO);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name,
sizeof(interface_name)) == -1) {
- char errbuf[1024];
- ERROR("network plugin: setsockopt (bind-if): %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: setsockopt (bind-if): %s", STRERRNO);
return -1;
}
}
client->fd =
socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (client->fd < 0) {
- char errbuf[1024];
- ERROR("network plugin: socket(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: socket(2) failed: %s", STRERRNO);
continue;
}
*tmp = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (*tmp < 0) {
- char errbuf[1024];
- ERROR("network plugin: socket(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: socket(2) failed: %s", STRERRNO);
continue;
}
while (listen_loop == 0) {
status = poll(listen_sockets_pollfd, listen_sockets_num, -1);
if (status <= 0) {
- char errbuf[1024];
if (errno == EINTR)
continue;
- ERROR("network plugin: poll(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: poll(2) failed: %s", STRERRNO);
break;
}
buffer_len = recv(listen_sockets_pollfd[i].fd, buffer, sizeof(buffer),
0 /* no flags */);
if (buffer_len < 0) {
- char errbuf[1024];
status = (errno != 0) ? errno : -1;
- ERROR("network plugin: recv(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network plugin: recv(2) failed: %s", STRERRNO);
break;
}
/* flags = */ 0, (struct sockaddr *)se->data.client.addr,
se->data.client.addrlen);
if (status < 0) {
- char errbuf[1024];
-
if ((errno == EINTR) || (errno == EAGAIN))
continue;
ERROR("network plugin: sendto failed: %s. Closing sending socket.",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
sockent_client_disconnect(se);
return;
}
assert(buffer_size <= sizeof(buffer));
DEBUG("network plugin: network_send_buffer_encrypted: "
- "buffer_size = %zu;",
+ "buffer_size = %" PRIsz ";",
buffer_size);
pea.head.length = htons(
static void network_send_buffer(char *buffer, size_t buffer_len) /* {{{ */
{
- DEBUG("network plugin: network_send_buffer: buffer_len = %zu", buffer_len);
+ DEBUG("network plugin: network_send_buffer: buffer_len = %" PRIsz,
+ buffer_len);
for (sockent_t *se = sending_sockets; se != NULL; se = se->next) {
#if HAVE_GCRYPT_H
dispatch_thread, NULL /* no argument */,
"network disp");
if (status != 0) {
- char errbuf[1024];
- ERROR("network: pthread_create failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network: pthread_create failed: %s", STRERRNO);
} else {
dispatch_thread_running = 1;
}
receive_thread, NULL /* no argument */,
"network recv");
if (status != 0) {
- char errbuf[1024];
- ERROR("network: pthread_create failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("network: pthread_create failed: %s", STRERRNO);
} else {
receive_thread_running = 1;
}
#include <kstat.h>
#endif
+static const char *config_keys[] = {"ReportV2", "ReportV3", "ReportV4"};
+static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
+static _Bool report_v2 = 1;
+static _Bool report_v3 = 1;
+static _Bool report_v4 = 1;
+
/*
see /proc/net/rpc/nfs
see http://www.missioncriticallinux.com/orph/NFS-Statistics
static size_t nfs4_server40_procedures_names_num =
STATIC_ARRAY_SIZE(nfs4_server40_procedures_names);
-static const char *nfs4_server41_procedures_names[] = {
- "backchannel_ctl",
- "bind_conn_to_session",
- "exchange_id",
- "create_session",
- "destroy_session",
- "free_stateid",
- "get_dir_delegation",
- "getdeviceinfo",
- "getdevicelist",
- "layoutcommit",
- "layoutget",
- "layoutreturn",
- "secinfo_no_name",
- "sequence",
- "set_ssv",
- "test_stateid",
- "want_delegation",
- "destroy_clientid",
- "reclaim_complete",
+static const char *nfs4_server4x_procedures_names[] = {
+ /* NFS 4.1 */
+ "backchannel_ctl", "bind_conn_to_session", "exchange_id", "create_session",
+ "destroy_session", "free_stateid", "get_dir_delegation", "getdeviceinfo",
+ "getdevicelist", "layoutcommit", "layoutget", "layoutreturn",
+ "secinfo_no_name", "sequence", "set_ssv", "test_stateid", "want_delegation",
+ "destroy_clientid", "reclaim_complete",
+ /* NFS 4.2 */
+ "allocate", /* 3.18 */
+ "copy", /* 3.18 */
+ "copy_notify", /* 3.18 */
+ "deallocate", /* 3.18 */
+ "ioadvise", /* 3.18 */
+ "layouterror", /* 3.18 */
+ "layoutstats", /* 3.18 */
+ "offloadcancel", /* 3.18 */
+ "offloadstatus", /* 3.18 */
+ "readplus", /* 3.18 */
+ "seek", /* 3.18 */
+ "write_same", /* 3.18 */
+ "clone" /* 4.5 */
};
-static size_t nfs4_server41_procedures_names_num =
- STATIC_ARRAY_SIZE(nfs4_server41_procedures_names);
-
#define NFS4_SERVER40_NUM_PROC \
(STATIC_ARRAY_SIZE(nfs4_server40_procedures_names))
-#define NFS4_SERVER41_NUM_PROC \
+#define NFS4_SERVER4X_NUM_PROC \
(STATIC_ARRAY_SIZE(nfs4_server40_procedures_names) + \
- STATIC_ARRAY_SIZE(nfs4_server41_procedures_names))
+ STATIC_ARRAY_SIZE(nfs4_server4x_procedures_names))
-#define NFS4_SERVER_MAX_PROC (NFS4_SERVER41_NUM_PROC)
+#define NFS4_SERVER_MAX_PROC (NFS4_SERVER4X_NUM_PROC)
static const char *nfs4_client40_procedures_names[] = {
"null",
"fsid_present" /* |54| 3.13 */
};
-static const char *nfs4_client41_procedures_names[] = {
+static const char *nfs4_client4x_procedures_names[] = {
+ /* NFS 4.1 */
"exchange_id", /* |40| 2.6.30 */
"create_session", /* |40| 2.6.30 */
"destroy_session", /* |40| 2.6.30 */
"free_stateid", /* |51| 3.1 */
"getdevicelist", /* |51| 3.1 */
"bind_conn_to_session", /* |53| 3.5 */
- "destroy_clientid" /* |53| 3.5 */
+ "destroy_clientid", /* |53| 3.5 */
+ /* NFS 4.2 */
+ "seek", /* |55| 3.18 */
+ "allocate", /* |57| 3.19 */
+ "deallocate", /* |57| 3.19 */
+ "layoutstats", /* |58| 4.2 */
+ "clone", /* |59| 4.4 */
+ "copy" /* |60| 4.7 */
};
#define NFS4_CLIENT40_NUM_PROC \
(STATIC_ARRAY_SIZE(nfs4_client40_procedures_names))
-#define NFS4_CLIENT41_NUM_PROC \
+#define NFS4_CLIENT4X_NUM_PROC \
(STATIC_ARRAY_SIZE(nfs4_client40_procedures_names) + \
- STATIC_ARRAY_SIZE(nfs4_client41_procedures_names))
+ STATIC_ARRAY_SIZE(nfs4_client4x_procedures_names))
-#define NFS4_CLIENT_MAX_PROC (NFS4_CLIENT41_NUM_PROC)
+#define NFS4_CLIENT_MAX_PROC (NFS4_CLIENT4X_NUM_PROC)
#endif
static kstat_t *nfs4_ksp_server;
#endif
+static int nfs_config(const char *key, const char *value) {
+ if (strcasecmp(key, "ReportV2") == 0)
+ report_v2 = IS_TRUE(value);
+ else if (strcasecmp(key, "ReportV3") == 0)
+ report_v3 = IS_TRUE(value);
+ else if (strcasecmp(key, "ReportV4") == 0)
+ report_v4 = IS_TRUE(value);
+ else
+ return -1;
+
+ return 0;
+}
+
#if KERNEL_LINUX
static int nfs_init(void) { return 0; }
/* #endif KERNEL_LINUX */
size_t proc_names_num) {
if (fields_num != proc_names_num) {
WARNING("nfs plugin: Wrong number of fields for "
- "NFSv%i %s statistics. Expected %zu, got %zu.",
+ "NFSv%i %s statistics. Expected %" PRIsz ", got %" PRIsz ".",
nfs_version, instance, proc_names_num, fields_num);
return EINVAL;
}
static int nfs_submit_nfs4_server(const char *instance, char **fields,
size_t fields_num) {
static int suppress_warning = 0;
+ size_t proc4x_names_num;
- if (fields_num != NFS4_SERVER40_NUM_PROC &&
- fields_num != NFS4_SERVER41_NUM_PROC) {
+ switch (fields_num) {
+ case NFS4_SERVER40_NUM_PROC:
+ case NFS4_SERVER40_NUM_PROC + 19: /* NFS 4.1 */
+ case NFS4_SERVER40_NUM_PROC + 31: /* NFS 4.2 */
+ case NFS4_SERVER40_NUM_PROC + 32: /* NFS 4.2 */
+ break;
+ default:
if (!suppress_warning) {
WARNING("nfs plugin: Unexpected number of fields for "
- "NFSv4 %s statistics: %zu. ",
+ "NFSv4 %s statistics: %" PRIsz ". ",
instance, fields_num);
}
nfs_submit_fields(4, instance, fields, nfs4_server40_procedures_names_num,
nfs4_server40_procedures_names);
- if (fields_num >= NFS4_SERVER41_NUM_PROC) {
+ if (fields_num > nfs4_server40_procedures_names_num) {
+ proc4x_names_num = fields_num - nfs4_server40_procedures_names_num;
fields += nfs4_server40_procedures_names_num;
- nfs_submit_fields(4, instance, fields, nfs4_server41_procedures_names_num,
- nfs4_server41_procedures_names);
+ nfs_submit_fields(4, instance, fields, proc4x_names_num,
+ nfs4_server4x_procedures_names);
}
return 0;
static int nfs_submit_nfs4_client(const char *instance, char **fields,
size_t fields_num) {
- size_t proc40_names_num, proc41_names_num;
+ size_t proc40_names_num, proc4x_names_num;
static int suppress_warning = 0;
proc40_names_num = 37;
break;
case 54:
+ case 55:
+ case 57:
+ case 58:
+ case 59:
+ case 60:
proc40_names_num = 38;
break;
default:
if (!suppress_warning) {
- WARNING("nfs plugin: Unexpected number of "
- "fields for NFSv4 %s "
- "statistics: %zu. ",
+ WARNING("nfs plugin: Unexpected number of fields for NFSv4 %s "
+ "statistics: %" PRIsz ". ",
instance, fields_num);
}
nfs4_client40_procedures_names);
if (fields_num > proc40_names_num) {
- proc41_names_num = fields_num - proc40_names_num;
+ proc4x_names_num = fields_num - proc40_names_num;
fields += proc40_names_num;
- nfs_submit_fields(4, instance, fields, proc41_names_num,
- nfs4_client41_procedures_names);
+ nfs_submit_fields(4, instance, fields, proc4x_names_num,
+ nfs4_client4x_procedures_names);
}
return 0;
if (fields_num < 3)
continue;
- if (strcmp(fields[0], "proc2") == 0) {
+ if (strcmp(fields[0], "proc2") == 0 && report_v2) {
nfs_submit_fields_safe(/* version = */ 2, inst, fields + 2,
(size_t)(fields_num - 2), nfs2_procedures_names,
nfs2_procedures_names_num);
- } else if (strncmp(fields[0], "proc3", 5) == 0) {
+ } else if (strncmp(fields[0], "proc3", 5) == 0 && report_v3) {
nfs_submit_fields_safe(/* version = */ 3, inst, fields + 2,
(size_t)(fields_num - 2), nfs3_procedures_names,
nfs3_procedures_names_num);
- } else if (strcmp(fields[0], "proc4ops") == 0) {
+ } else if (strcmp(fields[0], "proc4ops") == 0 && report_v4) {
if (inst[0] == 's')
nfs_submit_nfs4_server(inst, fields + 2, (size_t)(fields_num - 2));
- } else if (strcmp(fields[0], "proc4") == 0) {
+ } else if (strcmp(fields[0], "proc4") == 0 && report_v4) {
if (inst[0] == 'c')
nfs_submit_nfs4_client(inst, fields + 2, (size_t)(fields_num - 2));
}
#elif HAVE_LIBKSTAT
static int nfs_read(void) {
- nfs_read_kstat(nfs2_ksp_client, /* version = */ 2, "client",
- nfs2_procedures_names, nfs2_procedures_names_num);
- nfs_read_kstat(nfs2_ksp_server, /* version = */ 2, "server",
- nfs2_procedures_names, nfs2_procedures_names_num);
- nfs_read_kstat(nfs3_ksp_client, /* version = */ 3, "client",
- nfs3_procedures_names, nfs3_procedures_names_num);
- nfs_read_kstat(nfs3_ksp_server, /* version = */ 3, "server",
- nfs3_procedures_names, nfs3_procedures_names_num);
- nfs_read_kstat(nfs4_ksp_client, /* version = */ 4, "client",
- nfs4_procedures_names, nfs4_procedures_names_num);
- nfs_read_kstat(nfs4_ksp_server, /* version = */ 4, "server",
- nfs4_procedures_names, nfs4_procedures_names_num);
+ if (report_v2) {
+ nfs_read_kstat(nfs2_ksp_client, /* version = */ 2, "client",
+ nfs2_procedures_names, nfs2_procedures_names_num);
+ nfs_read_kstat(nfs2_ksp_server, /* version = */ 2, "server",
+ nfs2_procedures_names, nfs2_procedures_names_num);
+ }
+ if (report_v3) {
+ nfs_read_kstat(nfs3_ksp_client, /* version = */ 3, "client",
+ nfs3_procedures_names, nfs3_procedures_names_num);
+ nfs_read_kstat(nfs3_ksp_server, /* version = */ 3, "server",
+ nfs3_procedures_names, nfs3_procedures_names_num);
+ }
+ if (report_v4) {
+ nfs_read_kstat(nfs4_ksp_client, /* version = */ 4, "client",
+ nfs4_procedures_names, nfs4_procedures_names_num);
+ nfs_read_kstat(nfs4_ksp_server, /* version = */ 4, "server",
+ nfs4_procedures_names, nfs4_procedures_names_num);
+ }
return 0;
}
#endif /* HAVE_LIBKSTAT */
void module_register(void) {
+ plugin_register_config("nfs", nfs_config, config_keys, config_keys_num);
plugin_register_init("nfs", nfs_init);
plugin_register_read("nfs", nfs_read);
} /* void module_register */
fd = open(file, O_WRONLY | O_APPEND);
if (fd < 0) {
- char errbuf[1024];
status = errno;
- ERROR("notify_nagios plugin: Opening \"%s\" failed: %s", file,
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("notify_nagios plugin: Opening \"%s\" failed: %s", file, STRERRNO);
return status;
}
status = fcntl(fd, F_GETLK, &lock);
if (status != 0) {
- char errbuf[1024];
status = errno;
ERROR("notify_nagios plugin: Failed to acquire write lock on \"%s\": %s",
- file, sstrerror(status, errbuf, sizeof(errbuf)));
+ file, STRERRNO);
close(fd);
return status;
}
status = (int)lseek(fd, 0, SEEK_END);
if (status == -1) {
- char errbuf[1024];
status = errno;
ERROR("notify_nagios plugin: Seeking to end of \"%s\" failed: %s", file,
- sstrerror(status, errbuf, sizeof(errbuf)));
+ STRERRNO);
close(fd);
return status;
}
status = (int)swrite(fd, buffer, strlen(buffer));
if (status != 0) {
- char errbuf[1024];
status = errno;
- ERROR("notify_nagios plugin: Writing to \"%s\" failed: %s", file,
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("notify_nagios plugin: Writing to \"%s\" failed: %s", file, STRERRNO);
close(fd);
return status;
}
.ai_socktype = SOCK_DGRAM};
if ((status = getaddrinfo(host, port, &ai_hints, &ai_list)) != 0) {
- char errbuf[1024];
ERROR("ntpd plugin: getaddrinfo (%s, %s): %s", host, port,
- (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(status));
+ (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
return -1;
}
*res_data = NULL;
if (gettimeofday(&time_end, NULL) < 0) {
- char errbuf[1024];
- ERROR("ntpd plugin: gettimeofday failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ntpd plugin: gettimeofday failed: %s", STRERRNO);
return -1;
}
time_end.tv_sec++; /* wait for a most one second */
struct timeval time_left;
if (gettimeofday(&time_now, NULL) < 0) {
- char errbuf[1024];
- ERROR("ntpd plugin: gettimeofday failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ntpd plugin: gettimeofday failed: %s", STRERRNO);
return -1;
}
continue;
if (status < 0) {
- char errbuf[1024];
- ERROR("ntpd plugin: poll failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ntpd plugin: poll failed: %s", STRERRNO);
return -1;
}
continue;
if (status < 0) {
- char errbuf[1024];
- INFO("recv(2) failed: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ INFO("recv(2) failed: %s", STRERRNO);
DEBUG("Closing socket #%i", sd);
close(sd);
sock_descr = sd = -1;
* Enough with the checks. Copy the data now.
* We start by allocating some more memory.
*/
- DEBUG("realloc (%p, %zu)", (void *)*res_data,
+ DEBUG("realloc (%p, %" PRIsz ")", (void *)*res_data,
(items_num + pkt_item_num) * res_item_size);
items = realloc(*res_data, (items_num + pkt_item_num) * res_item_size);
if (items == NULL) {
(void *)req_data);
status = swrite(sd, (const char *)&req, REQ_LEN_NOMAC);
- if (status < 0) {
+ if (status != 0) {
DEBUG("`swrite' failed. Closing socket #%i", sd);
close(sd);
sock_descr = sd = -1;
buffer_size, NULL, 0, /* No port name */
flags);
if (status != 0) {
- char errbuf[1024];
ERROR("ntpd plugin: getnameinfo failed: %s",
- (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(status));
+ (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
return -1;
}
}
/* kerninfo -> estimated error */
- offset_loop = scale_loop * ((gauge_t)ntohl(ik->offset));
+ offset_loop = (gauge_t)((int32_t)ntohl(ik->offset) * scale_loop);
freq_loop = ntpd_read_fp(ik->freq);
- offset_error = scale_error * ((gauge_t)ntohl(ik->esterror));
+ offset_error = (gauge_t)((int32_t)ntohl(ik->esterror) * scale_error);
DEBUG("info_kernel:\n"
" pll offset = %.8g\n"
fh = fopen(path, "r");
if (fh == NULL) {
- char errbuf[1024];
ERROR("numa plugin: Reading node %i failed: open(%s): %s", node, path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
break;
} else /* ((status != 0) && (errno != ENOENT)) */
{
- char errbuf[1024];
- ERROR("numa plugin: stat(%s) failed: %s", path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("numa plugin: stat(%s) failed: %s", path, STRERRNO);
return -1;
}
}
cb_name = ssnprintf_alloc("nut/%s", name);
status = plugin_register_complex_read(
- /* group = */ "nut",
- /* name = */ cb_name,
- /* callback = */ nut_read,
- /* interval = */ 0,
- /* user_data = */ &(user_data_t){
- .data = ups, .free_func = free_nut_ups_t,
- });
+ /* group = */ "nut",
+ /* name = */ cb_name,
+ /* callback = */ nut_read,
+ /* interval = */ 0,
+ /* user_data = */ &(user_data_t){
+ .data = ups, .free_func = free_nut_ups_t,
+ });
sfree(cb_name);
vl.values = &(value_t){.gauge = value};
vl.values_len = 1;
- sstrncpy(vl.host,
- (strcasecmp(ups->hostname, "localhost") == 0) ? hostname_g
- : ups->hostname,
- sizeof(vl.host));
+ if (strcasecmp(ups->hostname, "localhost") != 0)
+ sstrncpy(vl.host, ups->hostname, sizeof(vl.host));
sstrncpy(vl.plugin, "nut", sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, ups->upsname, sizeof(vl.plugin_instance));
sstrncpy(vl.type, type, sizeof(vl.type));
tv.tv_sec = connect_timeout / 1000;
tv.tv_usec = connect_timeout % 1000;
- status = upscli_tryconnect(ups->conn, ups->hostname, ups->port, ssl_flags,
- &tv);
+ status =
+ upscli_tryconnect(ups->conn, ups->hostname, ups->port, ssl_flags, &tv);
#else /* #if HAVE_UPSCLI_TRYCONNECT */
status = upscli_connect(ups->conn, ups->hostname, ups->port, ssl_flags);
#endif
ai_ptr = ai_ptr->ai_next) {
int fd;
int status;
- char errbuf[1024];
fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (fd < 0) {
- ERROR("olsrd plugin: socket failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("olsrd plugin: socket failed: %s", STRERRNO);
continue;
}
status = connect(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0) {
- ERROR("olsrd plugin: connect failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("olsrd plugin: connect failed: %s", STRERRNO);
close(fd);
continue;
}
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. error = %s;", path,
- family_info->features[i].filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ family_info->features[i].filename, STRERRNO);
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. error = %s;", path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("onewire plugin: OW_get (%s) failed. error = %s;", path, STRERRNO);
return -1;
}
DEBUG("onewire plugin: OW_get (%s) returned: %s", path, buffer);
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 = %s;", traverse->path,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
DEBUG("onewire plugin: Read onewire device %s as %s", traverse->path,
static int cow_init(void) {
int status;
- char errbuf[1024];
if (device_g == NULL) {
ERROR("onewire plugin: cow_init: No device configured.");
DEBUG("onewire plugin: about to init device <%s>.", device_g);
status = (int)OW_init(device_g);
if (status != 0) {
- ERROR("onewire plugin: OW_init(%s) failed: %s.", device_g,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("onewire plugin: OW_init(%s) failed: %s.", device_g, STRERRNO);
return 1;
}
char *password;
char *cacert;
char *host;
- int state;
_Bool starttls;
int timeout;
char *url;
};
typedef struct cldap_s cldap_t; /* }}} */
-static cldap_t **databases = NULL;
-static size_t databases_num = 0;
-
-static void cldap_free(cldap_t *st) /* {{{ */
+static void cldap_free(void *arg) /* {{{ */
{
+ cldap_t *st = arg;
+
if (st == NULL)
return;
sfree(st->name);
sfree(st->url);
if (st->ld)
- ldap_memfree(st->ld);
+ ldap_unbind_ext_s(st->ld, NULL, NULL);
+
sfree(st);
} /* }}} void cldap_free */
/* initialize ldap for each host */
static int cldap_init_host(cldap_t *st) /* {{{ */
{
- LDAP *ld;
int rc;
- if (st->state && st->ld) {
+ if (st->ld) {
DEBUG("openldap plugin: Already connected to %s", st->url);
return 0;
}
- rc = ldap_initialize(&ld, st->url);
+ rc = ldap_initialize(&st->ld, st->url);
if (rc != LDAP_SUCCESS) {
ERROR("openldap plugin: ldap_initialize failed: %s", ldap_err2string(rc));
- st->state = 0;
- if (ld != NULL)
- ldap_unbind_ext_s(ld, NULL, NULL);
+ if (st->ld != NULL)
+ ldap_unbind_ext_s(st->ld, NULL, NULL);
+ st->ld = NULL;
return (-1);
}
- st->ld = ld;
-
ldap_set_option(st->ld, LDAP_OPT_PROTOCOL_VERSION, &st->version);
ldap_set_option(st->ld, LDAP_OPT_TIMEOUT,
}
if (st->starttls != 0) {
- rc = ldap_start_tls_s(ld, NULL, NULL);
+ rc = ldap_start_tls_s(st->ld, NULL, NULL);
if (rc != LDAP_SUCCESS) {
ERROR("openldap plugin: Failed to start tls on %s: %s", st->url,
ldap_err2string(rc));
- st->state = 0;
- if (st->ld != NULL)
- ldap_unbind_ext_s(st->ld, NULL, NULL);
+ ldap_unbind_ext_s(st->ld, NULL, NULL);
+ st->ld = NULL;
return (-1);
}
}
if (rc != LDAP_SUCCESS) {
ERROR("openldap plugin: Failed to bind to %s: %s", st->url,
ldap_err2string(rc));
- st->state = 0;
- if (st->ld != NULL)
- ldap_unbind_ext_s(st->ld, NULL, NULL);
+ ldap_unbind_ext_s(st->ld, NULL, NULL);
+ st->ld = NULL;
return (-1);
} else {
DEBUG("openldap plugin: Successfully connected to %s", st->url);
- st->state = 1;
return 0;
}
} /* }}} static cldap_init_host */
if (rc != LDAP_SUCCESS) {
ERROR("openldap plugin: Failed to execute search: %s", ldap_err2string(rc));
ldap_msgfree(result);
- st->state = 0;
- if (st->ld != NULL)
- ldap_unbind_ext_s(st->ld, NULL, NULL);
+ ldap_unbind_ext_s(st->ld, NULL, NULL);
+ st->ld = NULL;
return (-1);
}
ldap_free_urldesc(ludpp);
}
- if (status == 0) {
- cldap_t **temp;
-
- temp = (cldap_t **)realloc(databases,
- sizeof(*databases) * (databases_num + 1));
-
- if (temp == NULL) {
- ERROR("openldap plugin: realloc failed");
- status = -1;
- } else {
- char callback_name[3 * DATA_MAX_NAME_LEN] = {0};
-
- databases = temp;
- databases[databases_num] = st;
- databases_num++;
-
- snprintf(callback_name, sizeof(callback_name), "openldap/%s/%s",
- (st->host != NULL) ? st->host : hostname_g,
- (st->name != NULL) ? st->name : "default");
-
- status = plugin_register_complex_read(/* group = */ NULL,
- /* name = */ callback_name,
- /* callback = */ cldap_read_host,
- /* interval = */ 0,
- &(user_data_t){
- .data = st,
- });
- }
- }
-
if (status != 0) {
cldap_free(st);
return -1;
}
- return 0;
+ char callback_name[3 * DATA_MAX_NAME_LEN] = {0};
+
+ snprintf(callback_name, sizeof(callback_name), "openldap/%s/%s",
+ (st->host != NULL) ? st->host : hostname_g,
+ (st->name != NULL) ? st->name : "default");
+
+ return plugin_register_complex_read(/* group = */ NULL,
+ /* name = */ callback_name,
+ /* callback = */ cldap_read_host,
+ /* interval = */ 0,
+ &(user_data_t){
+ .data = st, .free_func = cldap_free,
+ });
} /* }}} int cldap_config_add */
static int cldap_config(oconfig_item_t *ci) /* {{{ */
return 0;
} /* }}} int cldap_init */
-static int cldap_shutdown(void) /* {{{ */
-{
- for (size_t i = 0; i < databases_num; i++)
- if (databases[i]->ld != NULL)
- ldap_unbind_ext_s(databases[i]->ld, NULL, NULL);
- sfree(databases);
- databases_num = 0;
-
- return 0;
-} /* }}} int cldap_shutdown */
-
void module_register(void) /* {{{ */
{
plugin_register_complex_config("openldap", cldap_config);
plugin_register_init("openldap", cldap_init);
- plugin_register_shutdown("openldap", cldap_shutdown);
} /* }}} void module_register */
#if defined(__APPLE__)
* Florian octo Forster <octo at collectd.org>
* Marco Chiappero <marco at absence.it>
* Fabian Schuh <mail at xeroc.org>
+ * Pavel Rochnyak <pavel2000 ngs.ru>
**/
#include "collectd.h"
#include "common.h"
#include "plugin.h"
-#define V1STRING \
+/**
+ * There is two main kinds of OpenVPN status file:
+ * - for 'single' mode (point-to-point or client mode)
+ * - for 'multi' mode (server with multiple clients)
+ *
+ * For 'multi' there is 3 versions of status file format:
+ * - version 1 - First version of status file: without line type tokens,
+ * comma delimited for easy machine parsing. Currently used by default.
+ * Added in openvpn-2.0-beta3.
+ * - version 2 - with line type tokens, with 'HEADER' line type, uses comma
+ * as a delimiter.
+ * Added in openvpn-2.0-beta15.
+ * - version 3 - The only difference from version 2 is delimiter: in version 3
+ * tabs are used instead of commas. Set of fields is the same.
+ * Added in openvpn-2.1_rc14.
+ *
+ * For versions 2/3 there may be different sets of fields in different
+ * OpenVPN versions.
+ *
+ * Versions 2.0, 2.1, 2.2:
+ * Common Name,Real Address,Virtual Address,
+ * Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t)
+ *
+ * Version 2.3:
+ * Common Name,Real Address,Virtual Address,
+ * Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t),Username
+ *
+ * Version 2.4:
+ * Common Name,Real Address,Virtual Address,Virtual IPv6 Address,
+ * Bytes Received,Bytes Sent,Connected Since,Connected Since (time_t),Username,
+ * Client ID,Peer ID
+ *
+ * Current Collectd code tries to handle changes in this field set,
+ * if they are backward-compatible.
+ **/
+
+#define TITLE_SINGLE "OpenVPN STATISTICS\n"
+#define TITLE_V1 "OpenVPN CLIENT LIST\n"
+#define TITLE_V2 "TITLE"
+
+#define V1HEADER \
"Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since\n"
-#define V2STRING \
- "HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Bytes " \
- "Received,Bytes Sent,Connected Since,Connected Since (time_t)\n"
-#define V3STRING \
- "HEADER CLIENT_LIST Common Name Real Address Virtual Address Bytes " \
- "Received Bytes Sent Connected Since Connected Since (time_t)\n"
-#define V4STRING \
- "HEADER,CLIENT_LIST,Common Name,Real Address,Virtual Address,Bytes " \
- "Received,Bytes Sent,Connected Since,Connected Since (time_t),Username\n"
-#define VSSTRING "OpenVPN STATISTICS\n"
struct vpn_status_s {
char *file;
- enum {
- MULTI1 = 1, /* status-version 1 */
- MULTI2, /* status-version 2 */
- MULTI3, /* status-version 3 */
- MULTI4, /* status-version 4 */
- SINGLE = 10 /* currently no versions for single mode, maybe in the future */
- } version;
char *name;
};
typedef struct vpn_status_s vpn_status_t;
-static vpn_status_t **vpn_list = NULL;
-static int vpn_num = 0;
-
static _Bool new_naming_schema = 0;
static _Bool collect_compression = 1;
static _Bool collect_user_count = 0;
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
/* Helper function
- * copy-n-pasted from common.c - changed delim to "," */
+ * copy-n-pasted from common.c - changed delim to ",\t" */
static int openvpn_strsplit(char *string, char **fields, size_t size) {
- size_t i;
- char *ptr;
- char *saveptr;
-
- i = 0;
- ptr = string;
- saveptr = NULL;
- while ((fields[i] = strtok_r(ptr, ",", &saveptr)) != NULL) {
+ size_t i = 0;
+ char *ptr = string;
+ char *saveptr = NULL;
+
+ while ((fields[i] = strtok_r(ptr, ",\t", &saveptr)) != NULL) {
ptr = NULL;
i++;
return i;
} /* int openvpn_strsplit */
+static void openvpn_free(void *arg) {
+ vpn_status_t *st = arg;
+
+ sfree(st->file);
+ sfree(st);
+} /* void openvpn_free */
+
/* dispatches number of users */
static void numusers_submit(const char *pinst, const char *tinst,
gauge_t value) {
char buffer[1024];
char *fields[4];
const int max_fields = STATIC_ARRAY_SIZE(fields);
- int fields_num, read = 0;
-
- derive_t link_rx, link_tx;
- derive_t tun_rx, tun_tx;
- derive_t pre_compress, post_compress;
- derive_t pre_decompress, post_decompress;
- derive_t overhead_rx, overhead_tx;
-
- link_rx = 0;
- link_tx = 0;
- tun_rx = 0;
- tun_tx = 0;
- pre_compress = 0;
- post_compress = 0;
- pre_decompress = 0;
- post_decompress = 0;
+
+ derive_t link_rx = 0, link_tx = 0;
+ derive_t tun_rx = 0, tun_tx = 0;
+ derive_t pre_compress = 0, post_compress = 0;
+ derive_t pre_decompress = 0, post_decompress = 0;
while (fgets(buffer, sizeof(buffer), fh) != NULL) {
- fields_num = openvpn_strsplit(buffer, fields, max_fields);
+ int fields_num = openvpn_strsplit(buffer, fields, max_fields);
/* status file is generated by openvpn/sig.c:print_status()
* http://svn.openvpn.net/projects/openvpn/trunk/openvpn/sig.c
iostats_submit(name, "traffic", link_rx, link_tx);
/* we need to force this order to avoid negative values with these unsigned */
- overhead_rx = (((link_rx - pre_decompress) + post_decompress) - tun_rx);
- overhead_tx = (((link_tx - post_compress) + pre_compress) - tun_tx);
+ derive_t overhead_rx =
+ (((link_rx - pre_decompress) + post_decompress) - tun_rx);
+ derive_t overhead_tx = (((link_tx - post_compress) + pre_compress) - tun_tx);
iostats_submit(name, "overhead", overhead_rx, overhead_tx);
compression_submit(name, "data_out", pre_compress, post_compress);
}
- read = 1;
-
- return read;
+ return 0;
} /* int single_read */
/* for reading status version 1 */
static int multi1_read(const char *name, FILE *fh) {
char buffer[1024];
char *fields[10];
- int fields_num, found_header = 0;
+ const int max_fields = STATIC_ARRAY_SIZE(fields);
long long sum_users = 0;
+ _Bool found_header = 0;
/* read the file until the "ROUTING TABLE" line is found (no more info after)
*/
if (strcmp(buffer, "ROUTING TABLE\n") == 0)
break;
- if (strcmp(buffer, V1STRING) == 0) {
+ if (strcmp(buffer, V1HEADER) == 0) {
found_header = 1;
continue;
}
/* we can't start reading data until this string is found */
continue;
- fields_num = openvpn_strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
+ int fields_num = openvpn_strsplit(buffer, fields, max_fields);
if (fields_num < 4)
continue;
}
if (ferror(fh))
- return 0;
+ return -1;
+
+ if (found_header == 0) {
+ NOTICE("openvpn plugin: Unknown file format in instance %s, please "
+ "report this as bug. Make sure to include "
+ "your status file, so the plugin can "
+ "be adapted.",
+ name);
+ return -1;
+ }
if (collect_user_count)
numusers_submit(name, name, sum_users);
- return 1;
+ return 0;
} /* int multi1_read */
-/* for reading status version 2 */
+/* for reading status version 2 / version 3
+ * status file is generated by openvpn/multi.c:multi_print_status()
+ * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c
+ */
static int multi2_read(const char *name, FILE *fh) {
char buffer[1024];
- char *fields[10];
+ /* OpenVPN-2.4 has 11 fields of data + 2 fields for "HEADER" and "CLIENT_LIST"
+ * So, set array size to 20 elements, to support future extensions.
+ */
+ char *fields[20];
const int max_fields = STATIC_ARRAY_SIZE(fields);
- int fields_num, read = 0;
long long sum_users = 0;
- while (fgets(buffer, sizeof(buffer), fh) != NULL) {
- fields_num = openvpn_strsplit(buffer, fields, max_fields);
-
- /* status file is generated by openvpn/multi.c:multi_print_status()
- * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c
- *
- * The line we're expecting has 8 fields. We ignore all lines
- * with more or less fields.
- */
- if (fields_num != 8)
- continue;
-
- if (strcmp(fields[0], "CLIENT_LIST") != 0)
- continue;
-
- if (collect_user_count)
- /* If so, sum all users, ignore the individuals*/
- {
- sum_users += 1;
- }
- if (collect_individual_users) {
- if (new_naming_schema) {
- /* plugin inst = file name, type inst = fields[1] */
- iostats_submit(name, /* vpn instance */
- fields[1], /* "Common Name" */
- atoll(fields[4]), /* "Bytes Received" */
- atoll(fields[5])); /* "Bytes Sent" */
- } else {
- /* plugin inst = fields[1], type inst = "" */
- iostats_submit(fields[1], /* "Common Name" */
- NULL, /* unused when in multimode */
- atoll(fields[4]), /* "Bytes Received" */
- atoll(fields[5])); /* "Bytes Sent" */
- }
- }
-
- read = 1;
- }
-
- if (collect_user_count) {
- numusers_submit(name, name, sum_users);
- read = 1;
- }
-
- return read;
-} /* int multi2_read */
-
-/* for reading status version 3 */
-static int multi3_read(const char *name, FILE *fh) {
- char buffer[1024];
- char *fields[15];
- const int max_fields = STATIC_ARRAY_SIZE(fields);
- int fields_num, read = 0;
- long long sum_users = 0;
+ _Bool found_header = 0;
+ int idx_cname = 0;
+ int idx_bytes_recv = 0;
+ int idx_bytes_sent = 0;
+ int columns = 0;
while (fgets(buffer, sizeof(buffer), fh) != NULL) {
- fields_num = strsplit(buffer, fields, max_fields);
+ int fields_num = openvpn_strsplit(buffer, fields, max_fields);
- /* status file is generated by openvpn/multi.c:multi_print_status()
- * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c
- *
- * The line we're expecting has 12 fields. We ignore all lines
- * with more or less fields.
- */
- if (fields_num != 12) {
- continue;
- } else {
- if (strcmp(fields[0], "CLIENT_LIST") != 0)
+ /* Try to find section header */
+ if (found_header == 0) {
+ if (fields_num < 2)
+ continue;
+ if (strcmp(fields[0], "HEADER") != 0)
+ continue;
+ if (strcmp(fields[1], "CLIENT_LIST") != 0)
continue;
- if (collect_user_count)
- /* If so, sum all users, ignore the individuals*/
- {
- sum_users += 1;
- }
-
- if (collect_individual_users) {
- if (new_naming_schema) {
- iostats_submit(name, /* vpn instance */
- fields[1], /* "Common Name" */
- atoll(fields[4]), /* "Bytes Received" */
- atoll(fields[5])); /* "Bytes Sent" */
- } else {
- iostats_submit(fields[1], /* "Common Name" */
- NULL, /* unused when in multimode */
- atoll(fields[4]), /* "Bytes Received" */
- atoll(fields[5])); /* "Bytes Sent" */
+ for (int i = 2; i < fields_num; i++) {
+ if (strcmp(fields[i], "Common Name") == 0) {
+ idx_cname = i - 1;
+ } else if (strcmp(fields[i], "Bytes Received") == 0) {
+ idx_bytes_recv = i - 1;
+ } else if (strcmp(fields[i], "Bytes Sent") == 0) {
+ idx_bytes_sent = i - 1;
}
}
- read = 1;
- }
- }
+ DEBUG("openvpn plugin: found MULTI v2/v3 HEADER. "
+ "Column idx: cname: %d, bytes_recv: %d, bytes_sent: %d",
+ idx_cname, idx_bytes_recv, idx_bytes_sent);
- if (collect_user_count) {
- numusers_submit(name, name, sum_users);
- read = 1;
- }
-
- return read;
-} /* int multi3_read */
+ if (idx_cname == 0 || idx_bytes_recv == 0 || idx_bytes_sent == 0)
+ break;
-/* for reading status version 4 */
-static int multi4_read(const char *name, FILE *fh) {
- char buffer[1024];
- char *fields[11];
- const int max_fields = STATIC_ARRAY_SIZE(fields);
- int fields_num, read = 0;
- long long sum_users = 0;
+ /* Data row has 1 field ("HEADER") less than header row */
+ columns = fields_num - 1;
- while (fgets(buffer, sizeof(buffer), fh) != NULL) {
- fields_num = openvpn_strsplit(buffer, fields, max_fields);
+ found_header = 1;
+ continue;
+ }
- /* status file is generated by openvpn/multi.c:multi_print_status()
- * http://svn.openvpn.net/projects/openvpn/trunk/openvpn/multi.c
- *
- * The line we're expecting has 9 fields. We ignore all lines
- * with more or less fields.
+ /* Header already found. Check if the line is the section data.
+ * If no match, then section was finished and there is no more data.
+ * Empty section is OK too.
*/
- if (fields_num != 9)
- continue;
+ if (fields_num == 0 || strcmp(fields[0], "CLIENT_LIST") != 0)
+ break;
- if (strcmp(fields[0], "CLIENT_LIST") != 0)
- continue;
+ /* Check if the data line fields count matches header line. */
+ if (fields_num != columns) {
+ ERROR("openvpn plugin: File format error in instance %s: Fields count "
+ "mismatch.",
+ name);
+ return -1;
+ }
+
+ DEBUG("openvpn plugin: found MULTI v2/v3 CLIENT_LIST. "
+ "Columns: cname: %s, bytes_recv: %s, bytes_sent: %s",
+ fields[idx_cname], fields[idx_bytes_recv], fields[idx_bytes_sent]);
if (collect_user_count)
- /* If so, sum all users, ignore the individuals*/
- {
sum_users += 1;
- }
+
if (collect_individual_users) {
if (new_naming_schema) {
/* plugin inst = file name, type inst = fields[1] */
- iostats_submit(name, /* vpn instance */
- fields[1], /* "Common Name" */
- atoll(fields[4]), /* "Bytes Received" */
- atoll(fields[5])); /* "Bytes Sent" */
+ iostats_submit(name, /* vpn instance */
+ fields[idx_cname], /* "Common Name" */
+ atoll(fields[idx_bytes_recv]), /* "Bytes Received" */
+ atoll(fields[idx_bytes_sent])); /* "Bytes Sent" */
} else {
- /* plugin inst = fields[1], type inst = "" */
- iostats_submit(fields[1], /* "Common Name" */
- NULL, /* unused when in multimode */
- atoll(fields[4]), /* "Bytes Received" */
- atoll(fields[5])); /* "Bytes Sent" */
+ /* plugin inst = fields[idx_cname], type inst = "" */
+ iostats_submit(fields[idx_cname], /* "Common Name" */
+ NULL, /* unused when in multimode */
+ atoll(fields[idx_bytes_recv]), /* "Bytes Received" */
+ atoll(fields[idx_bytes_sent])); /* "Bytes Sent" */
}
}
+ }
- read = 1;
+ if (ferror(fh))
+ return -1;
+
+ if (found_header == 0) {
+ NOTICE("openvpn plugin: Unknown file format in instance %s, please "
+ "report this as bug. Make sure to include "
+ "your status file, so the plugin can "
+ "be adapted.",
+ name);
+ return -1;
}
if (collect_user_count) {
numusers_submit(name, name, sum_users);
- read = 1;
}
- return read;
-} /* int multi4_read */
+ return 0;
+} /* int multi2_read */
/* read callback */
-static int openvpn_read(void) {
- FILE *fh;
- int read;
-
- read = 0;
-
- if (vpn_num == 0)
- return 0;
-
- /* call the right read function for every status entry in the list */
- for (int i = 0; i < vpn_num; i++) {
- int vpn_read = 0;
-
- fh = fopen(vpn_list[i]->file, "r");
- if (fh == NULL) {
- char errbuf[1024];
- WARNING("openvpn plugin: fopen(%s) failed: %s", vpn_list[i]->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
-
- continue;
- }
-
- switch (vpn_list[i]->version) {
- case SINGLE:
- vpn_read = single_read(vpn_list[i]->name, fh);
- break;
-
- case MULTI1:
- vpn_read = multi1_read(vpn_list[i]->name, fh);
- break;
-
- case MULTI2:
- vpn_read = multi2_read(vpn_list[i]->name, fh);
- break;
-
- case MULTI3:
- vpn_read = multi3_read(vpn_list[i]->name, fh);
- break;
-
- case MULTI4:
- vpn_read = multi4_read(vpn_list[i]->name, fh);
- break;
- }
-
- fclose(fh);
- read += vpn_read;
- }
-
- return read ? 0 : -1;
-} /* int openvpn_read */
-
-static int version_detect(const char *filename) {
- FILE *fh;
+static int openvpn_read(user_data_t *user_data) {
char buffer[1024];
- int version = 0;
+ int read = 0;
- /* Sanity checking. We're called from the config handling routine, so
- * better play it save. */
- if ((filename == NULL) || (*filename == 0))
- return 0;
+ vpn_status_t *st = user_data->data;
- fh = fopen(filename, "r");
+ FILE *fh = fopen(st->file, "r");
if (fh == NULL) {
- char errbuf[1024];
- WARNING("openvpn plugin: Unable to read \"%s\": %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
- return 0;
+ WARNING("openvpn plugin: fopen(%s) failed: %s", st->file, STRERRNO);
+
+ return -1;
}
- /* now search for the specific multimode data format */
- while ((fgets(buffer, sizeof(buffer), fh)) != NULL) {
- /* we look at the first line searching for SINGLE mode configuration */
- if (strcmp(buffer, VSSTRING) == 0) {
- DEBUG("openvpn plugin: found status file version SINGLE");
- version = SINGLE;
- break;
- }
- /* searching for multi version 1 */
- else if (strcmp(buffer, V1STRING) == 0) {
- DEBUG("openvpn plugin: found status file version MULTI1");
- version = MULTI1;
- break;
- }
- /* searching for multi version 2 */
- else if (strcmp(buffer, V2STRING) == 0) {
- DEBUG("openvpn plugin: found status file version MULTI2");
- version = MULTI2;
- break;
- }
- /* searching for multi version 3 */
- else if (strcmp(buffer, V3STRING) == 0) {
- DEBUG("openvpn plugin: found status file version MULTI3");
- version = MULTI3;
- break;
- }
- /* searching for multi version 4 */
- else if (strcmp(buffer, V4STRING) == 0) {
- DEBUG("openvpn plugin: found status file version MULTI4");
- version = MULTI4;
- break;
- }
+ // Try to detect file format by its first line
+ if ((fgets(buffer, sizeof(buffer), fh)) == NULL) {
+ WARNING("openvpn plugin: failed to get data from: %s", st->file);
+ fclose(fh);
+ return -1;
}
- if (version == 0) {
- /* This is only reached during configuration, so complaining to
- * the user is in order. */
+ if (strcmp(buffer, TITLE_SINGLE) == 0) { // OpenVPN STATISTICS
+ DEBUG("openvpn plugin: found status file SINGLE");
+ read = single_read(st->name, fh);
+ } else if (strcmp(buffer, TITLE_V1) == 0) { // OpenVPN CLIENT LIST
+ DEBUG("openvpn plugin: found status file MULTI version 1");
+ read = multi1_read(st->name, fh);
+ } else if (strncmp(buffer, TITLE_V2, strlen(TITLE_V2)) == 0) { // TITLE
+ DEBUG("openvpn plugin: found status file MULTI version 2/3");
+ read = multi2_read(st->name, fh);
+ } else {
NOTICE("openvpn plugin: %s: Unknown file format, please "
"report this as bug. Make sure to include "
"your status file, so the plugin can "
"be adapted.",
- filename);
+ st->file);
+ read = -1;
}
-
fclose(fh);
-
- return version;
-} /* int version_detect */
+ return read;
+} /* int openvpn_read */
static int openvpn_config(const char *key, const char *value) {
if (strcasecmp("StatusFile", key) == 0) {
- char *status_file, *status_name, *filename;
- int status_version;
- vpn_status_t *temp;
-
- /* try to detect the status file format */
- status_version = version_detect(value);
+ char callback_name[3 * DATA_MAX_NAME_LEN];
+ char *status_name;
- if (status_version == 0) {
- WARNING("openvpn plugin: unable to detect status version, "
- "discarding status file \"%s\".",
- value);
- return 1;
- }
-
- status_file = sstrdup(value);
+ char *status_file = strdup(value);
if (status_file == NULL) {
- char errbuf[1024];
- WARNING("openvpn plugin: sstrdup failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("openvpn plugin: strdup failed: %s", STRERRNO);
return 1;
}
/* it determines the file name as string starting at location filename + 1
*/
- filename = strrchr(status_file, (int)'/');
+ char *filename = strrchr(status_file, (int)'/');
if (filename == NULL) {
/* status_file is already the file name only */
status_name = status_file;
status_name = filename + 1;
}
- /* scan the list looking for a clone */
- for (int i = 0; i < vpn_num; i++) {
- if (strcasecmp(vpn_list[i]->name, status_name) == 0) {
- WARNING("openvpn plugin: status filename \"%s\" "
- "already used, please choose a "
- "different one.",
- status_name);
- sfree(status_file);
- return 1;
- }
- }
-
- /* create a new vpn element since file, version and name are ok */
- temp = malloc(sizeof(*temp));
- if (temp == NULL) {
- char errbuf[1024];
- ERROR("openvpn plugin: malloc failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ /* create a new vpn element */
+ vpn_status_t *instance = calloc(1, sizeof(*instance));
+ if (instance == NULL) {
+ ERROR("openvpn plugin: malloc failed: %s", STRERRNO);
sfree(status_file);
return 1;
}
- temp->file = status_file;
- temp->version = status_version;
- temp->name = status_name;
-
- vpn_status_t **tmp_list =
- realloc(vpn_list, (vpn_num + 1) * sizeof(*vpn_list));
- if (tmp_list == NULL) {
- char errbuf[1024];
- ERROR("openvpn plugin: realloc failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
-
- sfree(vpn_list);
- sfree(temp->file);
- sfree(temp);
- return 1;
+ instance->file = status_file;
+ instance->name = status_name;
+
+ snprintf(callback_name, sizeof(callback_name), "openvpn/%s", status_name);
+
+ int status = plugin_register_complex_read(
+ /* group = */ "openvpn",
+ /* name = */ callback_name,
+ /* callback = */ openvpn_read,
+ /* interval = */ 0,
+ &(user_data_t){
+ .data = instance, .free_func = openvpn_free,
+ });
+
+ if (status == EINVAL) {
+ WARNING("openvpn plugin: status filename \"%s\" "
+ "already used, please choose a "
+ "different one.",
+ status_name);
+ return -1;
}
- vpn_list = tmp_list;
-
- vpn_list[vpn_num] = temp;
- vpn_num++;
-
- DEBUG("openvpn plugin: status file \"%s\" added", temp->file);
+ DEBUG("openvpn plugin: status file \"%s\" added", instance->file);
} /* if (strcasecmp ("StatusFile", key) == 0) */
else if ((strcasecmp("CollectCompression", key) == 0) ||
(strcasecmp("Compression", key) == 0)) /* old, deprecated name */
return 0;
} /* int openvpn_config */
-/* shutdown callback */
-static int openvpn_shutdown(void) {
- for (int i = 0; i < vpn_num; i++) {
- sfree(vpn_list[i]->file);
- sfree(vpn_list[i]);
- }
-
- sfree(vpn_list);
-
- return 0;
-} /* int openvpn_shutdown */
-
static int openvpn_init(void) {
if (!collect_individual_users && !collect_compression &&
!collect_user_count) {
return -1;
}
- plugin_register_read("openvpn", openvpn_read);
- plugin_register_shutdown("openvpn", openvpn_shutdown);
-
return 0;
} /* int openvpn_init */
char *connect_id;
char *username;
char *password;
+ char *plugin_name;
udb_query_preparation_area_t **q_prep_areas;
udb_query_t **queries;
sfree(db->username);
sfree(db->password);
sfree(db->queries);
+ sfree(db->plugin_name);
if (db->q_prep_areas != NULL)
for (size_t i = 0; i < db->queries_num; ++i)
db->connect_id = NULL;
db->username = NULL;
db->password = NULL;
+ db->plugin_name = NULL;
status = cf_util_get_string(ci, &db->name);
if (status != 0) {
status = cf_util_get_string(child, &db->username);
else if (strcasecmp("Password", child->key) == 0)
status = cf_util_get_string(child, &db->password);
+ else if (strcasecmp("Plugin", child->key) == 0)
+ status = cf_util_get_string(child, &db->plugin_name);
else if (strcasecmp("Query", child->key) == 0)
status = udb_query_pick_from_list(child, queries, queries_num,
&db->queries, &db->queries_num);
}
if (queries_num > 0) {
- DEBUG("oracle plugin: o_config: queries_num = %zu; queries[0] = %p; "
- "udb_query_get_user_data (queries[0]) = %p;",
- queries_num, (void *)queries[0],
- udb_query_get_user_data(queries[0]));
+ DEBUG(
+ "oracle plugin: o_config: queries_num = %" PRIsz "; queries[0] = %p; "
+ "udb_query_get_user_data (queries[0]) = %p;",
+ queries_num, (void *)queries[0], udb_query_get_user_data(queries[0]));
}
} /* for (ci->children) */
memcpy(column_names[i], column_name, column_name_length);
column_names[i][column_name_length] = 0;
- DEBUG("oracle plugin: o_read_database_query: column_names[%zu] = %s; "
- "column_name_length = %" PRIu32 ";",
+ DEBUG("oracle plugin: o_read_database_query: column_names[%" PRIsz "] = %s;"
+ " column_name_length = %" PRIu32 ";",
i, column_names[i], (uint32_t)column_name_length);
status = OCIDefineByPos(oci_statement, &oci_defines[i], oci_error,
status = udb_query_prepare_result(
q, prep_area, (db->host != NULL) ? db->host : hostname_g,
- /* plugin = */ "oracle", db->name, column_names, column_num,
+ /* plugin = */ (db->plugin_name != NULL) ? db->plugin_name : "oracle",
+ db->name, column_names, column_num,
/* interval = */ 0);
if (status != 0) {
ERROR("oracle plugin: o_read_database_query (%s, %s): "
ovs_events_config_free();
return -1;
}
- strncpy(ovs_events_ctx.config.ovs_db_serv, service,
- sizeof(ovs_events_ctx.config.ovs_db_serv));
+ sstrncpy(ovs_events_ctx.config.ovs_db_serv, service,
+ sizeof(ovs_events_ctx.config.ovs_db_serv));
sfree(service);
} else if (strcasecmp("Socket", child->key) == 0) {
if (cf_util_get_string_buffer(
if (!YAJL_IS_OBJECT(jobject))
return -1;
- /* zero the interface info structure */
- memset(ifinfo, 0, sizeof(*ifinfo));
-
/* try to find external_ids, name and link_state fields */
jexternal_ids = ovs_utils_get_value_by_key(jobject, "external_ids");
if (jexternal_ids == NULL || ifinfo == NULL)
return -1;
+ /* zero the interface info structure */
+ memset(ifinfo, 0, sizeof(*ifinfo));
+
/* get iface-id from external_ids field */
jvalue = ovs_utils_get_map_value(jexternal_ids, "iface-id");
if (jvalue != NULL && YAJL_IS_STRING(jvalue))
/* Create or get port by port uuid */
static port_list_t *ovs_stats_new_port(bridge_list_t *bridge,
const char *uuid) {
+ if (uuid == NULL)
+ return NULL;
+
port_list_t *port = ovs_stats_get_port(uuid);
if (port == NULL) {
br = ovs_stats_get_bridge(g_bridge_list_head, YAJL_GET_STRING(br_name));
pthread_mutex_lock(&g_stats_lock);
if (br == NULL) {
- br = (bridge_list_t *)calloc(1, sizeof(bridge_list_t));
+ br = calloc(1, sizeof(*br));
if (!br) {
- ERROR("%s: Error allocating memory for bridge", plugin_name);
+ pthread_mutex_unlock(&g_stats_lock);
+ ERROR("%s: calloc(%zu) failed.", plugin_name, sizeof(*br));
return -1;
}
char *tmp = YAJL_GET_STRING(br_name);
if (br->name == NULL) {
sfree(br);
pthread_mutex_unlock(&g_stats_lock);
+ ERROR("%s: strdup failed.", plugin_name);
return -1;
}
br->next = g_bridge_list_head;
yajl_val *array = YAJL_GET_ARRAY(br_ports)->values;
size_t array_len = YAJL_GET_ARRAY(br_ports)->len;
if (array != NULL && array_len > 0 && YAJL_IS_ARRAY(array[1])) {
- yajl_val *ports_arr = YAJL_GET_ARRAY(array[1])->values;
- size_t ports_num = YAJL_GET_ARRAY(array[1])->len;
- for (size_t i = 0; i < ports_num && ports_arr != NULL; i++)
- ovs_stats_new_port(
- br, YAJL_GET_STRING(ports_arr[i]->u.array.values[1]));
+ if (YAJL_GET_ARRAY(array[1]) == NULL)
+ goto failure;
+ else {
+ yajl_val *ports_arr = YAJL_GET_ARRAY(array[1])->values;
+ size_t ports_num = YAJL_GET_ARRAY(array[1])->len;
+ for (size_t i = 0; i < ports_num && ports_arr != NULL; i++) {
+ tmp = YAJL_GET_STRING(ports_arr[i]->u.array.values[1]);
+ if (tmp != NULL)
+ ovs_stats_new_port(br, tmp);
+ else
+ goto failure;
+ }
+ }
}
} else
ovs_stats_new_port(br, YAJL_GET_STRING(br_ports->u.array.values[1]));
}
}
} else {
- ERROR("Incorrect JSON Bridge data");
- return -1;
+ goto failure;
}
+
return 0;
+
+failure:
+ ERROR("Incorrect JSON Bridge data");
+ return -1;
}
/* Handle JSON with Bridge Table change event */
/* Get interface statistic and external_ids */
static int ovs_stats_update_iface(yajl_val iface) {
- yajl_val row;
- port_list_t *port = NULL;
- if (iface && YAJL_IS_OBJECT(iface)) {
- row = ovs_utils_get_value_by_key(iface, "new");
- if (row && YAJL_IS_OBJECT(row)) {
- yajl_val iface_name = ovs_utils_get_value_by_key(row, "name");
- yajl_val iface_stats = ovs_utils_get_value_by_key(row, "statistics");
- yajl_val iface_ext_ids = ovs_utils_get_value_by_key(row, "external_ids");
- yajl_val iface_uuid = ovs_utils_get_value_by_key(row, "_uuid");
- if (iface_name && YAJL_IS_STRING(iface_name)) {
- port = ovs_stats_get_port_by_name(YAJL_GET_STRING(iface_name));
- if (port == NULL)
- return 0;
- }
- /*
- * {
- "statistics": [
- "map",
- [
- [
- "collisions",
- 0
- ],
- . . .
- [
- "tx_packets",
- 0
- ]
- ]
+ if (!iface || !YAJL_IS_OBJECT(iface)) {
+ ERROR("ovs_stats plugin: incorrect JSON port data");
+ return -1;
+ }
+
+ yajl_val row = ovs_utils_get_value_by_key(iface, "new");
+ if (!row || !YAJL_IS_OBJECT(row))
+ return 0;
+
+ yajl_val iface_name = ovs_utils_get_value_by_key(row, "name");
+ if (!iface_name || !YAJL_IS_STRING(iface_name))
+ return 0;
+
+ port_list_t *port = ovs_stats_get_port_by_name(YAJL_GET_STRING(iface_name));
+ if (port == NULL)
+ return 0;
+
+ yajl_val iface_stats = ovs_utils_get_value_by_key(row, "statistics");
+ yajl_val iface_ext_ids = ovs_utils_get_value_by_key(row, "external_ids");
+ yajl_val iface_uuid = ovs_utils_get_value_by_key(row, "_uuid");
+ /*
+ * {
+ "statistics": [
+ "map",
+ [
+ [
+ "collisions",
+ 0
+ ],
+ . . .
+ [
+ "tx_packets",
+ 0
]
- }
- Check that statistics is an array with 2 elements
- */
- if (iface_stats && YAJL_IS_ARRAY(iface_stats) &&
- YAJL_GET_ARRAY(iface_stats)->len == 2)
- ovs_stats_update_iface_stats(port,
- YAJL_GET_ARRAY(iface_stats)->values[1]);
- if (iface_ext_ids && YAJL_IS_ARRAY(iface_ext_ids))
- ovs_stats_update_iface_ext_ids(
- port, YAJL_GET_ARRAY(iface_ext_ids)->values[1]);
- if (iface_uuid && YAJL_IS_ARRAY(iface_uuid) &&
- YAJL_GET_ARRAY(iface_uuid)->len == 2)
- sstrncpy(port->iface_uuid,
- YAJL_GET_STRING(YAJL_GET_ARRAY(iface_uuid)->values[1]),
- sizeof(port->iface_uuid));
- }
- } else {
- ERROR("Incorrect JSON Port data");
+ ]
+ ]
+ }
+ Check that statistics is an array with 2 elements
+ */
+ if (iface_stats && YAJL_IS_ARRAY(iface_stats) &&
+ YAJL_GET_ARRAY(iface_stats)->len == 2)
+ ovs_stats_update_iface_stats(port, YAJL_GET_ARRAY(iface_stats)->values[1]);
+ if (iface_ext_ids && YAJL_IS_ARRAY(iface_ext_ids))
+ ovs_stats_update_iface_ext_ids(port,
+ YAJL_GET_ARRAY(iface_ext_ids)->values[1]);
+ if (iface_uuid && YAJL_IS_ARRAY(iface_uuid) &&
+ YAJL_GET_ARRAY(iface_uuid)->len == 2 &&
+ YAJL_GET_STRING(YAJL_GET_ARRAY(iface_uuid)->values[1]) != NULL)
+ sstrncpy(port->iface_uuid,
+ YAJL_GET_STRING(YAJL_GET_ARRAY(iface_uuid)->values[1]),
+ sizeof(port->iface_uuid));
+ else {
+ ERROR("ovs_stats plugin: incorrect JSON interface data");
return -1;
}
+
return 0;
}
*/
static int ovs_stats_plugin_config(oconfig_item_t *ci) {
bridge_list_t *bridge;
- char *br_name;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
goto cleanup_fail;
}
/* get value */
- if ((br_name = strdup(child->values[j].value.string)) == NULL) {
- ERROR("%s: strdup() copy bridge name fail", plugin_name);
- goto cleanup_fail;
- }
+ char const *br_name = child->values[j].value.string;
if ((bridge = ovs_stats_get_bridge(g_monitored_bridge_list_head,
br_name)) == NULL) {
if ((bridge = calloc(1, sizeof(bridge_list_t))) == NULL) {
ERROR("%s: Error allocating memory for bridge", plugin_name);
goto cleanup_fail;
} else {
+ char *br_name_dup = strdup(br_name);
+ if (br_name_dup == NULL) {
+ ERROR("%s: strdup() copy bridge name fail", plugin_name);
+ sfree(bridge);
+ goto cleanup_fail;
+ }
+
pthread_mutex_lock(&g_stats_lock);
/* store bridge name */
- bridge->name = br_name;
+ bridge->name = br_name_dup;
bridge->next = g_monitored_bridge_list_head;
g_monitored_bridge_list_head = bridge;
pthread_mutex_unlock(&g_stats_lock);
/* Shutdown OvS Stats plugin */
static int ovs_stats_plugin_shutdown(void) {
- pthread_mutex_lock(&g_stats_lock);
DEBUG("OvS Statistics plugin shutting down");
ovs_db_destroy(g_ovs_db);
+ pthread_mutex_lock(&g_stats_lock);
ovs_stats_free_bridge_list(g_bridge_list_head);
ovs_stats_free_bridge_list(g_monitored_bridge_list_head);
ovs_stats_free_port_list(g_port_list_head);
{"Collectd::NOTIF_WARNING", NOTIF_WARNING},
{"Collectd::NOTIF_OKAY", NOTIF_OKAY},
{"", 0}};
-
-struct {
- char name[64];
- char *var;
-} g_strings[] = {{"Collectd::hostname_g", hostname_g}, {"", NULL}};
-
/*
* Helper functions for data type conversion.
*/
if (array_len < ds->ds_num) {
log_warn("av2value: array does not contain enough elements for type "
- "\"%s\": got %zu, want %zu",
+ "\"%s\": got %" PRIsz ", want %" PRIsz,
name, array_len, ds->ds_num);
return 0;
} else if (array_len > ds->ds_num) {
log_warn("av2value: array contains excess elements for type \"%s\": got "
- "%zu, want %zu",
+ "%" PRIsz ", want %" PRIsz,
name, array_len, ds->ds_num);
}
if (NULL != (tmp = hv_fetch(hash, "host", 4, 0)))
sstrncpy(vl->host, SvPV_nolen(*tmp), sizeof(vl->host));
- else
- sstrncpy(vl->host, hostname_g, sizeof(vl->host));
if (NULL != (tmp = hv_fetch(hash, "plugin", 6, 0)))
sstrncpy(vl->plugin, SvPV_nolen(*tmp), sizeof(vl->plugin));
static int notification_meta2av(pTHX_ notification_meta_t *meta, AV *array) {
int meta_num = 0;
-
- while (meta) {
+ for (notification_meta_t *m = meta; m != NULL; m = m->next) {
++meta_num;
- meta = meta->next;
}
av_extend(array, meta_num);
ret = plugin_register_flush("perl", perl_flush, /* user_data = */ NULL);
}
- if (0 == ret)
+ if (0 == ret) {
ret = plugin_register_flush(pluginname, perl_flush, &userdata);
+ } else {
+ free(userdata.data);
+ }
} else {
ret = -1;
}
if (0 == ret)
XSRETURN_YES;
- else {
- free(userdata.data);
+ else
XSRETURN_EMPTY;
- }
} /* static void _plugin_register_generic_userdata ( ... ) */
/*
/* Lock the base thread to avoid race conditions with c_ithread_create().
* See https://github.com/collectd/collectd/issues/9 and
* https://github.com/collectd/collectd/issues/1706 for details.
- */
+ */
assert(aTHX == perl_threads->head->interp);
pthread_mutex_lock(&perl_threads->mutex);
/* Lock the base thread if this is not called from one of the read threads
* to avoid race conditions with c_ithread_create(). See
* https://github.com/collectd/collectd/issues/9 for details.
- */
+ */
if (aTHX == perl_threads->head->interp)
pthread_mutex_lock(&perl_threads->mutex);
* accessing any such variable (this is basically the same as using
* tie() in Perl) */
/* global strings */
+ struct {
+ char name[64];
+ char *var;
+ } g_strings[] = {{"Collectd::hostname_g", hostname_g}, {"", NULL}};
+
for (int i = 0; '\0' != g_strings[i].name[0]; ++i) {
tmp = get_sv(g_strings[i].name, 1);
sv_magicext(tmp, NULL, PERL_MAGIC_ext, &g_pv_vtbl, g_strings[i].var, 0);
char *plugin;
HV *config;
+ if (NULL == perl_threads) {
+ log_err("A `Plugin' block was encountered but no plugin was loaded yet. "
+ "Put the appropriate `LoadPlugin' option in front of it.");
+ return -1;
+ }
+
dSP;
if ((1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
fd = open(pf_device, O_RDONLY);
if (fd < 0) {
- char errbuf[1024];
- ERROR("pf plugin: Unable to open %s: %s", pf_device,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("pf plugin: Unable to open %s: %s", pf_device, STRERRNO);
return -1;
}
status = ioctl(fd, DIOCGETSTATUS, &state);
if (status != 0) {
- char errbuf[1024];
- ERROR("pf plugin: ioctl(DIOCGETSTATUS) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("pf plugin: ioctl(DIOCGETSTATUS) failed: %s", STRERRNO);
close(fd);
return -1;
}
fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (fd < 0) {
- char errbuf[1024];
- ERROR("pinba plugin: socket(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("pinba plugin: socket(2) failed: %s", STRERRNO);
return 0;
}
tmp = 1;
status = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
if (status != 0) {
- char errbuf[1024];
- WARNING("pinba plugin: setsockopt(SO_REUSEADDR) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("pinba plugin: setsockopt(SO_REUSEADDR) failed: %s", STRERRNO);
}
status = bind(fd, ai->ai_addr, ai->ai_addrlen);
if (status != 0) {
- char errbuf[1024];
- ERROR("pinba plugin: bind(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("pinba plugin: bind(2) failed: %s", STRERRNO);
close(fd);
return 0;
}
status = recvfrom(sock, buffer, buffer_size - 1, MSG_DONTWAIT,
/* from = */ NULL, /* from len = */ 0);
if (status < 0) {
- char errbuf[1024];
if ((errno == EINTR)
#ifdef EWOULDBLOCK
continue;
}
- WARNING("pinba plugin: recvfrom(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("pinba plugin: recvfrom(2) failed: %s", STRERRNO);
return -1;
} else if (status == 0) {
DEBUG("pinba plugin: recvfrom(2) returned unexpected status zero.");
{
continue;
} else if (status < 0) {
- char errbuf[1024];
-
if ((errno == EINTR) || (errno == EAGAIN))
continue;
- ERROR("pinba plugin: poll(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("pinba plugin: poll(2) failed: %s", STRERRNO);
pinba_socket_free(s);
return -1;
}
/* attrs = */ NULL, collector_thread,
/* args = */ NULL, "pinba collector");
if (status != 0) {
- char errbuf[1024];
- ERROR("pinba plugin: pthread_create(3) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("pinba plugin: pthread_create(3) failed: %s", STRERRNO);
return -1;
}
collector_thread_running = 1;
status = pthread_join(collector_thread_id, /* retval = */ NULL);
if (status != 0) {
- char errbuf[1024];
- ERROR("pinba plugin: pthread_join(3) failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("pinba plugin: pthread_join(3) failed: %s", STRERROR(status));
}
collector_thread_running = 0;
static double ping_timeout = 0.9;
static int ping_max_missed = -1;
+static pthread_mutex_t ping_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t ping_cond = PTHREAD_COND_INITIALIZER;
static int ping_thread_loop = 0;
static int ping_thread_error = 0;
static pthread_t ping_thread_id;
-static pthread_mutex_t ping_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t ping_cond = PTHREAD_COND_INITIALIZER;
static const char *config_keys[] = {"Host", "SourceAddress",
#ifdef HAVE_OPING_1_3
static void *ping_thread(void *arg) /* {{{ */
{
- pingobj_t *pingobj = NULL;
-
struct timeval tv_begin;
struct timeval tv_end;
struct timespec ts_wait;
c_complain_t complaint = C_COMPLAIN_INIT_STATIC;
- pthread_mutex_lock(&ping_lock);
-
- pingobj = ping_construct();
+ pingobj_t *pingobj = ping_construct();
if (pingobj == NULL) {
ERROR("ping plugin: ping_construct failed.");
+ pthread_mutex_lock(&ping_lock);
ping_thread_error = 1;
pthread_mutex_unlock(&ping_lock);
return (void *)-1;
if (count == 0) {
ERROR("ping plugin: No host could be added to ping object. Giving up.");
+ pthread_mutex_lock(&ping_lock);
ping_thread_error = 1;
pthread_mutex_unlock(&ping_lock);
return (void *)-1;
ts_int.tv_nsec = (long)(temp_nsec * 1000000000L);
}
+ pthread_mutex_lock(&ping_lock);
while (ping_thread_loop > 0) {
- int status;
_Bool send_successful = 0;
if (gettimeofday(&tv_begin, NULL) < 0) {
- char errbuf[1024];
- ERROR("ping plugin: gettimeofday failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ping plugin: gettimeofday failed: %s", STRERRNO);
ping_thread_error = 1;
break;
}
pthread_mutex_unlock(&ping_lock);
- status = ping_send(pingobj);
+ int status = ping_send(pingobj);
if (status < 0) {
c_complain(LOG_ERR, &complaint, "ping plugin: ping_send failed: %s",
ping_get_error(pingobj));
(void)ping_dispatch_all(pingobj);
if (gettimeofday(&tv_end, NULL) < 0) {
- char errbuf[1024];
- ERROR("ping plugin: gettimeofday failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ping plugin: gettimeofday failed: %s", STRERRNO);
ping_thread_error = 1;
break;
}
tmp = strdup(value);
if (tmp == NULL) {
- char errbuf[1024];
ERROR("ping plugin: Setting `%s' to `%s' failed: strdup failed: %s", name,
- value, sstrerror(errno, errbuf, sizeof(errbuf)));
+ value, STRERRNO);
return 1;
}
hl = malloc(sizeof(*hl));
if (hl == NULL) {
- char errbuf[1024];
- ERROR("ping plugin: malloc failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ping plugin: malloc failed: %s", STRERRNO);
return 1;
}
host = strdup(value);
if (host == NULL) {
- char errbuf[1024];
sfree(hl);
- ERROR("ping plugin: strdup failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ping plugin: strdup failed: %s", STRERRNO);
return 1;
}
} /* }}} for (i = 0; i < size; i++) */
ping_data[size] = 0;
} else
- WARNING("ping plugin: Ignoring invalid Size %zu.", size);
+ WARNING("ping plugin: Ignoring invalid Size %" PRIsz ".", size);
} else if (strcasecmp(key, "Timeout") == 0) {
double tmp;
char *password;
char *instance;
+ char *plugin_name;
char *sslmode;
db->instance = sstrdup(name);
+ db->plugin_name = NULL;
+
db->sslmode = NULL;
db->krbsrvname = NULL;
sfree(db->instance);
+ sfree(db->plugin_name);
+
sfree(db->sslmode);
sfree(db->krbsrvname);
C_PSQL_PAR_APPEND(buf, buf_len, "sslmode", db->sslmode);
C_PSQL_PAR_APPEND(buf, buf_len, "krbsrvname", db->krbsrvname);
C_PSQL_PAR_APPEND(buf, buf_len, "service", db->service);
+ C_PSQL_PAR_APPEND(buf, buf_len, "application_name", "collectd_postgresql");
db->conn = PQconnectdb(conninfo);
db->proto_version = PQprotocolVersion(db->conn);
else
host = db->host;
- status =
- udb_query_prepare_result(q, prep_area, host, "postgresql", db->instance,
- column_names, (size_t)column_num, db->interval);
+ status = udb_query_prepare_result(
+ q, prep_area, host,
+ (db->plugin_name != NULL) ? db->plugin_name : "postgresql", db->instance,
+ column_names, (size_t)column_num, db->interval);
+
if (0 != status) {
log_err("udb_query_prepare_result failed with status %i.", status);
BAIL_OUT(-1);
status = snprintf(str_ptr, str_len, ",%lf", rates[i]);
} else if (ds->ds[i].type == DS_TYPE_COUNTER)
- status = snprintf(str_ptr, str_len, ",%llu", vl->values[i].counter);
+ status = snprintf(str_ptr, str_len, ",%" PRIu64,
+ (uint64_t)vl->values[i].counter);
else if (ds->ds[i].type == DS_TYPE_DERIVE)
status = snprintf(str_ptr, str_len, ",%" PRIi64, vl->values[i].derive);
else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
cf_util_get_string(c, &db->password);
else if (0 == strcasecmp(c->key, "Instance"))
cf_util_get_string(c, &db->instance);
+ else if (0 == strcasecmp(c->key, "Plugin"))
+ cf_util_get_string(c, &db->plugin_name);
else if (0 == strcasecmp(c->key, "SSLMode"))
cf_util_get_string(c, &db->sslmode);
else if (0 == strcasecmp(c->key, "KRBSrvName"))
</Query>
<Query queries>
- Statement "SELECT sum(n_tup_ins) AS ins, \
- sum(n_tup_upd) AS upd, \
- sum(n_tup_del) AS del \
+ Statement "SELECT coalesce(sum(n_tup_ins), 0) AS ins, \
+ coalesce(sum(n_tup_upd), 0) AS upd, \
+ coalesce(sum(n_tup_del), 0) AS del \
FROM pg_stat_user_tables;"
<Result>
</Query>
<Query queries>
- Statement "SELECT sum(n_tup_ins) AS ins, \
- sum(n_tup_upd) AS upd, \
- sum(n_tup_del) AS del, \
- sum(n_tup_hot_upd) AS hot_upd \
+ Statement "SELECT coalesce(sum(n_tup_ins), 0) AS ins, \
+ coalesce(sum(n_tup_upd), 0) AS upd, \
+ coalesce(sum(n_tup_del), 0) AS del, \
+ coalesce(sum(n_tup_hot_upd), 0) AS hot_upd \
FROM pg_stat_user_tables;"
<Result>
</Query>
<Query table_states>
- Statement "SELECT sum(n_live_tup) AS live, sum(n_dead_tup) AS dead \
+ Statement "SELECT coalesce(sum(n_live_tup), 0) AS live, \
+ coalesce(sum(n_dead_tup), 0) AS dead \
FROM pg_stat_user_tables;"
<Result>
#endif
#define FUNC_ERROR(func) \
do { \
- char errbuf[1024]; \
- ERROR("powerdns plugin: %s failed: %s", func, \
- sstrerror(errno, errbuf, sizeof(errbuf))); \
+ ERROR("powerdns plugin: %s failed: %s", func, STRERRNO); \
} while (0)
#define SOCK_ERROR(func, sockpath) \
do { \
- char errbuf[1024]; \
ERROR("powerdns plugin: Socket `%s` %s failed: %s", sockpath, func, \
- sstrerror(errno, errbuf, sizeof(errbuf))); \
+ STRERRNO); \
} while (0)
#define SERVER_SOCKET LOCALSTATEDIR "/run/pdns.controlsocket"
}
if (ds->ds_num != 1) {
- ERROR("powerdns plugin: type `%s' has %zu data sources, "
+ ERROR("powerdns plugin: type `%s' has %" PRIsz " data sources, "
"but I can only handle one.",
type, ds->ds_num);
return;
plugin_dispatch_values(&vl);
} /* }}} static void submit */
-static int powerdns_get_data_dgram(list_item_t *item, /* {{{ */
- char **ret_buffer, size_t *ret_buffer_size) {
+static int powerdns_get_data_dgram(list_item_t *item, char **ret_buffer) {
+ /* {{{ */
int sd;
int status;
buffer[buffer_size - 1] = 0;
*ret_buffer = buffer;
- *ret_buffer_size = buffer_size;
-
return 0;
} /* }}} int powerdns_get_data_dgram */
-static int powerdns_get_data_stream(list_item_t *item, /* {{{ */
- char **ret_buffer,
- size_t *ret_buffer_size) {
+static int powerdns_get_data_stream(list_item_t *item, char **ret_buffer) {
+ /* {{{ */
int sd;
int status;
if (status < 0) {
SOCK_ERROR("recv", item->sockaddr.sun_path);
break;
- } else if (status == 0)
+ } else if (status == 0) {
break;
+ }
buffer_new = realloc(buffer, buffer_size + status + 1);
if (buffer_new == NULL) {
FUNC_ERROR("realloc");
- status = -1;
+ status = ENOMEM;
break;
}
buffer = buffer_new;
} /* while (42) */
close(sd);
- if (status < 0) {
+ if (status != 0) {
sfree(buffer);
- } else {
- assert(status == 0);
- *ret_buffer = buffer;
- *ret_buffer_size = buffer_size;
+ return status;
}
- return status;
+ *ret_buffer = buffer;
+ return 0;
} /* }}} int powerdns_get_data_stream */
-static int powerdns_get_data(list_item_t *item, char **ret_buffer,
- size_t *ret_buffer_size) {
+static int powerdns_get_data(list_item_t *item, char **ret_buffer) {
if (item->socktype == SOCK_DGRAM)
- return powerdns_get_data_dgram(item, ret_buffer, ret_buffer_size);
+ return powerdns_get_data_dgram(item, ret_buffer);
else if (item->socktype == SOCK_STREAM)
- return powerdns_get_data_stream(item, ret_buffer, ret_buffer_size);
+ return powerdns_get_data_stream(item, ret_buffer);
else {
ERROR("powerdns plugin: Unknown socket type: %i", (int)item->socktype);
return -1;
static int powerdns_read_server(list_item_t *item) /* {{{ */
{
- char *buffer = NULL;
- size_t buffer_size = 0;
- int status;
-
- char *dummy;
- char *saveptr;
-
- char *key;
- char *value;
-
- const char *const *fields;
- int fields_num;
-
if (item->command == NULL)
item->command = strdup(SERVER_COMMAND);
if (item->command == NULL) {
return -1;
}
- status = powerdns_get_data(item, &buffer, &buffer_size);
- if (status != 0)
- return -1;
+ char *buffer = NULL;
+ int status = powerdns_get_data(item, &buffer);
+ if (status != 0) {
+ ERROR("powerdns plugin: powerdns_get_data failed.");
+ return status;
+ }
+ if (buffer == NULL) {
+ return EINVAL;
+ }
+ const char *const *fields = default_server_fields;
+ int fields_num = default_server_fields_num;
if (item->fields_num != 0) {
fields = (const char *const *)item->fields;
fields_num = item->fields_num;
- } else {
- fields = default_server_fields;
- fields_num = default_server_fields_num;
}
assert(fields != NULL);
/* corrupt-packets=0,deferred-cache-inserts=0,deferred-cache-lookup=0,latency=0,packetcache-hit=0,packetcache-miss=0,packetcache-size=0,qsize-q=0,query-cache-hit=0,query-cache-miss=0,recursing-answers=0,recursing-questions=0,servfail-packets=0,tcp-answers=0,tcp-queries=0,timedout-packets=0,udp-answers=0,udp-queries=0,udp4-answers=0,udp4-queries=0,udp6-answers=0,udp6-queries=0,
*/
- dummy = buffer;
- saveptr = NULL;
+ char *dummy = buffer;
+ char *saveptr = NULL;
+ char *key;
while ((key = strtok_r(dummy, ",", &saveptr)) != NULL) {
dummy = NULL;
- value = strchr(key, '=');
+ char *value = strchr(key, '=');
if (value == NULL)
break;
static int powerdns_read_recursor(list_item_t *item) /* {{{ */
{
char *buffer = NULL;
- size_t buffer_size = 0;
int status;
char *dummy;
}
assert(item->command != NULL);
- status = powerdns_get_data(item, &buffer, &buffer_size);
+ status = powerdns_get_data(item, &buffer);
if (status != 0) {
ERROR("powerdns plugin: powerdns_get_data failed.");
return -1;
/**
* collectd - src/processes.c
* Copyright (C) 2005 Lyonel Vincent
- * Copyright (C) 2006-2010 Florian octo Forster
+ * Copyright (C) 2006-2017 Florian octo Forster
* Copyright (C) 2008 Oleg King
* Copyright (C) 2009 Sebastian Harl
* Copyright (C) 2009 Andrés J. Díaz
* Clément Stenac <clement.stenac at diwi.org>
* Cosmin Ioiart <cioiart at gmail.com>
* Pavel Rochnyack <pavel2000 at ngs.ru>
+ * Wilfried Goesgens <dothebart at citadel.org>
**/
#include "collectd.h"
#include "common.h"
#include "plugin.h"
+#if HAVE_LIBTASKSTATS
+#include "utils_complain.h"
+#include "utils_taskstats.h"
+#endif
+
/* Include header files for the mach system, if they exist.. */
#if HAVE_THREAD_INFO
#if HAVE_MACH_MACH_INIT_H
#include <kstat.h>
#endif
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+
#ifndef CMDLINE_BUFFER_SIZE
#if defined(ARG_MAX) && (ARG_MAX < 4096)
#define CMDLINE_BUFFER_SIZE ARG_MAX
unsigned long num_proc;
unsigned long num_lwp;
unsigned long num_fd;
+ unsigned long num_maps;
unsigned long vmem_size;
unsigned long vmem_rss;
unsigned long vmem_data;
derive_t cswitch_invol;
_Bool has_cswitch;
+#if HAVE_LIBTASKSTATS
+ ts_delay_t delay;
+#endif
+ _Bool has_delay;
+
_Bool has_fd;
+
+ _Bool has_maps;
} process_entry_t;
typedef struct procstat_entry_s {
derive_t cswitch_vol;
derive_t cswitch_invol;
+#if HAVE_LIBTASKSTATS
+ value_to_rate_state_t delay_cpu;
+ value_to_rate_state_t delay_blkio;
+ value_to_rate_state_t delay_swapin;
+ value_to_rate_state_t delay_freepages;
+#endif
+
struct procstat_entry_s *next;
} procstat_entry_t;
unsigned long num_proc;
unsigned long num_lwp;
unsigned long num_fd;
+ unsigned long num_maps;
unsigned long vmem_size;
unsigned long vmem_rss;
unsigned long vmem_data;
derive_t cswitch_vol;
derive_t cswitch_invol;
+ /* Linux Delay Accounting. Unit is ns/s. */
+ gauge_t delay_cpu;
+ gauge_t delay_blkio;
+ gauge_t delay_swapin;
+ gauge_t delay_freepages;
+
_Bool report_fd_num;
+ _Bool report_maps_num;
_Bool report_ctx_switch;
+ _Bool report_delay;
struct procstat *next;
struct procstat_entry_s *instances;
static _Bool want_init = 1;
static _Bool report_ctx_switch = 0;
static _Bool report_fd_num = 0;
+static _Bool report_maps_num = 0;
+static _Bool report_delay = 0;
#if HAVE_THREAD_INFO
static mach_port_t port_host_self;
int getargs(void *processBuffer, int bufferLen, char *argsBuffer, int argsLen);
#endif /* HAVE_PROCINFO_H */
+#if HAVE_LIBTASKSTATS
+static ts_t *taskstats_handle = NULL;
+#endif
+
/* put name of process from config to list_head_g tree
* list_head_g is a list of 'procstat_t' structs with
* processes names we want to watch */
new->cswitch_invol = -1;
new->report_fd_num = report_fd_num;
+ new->report_maps_num = report_maps_num;
new->report_ctx_switch = report_ctx_switch;
+ new->report_delay = report_delay;
#if HAVE_REGEX_H
if (regexp != NULL) {
*group_counter += curr_value;
}
+#if HAVE_LIBTASKSTATS
+static void ps_update_delay_one(gauge_t *out_rate_sum,
+ value_to_rate_state_t *state, uint64_t cnt,
+ cdtime_t t) {
+ gauge_t rate = NAN;
+ int status = value_to_rate(&rate, (value_t){.counter = (counter_t)cnt},
+ DS_TYPE_COUNTER, t, state);
+ if ((status != 0) || isnan(rate)) {
+ return;
+ }
+
+ if (isnan(*out_rate_sum)) {
+ *out_rate_sum = rate;
+ } else {
+ *out_rate_sum += rate;
+ }
+}
+
+static void ps_update_delay(procstat_t *out, procstat_entry_t *prev,
+ process_entry_t *curr) {
+ cdtime_t now = cdtime();
+
+ ps_update_delay_one(&out->delay_cpu, &prev->delay_cpu, curr->delay.cpu_ns,
+ now);
+ ps_update_delay_one(&out->delay_blkio, &prev->delay_blkio,
+ curr->delay.blkio_ns, now);
+ ps_update_delay_one(&out->delay_swapin, &prev->delay_swapin,
+ curr->delay.swapin_ns, now);
+ ps_update_delay_one(&out->delay_freepages, &prev->delay_freepages,
+ curr->delay.freepages_ns, now);
+}
+#endif
+
/* add process entry to 'instances' of process 'name' (or refresh it) */
static void ps_list_add(const char *name, const char *cmdline,
process_entry_t *entry) {
ps->num_proc += entry->num_proc;
ps->num_lwp += entry->num_lwp;
ps->num_fd += entry->num_fd;
+ ps->num_maps += entry->num_maps;
ps->vmem_size += entry->vmem_size;
ps->vmem_rss += entry->vmem_rss;
ps->vmem_data += entry->vmem_data;
ps_update_counter(&ps->io_diskw, &pse->io_diskw, entry->io_diskw);
}
- if ((entry->cswitch_vol != -1) && (entry->cswitch_vol != -1)) {
+ if ((entry->cswitch_vol != -1) && (entry->cswitch_invol != -1)) {
ps_update_counter(&ps->cswitch_vol, &pse->cswitch_vol,
entry->cswitch_vol);
ps_update_counter(&ps->cswitch_invol, &pse->cswitch_invol,
entry->cpu_user_counter);
ps_update_counter(&ps->cpu_system_counter, &pse->cpu_system_counter,
entry->cpu_system_counter);
+
+#if HAVE_LIBTASKSTATS
+ ps_update_delay(ps, pse, entry);
+#endif
}
}
ps->num_proc = 0;
ps->num_lwp = 0;
ps->num_fd = 0;
+ ps->num_maps = 0;
ps->vmem_size = 0;
ps->vmem_rss = 0;
ps->vmem_data = 0;
ps->vmem_code = 0;
ps->stack_size = 0;
+ ps->delay_cpu = NAN;
+ ps->delay_blkio = NAN;
+ ps->delay_swapin = NAN;
+ ps->delay_freepages = NAN;
+
pse_prev = NULL;
pse = ps->instances;
while (pse != NULL) {
cf_util_get_boolean(c, &ps->report_ctx_switch);
else if (strcasecmp(c->key, "CollectFileDescriptor") == 0)
cf_util_get_boolean(c, &ps->report_fd_num);
- else {
- ERROR("processes plugin: Option `%s' not allowed here.", c->key);
+ else if (strcasecmp(c->key, "CollectMemoryMaps") == 0)
+ cf_util_get_boolean(c, &ps->report_maps_num);
+ else if (strcasecmp(c->key, "CollectDelayAccounting") == 0) {
+#if HAVE_LIBTASKSTATS
+ cf_util_get_boolean(c, &ps->report_delay);
+#else
+ WARNING("processes plugin: The plugin has been compiled without support "
+ "for the \"CollectDelayAccounting\" option.");
+#endif
+ } else {
+ ERROR("processes plugin: Option \"%s\" not allowed here.", c->key);
}
} /* for (ci->children) */
} /* void ps_tune_instance */
#if KERNEL_LINUX || KERNEL_SOLARIS || KERNEL_FREEBSD
if (strlen(c->values[0].value.string) > max_procname_len) {
- WARNING("processes plugin: this platform has a %zu character limit "
+ WARNING("processes plugin: this platform has a %" PRIsz
+ " character limit "
"to process names. The `Process \"%s\"' option will "
"not work as expected.",
max_procname_len, c->values[0].value.string);
cf_util_get_boolean(c, &report_ctx_switch);
} else if (strcasecmp(c->key, "CollectFileDescriptor") == 0) {
cf_util_get_boolean(c, &report_fd_num);
+ } else if (strcasecmp(c->key, "CollectMemoryMaps") == 0) {
+ cf_util_get_boolean(c, &report_maps_num);
+ } else if (strcasecmp(c->key, "CollectDelayAccounting") == 0) {
+#if HAVE_LIBTASKSTATS
+ cf_util_get_boolean(c, &report_delay);
+#else
+ WARNING("processes plugin: The plugin has been compiled without support "
+ "for the \"CollectDelayAccounting\" option.");
+#endif
} else {
ERROR("processes plugin: The `%s' configuration option is not "
"understood and will be ignored.",
#elif KERNEL_LINUX
pagesize_g = sysconf(_SC_PAGESIZE);
DEBUG("pagesize_g = %li; CONFIG_HZ = %i;", pagesize_g, CONFIG_HZ);
+
+#if HAVE_LIBTASKSTATS
+ if (taskstats_handle == NULL) {
+ taskstats_handle = ts_create();
+ if (taskstats_handle == NULL) {
+ WARNING("processes plugin: Creating taskstats handle failed.");
+ }
+ }
+#endif
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKVM_GETPROCS && \
plugin_dispatch_values(&vl);
}
+ if (ps->num_maps > 0) {
+ sstrncpy(vl.type, "file_handles", sizeof(vl.type));
+ sstrncpy(vl.type_instance, "mapped", sizeof(vl.type_instance));
+ vl.values[0].gauge = ps->num_maps;
+ vl.values_len = 1;
+ plugin_dispatch_values(&vl);
+ }
+
if ((ps->cswitch_vol != -1) && (ps->cswitch_invol != -1)) {
sstrncpy(vl.type, "contextswitch", sizeof(vl.type));
sstrncpy(vl.type_instance, "voluntary", sizeof(vl.type_instance));
plugin_dispatch_values(&vl);
}
- DEBUG("name = %s; num_proc = %lu; num_lwp = %lu; num_fd = %lu; "
- "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
- "vmem_code = %lu; "
- "vmem_minflt_counter = %" PRIi64 "; vmem_majflt_counter = %" PRIi64 "; "
- "cpu_user_counter = %" PRIi64 "; cpu_system_counter = %" PRIi64 "; "
- "io_rchar = %" PRIi64 "; io_wchar = %" PRIi64 "; "
- "io_syscr = %" PRIi64 "; io_syscw = %" PRIi64 "; "
- "io_diskr = %" PRIi64 "; io_diskw = %" PRIi64 "; "
- "cswitch_vol = %" PRIi64 "; cswitch_invol = %" PRIi64 ";",
- ps->name, ps->num_proc, ps->num_lwp, ps->num_fd, ps->vmem_size,
- ps->vmem_rss, ps->vmem_data, ps->vmem_code, ps->vmem_minflt_counter,
- ps->vmem_majflt_counter, ps->cpu_user_counter, ps->cpu_system_counter,
- ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw, ps->io_diskr,
- ps->io_diskw, ps->cswitch_vol, ps->cswitch_invol);
+ /* The ps->delay_* metrics are in nanoseconds per second. Convert to seconds
+ * per second. */
+ gauge_t const delay_factor = 1000000000.0;
+
+ struct {
+ char *type_instance;
+ gauge_t rate_ns;
+ } delay_metrics[] = {
+ {"delay-cpu", ps->delay_cpu},
+ {"delay-blkio", ps->delay_blkio},
+ {"delay-swapin", ps->delay_swapin},
+ {"delay-freepages", ps->delay_freepages},
+ };
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(delay_metrics); i++) {
+ if (isnan(delay_metrics[i].rate_ns)) {
+ continue;
+ }
+ sstrncpy(vl.type, "delay_rate", sizeof(vl.type));
+ sstrncpy(vl.type_instance, delay_metrics[i].type_instance,
+ sizeof(vl.type_instance));
+ vl.values[0].gauge = delay_metrics[i].rate_ns * delay_factor;
+ vl.values_len = 1;
+ plugin_dispatch_values(&vl);
+ }
+
+ DEBUG(
+ "name = %s; num_proc = %lu; num_lwp = %lu; num_fd = %lu; num_maps = %lu; "
+ "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
+ "vmem_code = %lu; "
+ "vmem_minflt_counter = %" PRIi64 "; vmem_majflt_counter = %" PRIi64 "; "
+ "cpu_user_counter = %" PRIi64 "; cpu_system_counter = %" PRIi64 "; "
+ "io_rchar = %" PRIi64 "; io_wchar = %" PRIi64 "; "
+ "io_syscr = %" PRIi64 "; io_syscw = %" PRIi64 "; "
+ "io_diskr = %" PRIi64 "; io_diskw = %" PRIi64 "; "
+ "cswitch_vol = %" PRIi64 "; cswitch_invol = %" PRIi64 "; "
+ "delay_cpu = %g; delay_blkio = %g; "
+ "delay_swapin = %g; delay_freepages = %g;",
+ ps->name, ps->num_proc, ps->num_lwp, ps->num_fd, ps->num_maps,
+ ps->vmem_size, ps->vmem_rss, ps->vmem_data, ps->vmem_code,
+ ps->vmem_minflt_counter, ps->vmem_majflt_counter, ps->cpu_user_counter,
+ ps->cpu_system_counter, ps->io_rchar, ps->io_wchar, ps->io_syscr,
+ ps->io_syscw, ps->io_diskr, ps->io_diskw, ps->cswitch_vol,
+ ps->cswitch_invol, ps->delay_cpu, ps->delay_blkio, ps->delay_swapin,
+ ps->delay_freepages);
+
} /* void ps_submit_proc_list */
#if KERNEL_LINUX || KERNEL_SOLARIS
} /* while (fgets) */
if (fclose(fh)) {
- char errbuf[1024];
- WARNING("processes: fclose: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("processes: fclose: %s", STRERRNO);
}
}
closedir(dh);
} /* while (fgets) */
if (fclose(fh)) {
- char errbuf[1024];
- WARNING("processes: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("processes: fclose: %s", STRERRNO);
}
ps->vmem_data = data * 1024;
} /* while (fgets) */
if (fclose(fh)) {
- char errbuf[1024];
- WARNING("processes: fclose: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("processes: fclose: %s", STRERRNO);
}
return 0;
} /* int ps_read_io (...) */
+static int ps_count_maps(pid_t pid) {
+ FILE *fh;
+ char buffer[1024];
+ char filename[64];
+ int count = 0;
+
+ snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
+ if ((fh = fopen(filename, "r")) == NULL) {
+ DEBUG("ps_count_maps: Failed to open file `%s'", filename);
+ return -1;
+ }
+
+ while (fgets(buffer, sizeof(buffer), fh) != NULL) {
+ if (strchr(buffer, '\n')) {
+ count++;
+ }
+ } /* while (fgets) */
+
+ if (fclose(fh)) {
+ WARNING("processes: fclose: %s", STRERRNO);
+ }
+ return count;
+} /* int ps_count_maps (...) */
+
static int ps_count_fd(int pid) {
char dirname[64];
DIR *dh;
return (count >= 1) ? count : 1;
} /* int ps_count_fd (pid) */
+#if HAVE_LIBTASKSTATS
+static int ps_delay(process_entry_t *ps) {
+ if (taskstats_handle == NULL) {
+ return ENOTCONN;
+ }
+
+ int status = ts_delay_by_tgid(taskstats_handle, (uint32_t)ps->id, &ps->delay);
+ if (status == EPERM) {
+ static c_complain_t c;
+#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_ADMIN)
+ if (check_capability(CAP_NET_ADMIN) != 0) {
+ if (getuid() == 0) {
+ c_complain(
+ LOG_ERR, &c,
+ "processes plugin: Reading Delay Accounting metric failed: %s. "
+ "collectd is running as root, but missing the CAP_NET_ADMIN "
+ "capability. The most common cause for this is that the init "
+ "system is dropping capabilities.",
+ STRERROR(status));
+ } else {
+ c_complain(
+ LOG_ERR, &c,
+ "processes plugin: Reading Delay Accounting metric failed: %s. "
+ "collectd is not running as root and missing the CAP_NET_ADMIN "
+ "capability. Either run collectd as root or grant it the "
+ "CAP_NET_ADMIN capability using \"setcap cap_net_admin=ep " PREFIX
+ "/sbin/collectd\".",
+ STRERROR(status));
+ }
+ } else {
+ ERROR("processes plugin: ts_delay_by_tgid failed: %s. The CAP_NET_ADMIN "
+ "capability is available (I checked), so this error is utterly "
+ "unexpected.",
+ STRERROR(status));
+ }
+#else
+ c_complain(LOG_ERR, &c,
+ "processes plugin: Reading Delay Accounting metric failed: %s. "
+ "Reading Delay Accounting metrics requires root privileges.",
+ STRERROR(status));
+#endif
+ return status;
+ } else if (status != 0) {
+ ERROR("processes plugin: ts_delay_by_tgid failed: %s", STRERROR(status));
+ return status;
+ }
+
+ return 0;
+}
+#endif
+
static void ps_fill_details(const procstat_t *ps, process_entry_t *entry) {
if (entry->has_io == 0) {
ps_read_io(entry);
}
}
+ if (ps->report_maps_num) {
+ int num_maps;
+ if (entry->has_maps == 0 && (num_maps = ps_count_maps(entry->id)) > 0) {
+ entry->num_maps = num_maps;
+ }
+ entry->has_maps = 1;
+ }
+
if (ps->report_fd_num) {
int num_fd;
if (entry->has_fd == 0 && (num_fd = ps_count_fd(entry->id)) > 0) {
}
entry->has_fd = 1;
}
+
+#if HAVE_LIBTASKSTATS
+ if (ps->report_delay && !entry->has_delay) {
+ if (ps_delay(entry) == 0) {
+ entry->has_delay = 1;
+ }
+ }
+#endif
} /* void ps_fill_details (...) */
+/* ps_read_process reads process counters on Linux. */
static int ps_read_process(long pid, process_entry_t *ps, char *state) {
char filename[64];
char buffer[1024];
/* Either '(' or ')' is not found or they are in the wrong order.
* Anyway, something weird that shouldn't happen ever. */
if (name_start_pos >= name_end_pos) {
- ERROR("processes plugin: name_start_pos = %zu >= name_end_pos = %zu",
+ ERROR("processes plugin: name_start_pos = %" PRIsz
+ " >= name_end_pos = %" PRIsz,
name_start_pos, name_end_pos);
return -1;
}
errno = 0;
fd = open(file, O_RDONLY);
if (fd < 0) {
- char errbuf[4096];
/* ENOENT means the process exited while we were handling it.
* Don't complain about this, it only fills the logs. */
if (errno != ENOENT)
- WARNING("processes plugin: Failed to open `%s': %s.", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("processes plugin: Failed to open `%s': %s.", file, STRERRNO);
return NULL;
}
status = read(fd, (void *)buf_ptr, len);
if (status < 0) {
- char errbuf[1024];
if ((EAGAIN == errno) || (EINTR == errno))
continue;
WARNING("processes plugin: Failed to read from `%s': %s.", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
close(fd);
return NULL;
}
proc_stat = fopen("/proc/stat", "r");
if (proc_stat == NULL) {
- char errbuf[1024];
- ERROR("processes plugin: fopen (/proc/stat) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("processes plugin: fopen (/proc/stat) failed: %s", STRERRNO);
return -1;
}
if ((status < 0) || (((size_t)status) != sizeof(info))) {
ERROR("processes plugin: Unexpected return value "
"while reading \"%s\": "
- "Returned %zd but expected %zu.",
+ "Returned %zd but expected %" PRIsz ".",
path, status, buffer_size);
return NULL;
}
*/
ps->num_fd = 0;
+ /* Number of memory mappings */
+ ps->num_maps = 0;
+
/*
* Calculating input/ouput chars
* Formula used is total chars / total blocks => chars/block
return 0;
}
#endif /* HAVE_THREAD_INFO */
-/* ------- end of additional functions for KERNEL_LINUX/HAVE_THREAD_INFO -------
- */
+/* end of additional functions for KERNEL_LINUX/HAVE_THREAD_INFO */
/* do actual readings from kernel */
static int ps_read(void) {
/* File descriptor count not implemented */
pse.num_fd = 0;
+ /* Number of memory mappings */
+ pse.num_maps = 0;
+
pse.vmem_minflt_counter = task_events_info.cow_faults;
pse.vmem_majflt_counter = task_events_info.faults;
ps_list_reset();
if ((proc = opendir("/proc")) == NULL) {
- char errbuf[1024];
- ERROR("Cannot open `/proc': %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("Cannot open `/proc': %s", STRERRNO);
return -1;
}
/* file descriptor count not implemented */
pse.num_fd = 0;
+ /* Number of memory mappings */
+ pse.num_maps = 0;
+
/* context switch counters not implemented */
pse.cswitch_vol = -1;
pse.cswitch_invol = -1;
/* file descriptor count not implemented */
pse.num_fd = 0;
+ /* Number of memory mappings */
+ pse.num_maps = 0;
+
/* context switch counters not implemented */
pse.cswitch_vol = -1;
pse.cswitch_invol = -1;
pse.io_diskw = -1;
pse.num_fd = 0;
+ pse.num_maps = 0;
pse.cswitch_vol = -1;
pse.cswitch_invol = -1;
fh = fopen(path, "r");
if (fh == NULL) {
- ERROR("protocols plugin: fopen (%s) failed: %s.", path,
- sstrerror(errno, key_buffer, sizeof(key_buffer)));
+ ERROR("protocols plugin: fopen (%s) failed: %s.", path, STRERRNO);
return -1;
}
"The callback function will be called with no parameters except for\n"
" data if it was supplied.";
+static char CollectdError_doc[] =
+ "Basic exception for collectd Python scripts.\n"
+ "\n"
+ "Throwing this exception will not cause a stacktrace to be logged, \n"
+ "even if LogTraces is enabled in the config.";
+
static pthread_t main_thread;
static PyOS_sighandler_t python_sigint_handler;
static _Bool do_interactive = 0;
static PyThreadState *state;
-static PyObject *sys_path, *cpy_format_exception;
+static PyObject *sys_path, *cpy_format_exception, *CollectdError;
static cpy_callback_t *cpy_config_callbacks;
static cpy_callback_t *cpy_init_callbacks;
}
void cpy_log_exception(const char *context) {
- int l = 0;
+ int l = 0, collectd_error;
const char *typename = NULL, *message = NULL;
PyObject *type, *value, *traceback, *tn, *m, *list;
PyErr_NormalizeException(&type, &value, &traceback);
if (type == NULL)
return;
+ collectd_error = PyErr_GivenExceptionMatches(value, CollectdError);
tn = PyObject_GetAttrString(type, "__name__"); /* New reference. */
m = PyObject_Str(value); /* New reference. */
if (tn != NULL)
typename = "NamelessException";
if (message == NULL)
message = "N/A";
- Py_BEGIN_ALLOW_THREADS ERROR("Unhandled python exception in %s: %s: %s",
- context, typename, message);
- Py_END_ALLOW_THREADS Py_XDECREF(tn);
+ Py_BEGIN_ALLOW_THREADS;
+ if (collectd_error) {
+ WARNING("%s in %s: %s", typename, context, message);
+ } else {
+ ERROR("Unhandled python exception in %s: %s: %s", context, typename,
+ message);
+ }
+ Py_END_ALLOW_THREADS;
+ Py_XDECREF(tn);
Py_XDECREF(m);
- if (!cpy_format_exception || !traceback) {
+ if (!cpy_format_exception || !traceback || collectd_error) {
PyErr_Clear();
Py_DECREF(type);
Py_XDECREF(value);
if (cpy[strlen(cpy) - 1] == '\n')
cpy[strlen(cpy) - 1] = 0;
- Py_BEGIN_ALLOW_THREADS ERROR("%s", cpy);
- Py_END_ALLOW_THREADS
+ Py_BEGIN_ALLOW_THREADS;
+ ERROR("%s", cpy);
+ Py_END_ALLOW_THREADS;
- free(cpy);
+ free(cpy);
}
Py_XDECREF(list);
PyList_SetItem(
list, i, PyLong_FromUnsignedLongLong(value_list->values[i].absolute));
} else {
- Py_BEGIN_ALLOW_THREADS ERROR("cpy_write_callback: Unknown value type %d.",
- ds->ds[i].type);
- Py_END_ALLOW_THREADS Py_DECREF(list);
+ Py_BEGIN_ALLOW_THREADS;
+ ERROR("cpy_write_callback: Unknown value type %d.", ds->ds[i].type);
+ Py_END_ALLOW_THREADS;
+ Py_DECREF(list);
CPY_RETURN_FROM_THREADS 0;
}
if (PyErr_Occurred() != NULL) {
}
dict = PyDict_New(); /* New reference. */
if (value_list->meta) {
- char **table;
+ char **table = NULL;
meta_data_t *meta = value_list->meta;
int num = meta_data_toc(meta, &table);
} else if (type == MD_TYPE_SIGNED_INT) {
if (meta_data_get_signed_int(meta, table[i], &si))
continue;
- temp = PyObject_CallFunctionObjArgs((void *)&SignedType,
- PyLong_FromLongLong(si),
+ PyObject *sival = PyLong_FromLongLong(si); /* New reference */
+ temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival,
(void *)0); /* New reference. */
PyDict_SetItemString(dict, table[i], temp);
Py_XDECREF(temp);
+ Py_XDECREF(sival);
} else if (type == MD_TYPE_UNSIGNED_INT) {
if (meta_data_get_unsigned_int(meta, table[i], &ui))
continue;
- temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType,
- PyLong_FromUnsignedLongLong(ui),
+ PyObject *uval = PyLong_FromUnsignedLongLong(ui); /* New reference */
+ temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval,
(void *)0); /* New reference. */
PyDict_SetItemString(dict, table[i], temp);
Py_XDECREF(temp);
+ Py_XDECREF(uval);
} else if (type == MD_TYPE_DOUBLE) {
if (meta_data_get_double(meta, table[i], &d))
continue;
Notification *n;
CPY_LOCK_THREADS
+ PyObject *dict = PyDict_New(); /* New reference. */
+ for (notification_meta_t *meta = notification->meta; meta != NULL;
+ meta = meta->next) {
+ PyObject *temp = NULL;
+ if (meta->type == NM_TYPE_STRING) {
+ temp = cpy_string_to_unicode_or_bytes(
+ meta->nm_value.nm_string); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ } else if (meta->type == NM_TYPE_SIGNED_INT) {
+ PyObject *sival = PyLong_FromLongLong(meta->nm_value.nm_signed_int);
+ temp = PyObject_CallFunctionObjArgs((void *)&SignedType, sival,
+ (void *)0); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ Py_XDECREF(sival);
+ } else if (meta->type == NM_TYPE_UNSIGNED_INT) {
+ PyObject *uval =
+ PyLong_FromUnsignedLongLong(meta->nm_value.nm_unsigned_int);
+ temp = PyObject_CallFunctionObjArgs((void *)&UnsignedType, uval,
+ (void *)0); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ Py_XDECREF(uval);
+ } else if (meta->type == NM_TYPE_DOUBLE) {
+ temp = PyFloat_FromDouble(meta->nm_value.nm_double); /* New reference. */
+ PyDict_SetItemString(dict, meta->name, temp);
+ Py_XDECREF(temp);
+ } else if (meta->type == NM_TYPE_BOOLEAN) {
+ PyDict_SetItemString(dict, meta->name,
+ meta->nm_value.nm_boolean ? Py_True : Py_False);
+ }
+ }
notify = Notification_New(); /* New reference. */
n = (Notification *)notify;
sstrncpy(n->data.host, notification->host, sizeof(n->data.host));
n->data.time = CDTIME_T_TO_DOUBLE(notification->time);
sstrncpy(n->message, notification->message, sizeof(n->message));
n->severity = notification->severity;
+ Py_CLEAR(n->meta);
+ n->meta = dict; /* Steals a reference. */
ret = PyObject_CallFunctionObjArgs(c->callback, n, c->data,
(void *)0); /* New reference. */
Py_XDECREF(notify);
for (size_t i = 0; i < ds->ds_num; ++i) {
tuple = PyTuple_New(4);
PyTuple_SET_ITEM(tuple, 0, cpy_string_to_unicode_or_bytes(ds->ds[i].name));
- PyTuple_SET_ITEM(tuple, 1, cpy_string_to_unicode_or_bytes(
- DS_TYPE_TO_STRING(ds->ds[i].type)));
+ PyTuple_SET_ITEM(
+ tuple, 1,
+ cpy_string_to_unicode_or_bytes(DS_TYPE_TO_STRING(ds->ds[i].type)));
PyTuple_SET_ITEM(tuple, 2, float_or_none(ds->ds[i].min));
PyTuple_SET_ITEM(tuple, 3, float_or_none(ds->ds[i].max));
PyList_SET_ITEM(list, i, tuple);
if (PyArg_ParseTupleAndKeywords(args, kwds, "|etiet", kwlist, NULL, &plugin,
&timeout, NULL, &identifier) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_flush(plugin, timeout, identifier);
- Py_END_ALLOW_THREADS PyMem_Free(plugin);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_flush(plugin, timeout, identifier);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(plugin);
PyMem_Free(identifier);
Py_RETURN_NONE;
}
register_function(buf, handler,
&(user_data_t){
- .data = c, .free_func = cpy_destroy_user_data,
+ .data = c,
+ .free_func = cpy_destroy_user_data,
});
++cpy_num_callbacks;
/* group = */ "python", buf, cpy_read_callback,
DOUBLE_TO_CDTIME_T(interval),
&(user_data_t){
- .data = c, .free_func = cpy_destroy_user_data,
+ .data = c,
+ .free_func = cpy_destroy_user_data,
});
++cpy_num_callbacks;
return cpy_string_to_unicode_or_bytes(buf);
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_ERR, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_ERR, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_WARNING, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_WARNING, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_NOTICE, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_NOTICE, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_INFO, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_INFO, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
Py_RETURN_NONE;
}
char *text;
if (PyArg_ParseTuple(args, "et", NULL, &text) == 0)
return NULL;
- Py_BEGIN_ALLOW_THREADS plugin_log(LOG_DEBUG, "%s", text);
- Py_END_ALLOW_THREADS PyMem_Free(text);
+ Py_BEGIN_ALLOW_THREADS;
+ plugin_log(LOG_DEBUG, "%s", text);
+ Py_END_ALLOW_THREADS;
+ PyMem_Free(text);
#endif
Py_RETURN_NONE;
}
}
PyErr_Print();
- Py_BEGIN_ALLOW_THREADS cpy_unregister_list(&cpy_config_callbacks);
+ Py_BEGIN_ALLOW_THREADS;
+ cpy_unregister_list(&cpy_config_callbacks);
cpy_unregister_list(&cpy_init_callbacks);
cpy_unregister_list(&cpy_shutdown_callbacks);
cpy_shutdown_triggered = 1;
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS;
- if (!cpy_num_callbacks) {
+ if (!cpy_num_callbacks) {
Py_Finalize();
return 0;
}
values = PyTuple_New(ci->values_num); /* New reference. */
for (int i = 0; i < ci->values_num; ++i) {
if (ci->values[i].type == OCONFIG_TYPE_STRING) {
- PyTuple_SET_ITEM(values, i, cpy_string_to_unicode_or_bytes(
- ci->values[i].value.string));
+ PyTuple_SET_ITEM(
+ values, i,
+ cpy_string_to_unicode_or_bytes(ci->values[i].value.string));
} else if (ci->values[i].type == OCONFIG_TYPE_NUMBER) {
PyTuple_SET_ITEM(values, i,
PyFloat_FromDouble(ci->values[i].value.number));
static int cpy_init_python(void) {
PyOS_sighandler_t cur_sig;
- PyObject *sys;
+ PyObject *sys, *errordict;
PyObject *module;
#ifdef IS_PY3K
PyType_Ready(&SignedType);
UnsignedType.tp_base = &PyLong_Type;
PyType_Ready(&UnsignedType);
+ errordict = PyDict_New();
+ PyDict_SetItemString(
+ errordict, "__doc__",
+ cpy_string_to_unicode_or_bytes(CollectdError_doc)); /* New reference. */
+ CollectdError = PyErr_NewException("collectd.CollectdError", NULL, errordict);
sys = PyImport_ImportModule("sys"); /* New reference. */
if (sys == NULL) {
cpy_log_exception("python initialization");
(void *)&SignedType); /* Steals a reference. */
PyModule_AddObject(module, "Unsigned",
(void *)&UnsignedType); /* Steals a reference. */
+ Py_XINCREF(CollectdError);
+ PyModule_AddObject(module, "CollectdError",
+ CollectdError); /* Steals a reference. */
PyModule_AddIntConstant(module, "LOG_DEBUG", LOG_DEBUG);
PyModule_AddIntConstant(module, "LOG_INFO", LOG_INFO);
PyModule_AddIntConstant(module, "LOG_NOTICE", LOG_NOTICE);
#include "cpython.h"
+typedef struct {
+ int (*add_string)(void *, const char *, const char *);
+ int (*add_signed_int)(void *, const char *, int64_t);
+ int (*add_unsigned_int)(void *, const char *, uint64_t);
+ int (*add_double)(void *, const char *, double);
+ int (*add_boolean)(void *, const char *, _Bool);
+} cpy_build_meta_handler_t;
+
#define FreeAll() \
do { \
PyMem_Free(type); \
return 0;
}
-static meta_data_t *cpy_build_meta(PyObject *meta) {
+static int cpy_build_meta_generic(PyObject *meta,
+ cpy_build_meta_handler_t *meta_func,
+ void *m) {
int s;
- meta_data_t *m = NULL;
PyObject *l;
if ((meta == NULL) || (meta == Py_None))
- return NULL;
+ return -1;
l = PyDict_Items(meta); /* New reference. */
if (!l) {
cpy_log_exception("building meta data");
- return NULL;
+ return -1;
}
s = PyList_Size(l);
if (s <= 0) {
Py_XDECREF(l);
- return NULL;
+ return -1;
}
- m = meta_data_create();
for (int i = 0; i < s; ++i) {
const char *string, *keystring;
PyObject *key, *value, *item, *tmp;
value = PyTuple_GET_ITEM(item, 1);
Py_INCREF(value);
if (value == Py_True) {
- meta_data_add_boolean(m, keystring, 1);
+ meta_func->add_boolean(m, keystring, 1);
} else if (value == Py_False) {
- meta_data_add_boolean(m, keystring, 0);
+ meta_func->add_boolean(m, keystring, 0);
} else if (PyFloat_Check(value)) {
- meta_data_add_double(m, keystring, PyFloat_AsDouble(value));
+ meta_func->add_double(m, keystring, PyFloat_AsDouble(value));
} else if (PyObject_TypeCheck(value, &SignedType)) {
long long int lli;
lli = PyLong_AsLongLong(value);
if (!PyErr_Occurred() && (lli == (int64_t)lli))
- meta_data_add_signed_int(m, keystring, lli);
+ meta_func->add_signed_int(m, keystring, lli);
} else if (PyObject_TypeCheck(value, &UnsignedType)) {
long long unsigned llu;
llu = PyLong_AsUnsignedLongLong(value);
if (!PyErr_Occurred() && (llu == (uint64_t)llu))
- meta_data_add_unsigned_int(m, keystring, llu);
+ meta_func->add_unsigned_int(m, keystring, llu);
} else if (PyNumber_Check(value)) {
long long int lli;
long long unsigned llu;
tmp = PyNumber_Long(value);
lli = PyLong_AsLongLong(tmp);
if (!PyErr_Occurred() && (lli == (int64_t)lli)) {
- meta_data_add_signed_int(m, keystring, lli);
+ meta_func->add_signed_int(m, keystring, lli);
} else {
PyErr_Clear();
llu = PyLong_AsUnsignedLongLong(tmp);
if (!PyErr_Occurred() && (llu == (uint64_t)llu))
- meta_data_add_unsigned_int(m, keystring, llu);
+ meta_func->add_unsigned_int(m, keystring, llu);
}
Py_XDECREF(tmp);
} else {
string = cpy_unicode_or_bytes_to_string(&value);
if (string) {
- meta_data_add_string(m, keystring, string);
+ meta_func->add_string(m, keystring, string);
} else {
PyErr_Clear();
tmp = PyObject_Str(value);
string = cpy_unicode_or_bytes_to_string(&tmp);
if (string)
- meta_data_add_string(m, keystring, string);
+ meta_func->add_string(m, keystring, string);
Py_XDECREF(tmp);
}
}
Py_DECREF(key);
}
Py_XDECREF(l);
+ return 0;
+}
+
+#define CPY_BUILD_META_FUNC(meta_type, func, val_type) \
+ static int cpy_##func(void *meta, const char *key, val_type val) { \
+ return func((meta_type *)meta, key, val); \
+ }
+
+#define CPY_BUILD_META_HANDLER(func_prefix, meta_type) \
+ CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_string, const char *) \
+ CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_signed_int, int64_t) \
+ CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_unsigned_int, uint64_t) \
+ CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_double, double) \
+ CPY_BUILD_META_FUNC(meta_type, func_prefix##_add_boolean, _Bool) \
+ \
+ static cpy_build_meta_handler_t cpy_##func_prefix = { \
+ .add_string = cpy_##func_prefix##_add_string, \
+ .add_signed_int = cpy_##func_prefix##_add_signed_int, \
+ .add_unsigned_int = cpy_##func_prefix##_add_unsigned_int, \
+ .add_double = cpy_##func_prefix##_add_double, \
+ .add_boolean = cpy_##func_prefix##_add_boolean}
+
+CPY_BUILD_META_HANDLER(meta_data, meta_data_t);
+CPY_BUILD_META_HANDLER(plugin_notification_meta, notification_t);
+
+static meta_data_t *cpy_build_meta(PyObject *meta) {
+ meta_data_t *m = meta_data_create();
+ if (cpy_build_meta_generic(meta, &cpy_meta_data, (void *)m) < 0) {
+ meta_data_destroy(m);
+ return NULL;
+ }
return m;
}
+static void cpy_build_notification_meta(notification_t *n, PyObject *meta) {
+ cpy_build_meta_generic(meta, &cpy_plugin_notification_meta, (void *)n);
+}
+
static PyObject *Values_dispatch(Values *self, PyObject *args, PyObject *kwds) {
int ret;
const data_set_t *ds;
}
size = (size_t)PySequence_Length(values);
if (size != ds->ds_num) {
- PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
+ PyErr_Format(PyExc_RuntimeError,
+ "type %s needs %" PRIsz " values, got %" PRIsz,
value_list.type, ds->ds_num, size);
return NULL;
}
}
size = (size_t)PySequence_Length(values);
if (size != ds->ds_num) {
- PyErr_Format(PyExc_RuntimeError, "type %s needs %zu values, got %zu",
+ PyErr_Format(PyExc_RuntimeError,
+ "type %s needs %" PRIsz " values, got %" PRIsz,
value_list.type, ds->ds_num, size);
return NULL;
}
Values_new /* tp_new */
};
+static char notification_meta_doc[] =
+ "These are the meta data for the Notification object.\n"
+ "It has to be a dictionary of numbers, strings or bools. All keys must be\n"
+ "strings. int and long objects will be dispatched as signed integers "
+ "unless\n"
+ "they are between 2**63 and 2**64-1, which will result in an unsigned "
+ "integer.\n"
+ "One of these storage classes can be forced by using the classes\n"
+ "collectd.Signed and collectd.Unsigned. A meta object received by a\n"
+ "notification callback will always contain Signed or Unsigned objects.";
+
static char severity_doc[] =
"The severity of this notification. Assign or compare to\n"
"NOTIF_FAILURE, NOTIF_WARNING or NOTIF_OKAY.";
int severity = 0;
double time = 0;
char *message = NULL;
+ PyObject *meta = NULL;
char *type = NULL, *plugin_instance = NULL, *type_instance = NULL,
*plugin = NULL, *host = NULL;
- static char *kwlist[] = {"type", "message", "plugin_instance",
- "type_instance", "plugin", "host",
- "time", "severity", NULL};
+ static char *kwlist[] = {
+ "type", "message", "plugin_instance", "type_instance", "plugin",
+ "host", "time", "severity", "meta", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, NULL,
- &type, NULL, &message, NULL,
- &plugin_instance, NULL, &type_instance, NULL,
- &plugin, NULL, &host, &time, &severity))
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "|etetetetetetdiO", kwlist, NULL, &type, NULL, &message,
+ NULL, &plugin_instance, NULL, &type_instance, NULL, &plugin, NULL,
+ &host, &time, &severity, &meta))
return -1;
if (type && plugin_get_ds(type) == NULL) {
FreeAll();
PyMem_Free(message);
+
+ if (meta == NULL) {
+ meta = PyDict_New();
+ PyErr_Clear();
+ } else {
+ Py_INCREF(meta);
+ }
+
+ PyObject *tmp = self->meta;
+ self->meta = meta;
+ Py_XDECREF(tmp);
+
return 0;
}
const data_set_t *ds;
notification_t notification;
double t = self->data.time;
+ PyObject *meta = self->meta;
int severity = self->severity;
char *host = NULL, *plugin = NULL, *plugin_instance = NULL, *type = NULL,
*type_instance = NULL;
char *message = NULL;
- static char *kwlist[] = {"type", "message", "plugin_instance",
- "type_instance", "plugin", "host",
- "time", "severity", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdi", kwlist, NULL,
+ static char *kwlist[] = {
+ "type", "message", "plugin_instance", "type_instance", "plugin",
+ "host", "time", "severity", "meta", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|etetetetetetdiO", kwlist, NULL,
&type, NULL, &message, NULL,
&plugin_instance, NULL, &type_instance, NULL,
- &plugin, NULL, &host, &t, &severity))
+ &plugin, NULL, &host, &t, &severity, &meta))
return NULL;
notification.time = DOUBLE_TO_CDTIME_T(t);
PyErr_Format(PyExc_TypeError, "Dataset %s not found", notification.type);
return NULL;
}
+ if (meta != NULL && meta != Py_None && !PyDict_Check(meta)) {
+ PyErr_Format(PyExc_TypeError, "meta must be a dict");
+ return NULL;
+ }
+ cpy_build_notification_meta(¬ification, meta);
if (notification.time == 0)
notification.time = cdtime();
sstrncpy(notification.plugin, "python", sizeof(notification.plugin));
Py_BEGIN_ALLOW_THREADS;
ret = plugin_dispatch_notification(¬ification);
+ if (notification.meta)
+ plugin_notification_meta_free(notification.meta);
Py_END_ALLOW_THREADS;
if (ret != 0) {
PyErr_SetString(PyExc_RuntimeError,
if (self == NULL)
return NULL;
+ self->meta = PyDict_New();
self->message[0] = 0;
self->severity = 0;
return (PyObject *)self;
static PyObject *Notification_repr(PyObject *s) {
PyObject *ret, *tmp;
- static PyObject *l_severity = NULL, *l_message = NULL, *l_closing = NULL;
+ static PyObject *l_severity = NULL, *l_message = NULL, *l_meta = NULL,
+ *l_closing = NULL;
Notification *self = (Notification *)s;
if (l_severity == NULL)
l_severity = cpy_string_to_unicode_or_bytes(",severity=");
if (l_message == NULL)
l_message = cpy_string_to_unicode_or_bytes(",message=");
+ if (l_meta == NULL)
+ l_meta = cpy_string_to_unicode_or_bytes(",meta=");
if (l_closing == NULL)
l_closing = cpy_string_to_unicode_or_bytes(")");
- if (l_severity == NULL || l_message == NULL || l_closing == NULL)
+ if (l_severity == NULL || l_message == NULL || l_meta == NULL ||
+ l_closing == NULL)
return NULL;
ret = cpy_common_repr(s);
CPY_SUBSTITUTE(PyObject_Repr, tmp, tmp);
CPY_STRCAT_AND_DEL(&ret, tmp);
}
+ if (self->meta &&
+ (!PyDict_Check(self->meta) || PyDict_Size(self->meta) > 0)) {
+ CPY_STRCAT(&ret, l_meta);
+ tmp = PyObject_Repr(self->meta);
+ CPY_STRCAT_AND_DEL(&ret, tmp);
+ }
CPY_STRCAT(&ret, l_closing);
return ret;
}
+static int Notification_traverse(PyObject *self, visitproc visit, void *arg) {
+ Notification *n = (Notification *)self;
+ Py_VISIT(n->meta);
+ return 0;
+}
+
+static int Notification_clear(PyObject *self) {
+ Notification *n = (Notification *)self;
+ Py_CLEAR(n->meta);
+ return 0;
+}
+
+static void Notification_dealloc(PyObject *self) {
+ Notification_clear(self);
+ self->ob_type->tp_free(self);
+}
+
static PyMethodDef Notification_methods[] = {
{"dispatch", (PyCFunction)Notification_dispatch,
METH_VARARGS | METH_KEYWORDS, dispatch_doc},
static PyMemberDef Notification_members[] = {
{"severity", T_INT, offsetof(Notification, severity), 0, severity_doc},
+ {"meta", T_OBJECT_EX, offsetof(Notification, meta), 0,
+ notification_meta_doc},
{NULL}};
static PyGetSetDef Notification_getseters[] = {
{NULL}};
PyTypeObject NotificationType = {
- CPY_INIT_TYPE "collectd.Notification", /* tp_name */
- sizeof(Notification), /* tp_basicsize */
- 0, /* Will be filled in later */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- Notification_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- Notification_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- Notification_methods, /* tp_methods */
- Notification_members, /* tp_members */
- Notification_getseters, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- Notification_init, /* tp_init */
- 0, /* tp_alloc */
- Notification_new /* tp_new */
+ CPY_INIT_TYPE "collectd.Notification", /* tp_name */
+ sizeof(Notification), /* tp_basicsize */
+ 0, /* Will be filled in later */
+ Notification_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ Notification_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
+ Notification_doc, /* tp_doc */
+ Notification_traverse, /* tp_traverse */
+ Notification_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Notification_methods, /* tp_methods */
+ Notification_members, /* tp_members */
+ Notification_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ Notification_init, /* tp_init */
+ 0, /* tp_alloc */
+ Notification_new /* tp_new */
};
static char Signed_doc[] =
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Signed_doc /* tp_doc */
};
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
Unsigned_doc /* tp_doc */
};
rd->connection =
ros_connect(rd->node, rd->service, rd->username, rd->password);
if (rd->connection == NULL) {
- char errbuf[128];
- ERROR("routeros plugin: ros_connect failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("routeros plugin: ros_connect failed: %s", STRERRNO);
return -1;
}
}
status = ros_interface(rd->connection, handle_interface,
/* user data = */ rd);
if (status != 0) {
- char errbuf[128];
- ERROR("routeros plugin: ros_interface failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("routeros plugin: ros_interface failed: %s", STRERROR(status));
ros_disconnect(rd->connection);
rd->connection = NULL;
return -1;
status = ros_registration_table(rd->connection, handle_regtable,
/* user data = */ rd);
if (status != 0) {
- char errbuf[128];
ERROR("routeros plugin: ros_registration_table failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ STRERROR(status));
ros_disconnect(rd->connection);
rd->connection = NULL;
return -1;
status = ros_system_resource(rd->connection, handle_system_resource,
/* user data = */ rd);
if (status != 0) {
- char errbuf[128];
ERROR("routeros plugin: ros_system_resource failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ STRERROR(status));
ros_disconnect(rd->connection);
rd->connection = NULL;
return -1;
}
}
- snprintf(read_name, sizeof(read_name), "routeros/%s", router_data->node);
- if (status == 0)
- status = plugin_register_complex_read(
- /* group = */ NULL, read_name, cr_read, /* interval = */ 0,
- &(user_data_t){
- .data = router_data, .free_func = (void *)cr_free_data,
- });
-
- if (status != 0)
+ if (status != 0) {
cr_free_data(router_data);
+ return status;
+ }
- return status;
+ snprintf(read_name, sizeof(read_name), "routeros/%s", router_data->node);
+ return plugin_register_complex_read(
+ /* group = */ NULL, read_name, cr_read, /* interval = */ 0,
+ &(user_data_t){
+ .data = router_data, .free_func = (void *)cr_free_data,
+ });
} /* }}} int cr_config_router */
static int cr_config(oconfig_item_t *ci) {
return -1;
if (ds->ds[i].type == DS_TYPE_COUNTER) {
- status = snprintf(buffer + offset, buffer_len - offset, ":%llu",
- vl->values[i].counter);
+ status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
+ (uint64_t)vl->values[i].counter);
} else if (ds->ds[i].type == DS_TYPE_GAUGE) {
status = snprintf(buffer + offset, buffer_len - offset, ":%f",
vl->values[i].gauge);
status = stat(filename, &statbuf);
if (status != 0) {
if (errno != ENOENT) {
- char errbuf[1024];
- ERROR("rrdcached plugin: stat (%s) failed: %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("rrdcached plugin: stat (%s) failed: %s", filename, STRERRNO);
return -1;
}
/*
* Private types
*/
-struct rrd_cache_s {
+typedef struct rrd_cache_s {
int values_num;
char **values;
cdtime_t first_value;
cdtime_t last_value;
int64_t random_variation;
enum { FLAG_NONE = 0x00, FLAG_QUEUED = 0x01, FLAG_FLUSHQ = 0x02 } flags;
-};
-typedef struct rrd_cache_s rrd_cache_t;
+} rrd_cache_t;
enum rrd_queue_dir_e { QUEUE_INSERT_FRONT, QUEUE_INSERT_BACK };
typedef enum rrd_queue_dir_e rrd_queue_dir_t;
#if HAVE_THREADSAFE_LIBRRD
static int srrd_update(char *filename, char *template, int argc,
const char **argv) {
- int status;
-
optind = 0; /* bug in librrd? */
rrd_clear_error();
- status = rrd_update_r(filename, template, argc, (void *)argv);
-
+ int status = rrd_update_r(filename, template, argc, (void *)argv);
if (status != 0) {
WARNING("rrdtool plugin: rrd_update_r (%s) failed: %s", filename,
rrd_get_error());
return -1;
if (ds->ds[i].type == DS_TYPE_COUNTER)
- status = snprintf(buffer + offset, buffer_len - offset, ":%llu",
- vl->values[i].counter);
+ status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
+ (uint64_t)vl->values[i].counter);
else if (ds->ds[i].type == DS_TYPE_GAUGE)
status = snprintf(buffer + offset, buffer_len - offset, ":" GAUGE_FORMAT,
vl->values[i].gauge);
vl->values[0].gauge);
break;
case DS_TYPE_COUNTER:
- status = snprintf(buffer, buffer_len, "%u:%llu", (unsigned)tt,
- vl->values[0].counter);
+ status = snprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt,
+ (uint64_t)vl->values[0].counter);
break;
case DS_TYPE_ABSOLUTE:
status = snprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt,
{
char **tmp = realloc(keys, (keys_num + 1) * sizeof(char *));
if (tmp == NULL) {
- char errbuf[1024];
- ERROR("rrdtool plugin: "
- "realloc failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("rrdtool plugin: realloc failed: %s", STRERRNO);
c_avl_iterator_destroy(iter);
sfree(keys);
return;
return -1;
}
- c_avl_get(cache, filename, (void *)&rc);
-
- if (rc == NULL) {
+ int status = c_avl_get(cache, filename, (void *)&rc);
+ if ((status != 0) || (rc == NULL)) {
rc = malloc(sizeof(*rc));
if (rc == NULL) {
pthread_mutex_unlock(&cache_lock);
values_new =
realloc((void *)rc->values, (rc->values_num + 1) * sizeof(char *));
if (values_new == NULL) {
- char errbuf[1024];
void *cache_key = NULL;
- sstrerror(errno, errbuf, sizeof(errbuf));
-
c_avl_remove(cache, filename, &cache_key, NULL);
pthread_mutex_unlock(&cache_lock);
- ERROR("rrdtool plugin: realloc failed: %s", errbuf);
+ ERROR("rrdtool plugin: realloc failed: %s", STRERRNO);
sfree(cache_key);
sfree(rc->values);
void *cache_key = strdup(filename);
if (cache_key == NULL) {
- char errbuf[1024];
- sstrerror(errno, errbuf, sizeof(errbuf));
-
pthread_mutex_unlock(&cache_lock);
- ERROR("rrdtool plugin: strdup failed: %s", errbuf);
+ ERROR("rrdtool plugin: strdup failed: %s", STRERRNO);
sfree(rc->values[0]);
sfree(rc->values);
static int rrd_write(const data_set_t *ds, const value_list_t *vl,
user_data_t __attribute__((unused)) * user_data) {
- struct stat statbuf;
- char filename[512];
- char values[512];
- int status;
if (do_shutdown)
return 0;
return -1;
}
+ char filename[PATH_MAX];
if (value_list_to_filename(filename, sizeof(filename), vl) != 0)
return -1;
+ char values[32 * (ds->ds_num + 1)];
if (value_list_to_string(values, sizeof(values), ds, vl) != 0)
return -1;
+ struct stat statbuf = {0};
if (stat(filename, &statbuf) == -1) {
if (errno == ENOENT) {
- status = cu_rrd_create_file(filename, ds, vl, &rrdcreate_config);
- if (status != 0)
+ if (cu_rrd_create_file(filename, ds, vl, &rrdcreate_config) != 0) {
return -1;
- else if (rrdcreate_config.async)
+ } else if (rrdcreate_config.async) {
return 0;
+ }
} else {
- char errbuf[1024];
- ERROR("stat(%s) failed: %s", filename,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("rrdtool plugin: stat(%s) failed: %s", filename, STRERRNO);
return -1;
}
} else if (!S_ISREG(statbuf.st_mode)) {
- ERROR("stat(%s): Not a regular file!", filename);
+ ERROR("rrdtool plugin: stat(%s): Not a regular file!", filename);
return -1;
}
- status = rrd_cache_insert(filename, values, vl->time);
-
- return status;
+ return rrd_cache_insert(filename, values, vl->time);
} /* int rrd_write */
static int rrd_flush(cdtime_t timeout, const char *identifier,
static int rrd_init(void) {
static int init_once = 0;
- int status;
if (init_once != 0)
return 0;
random_timeout = 0;
cache_flush_timeout = 0;
} else if (cache_flush_timeout < cache_timeout) {
- INFO("rrdtool plugin: \"CacheFlush %.3f\" is less than \"CacheTimeout %.3f\". "
- "Ajusting \"CacheFlush\" to %.3f seconds.",
+ INFO("rrdtool plugin: \"CacheFlush %.3f\" is less than \"CacheTimeout "
+ "%.3f\". Adjusting \"CacheFlush\" to %.3f seconds.",
CDTIME_T_TO_DOUBLE(cache_flush_timeout),
CDTIME_T_TO_DOUBLE(cache_timeout),
CDTIME_T_TO_DOUBLE(cache_timeout * 10));
pthread_mutex_unlock(&cache_lock);
- status =
+ int status =
plugin_thread_create(&queue_thread, /* attr = */ NULL, rrd_queue_thread,
/* args = */ NULL, "rrdtool queue");
if (status != 0) {
if (conffile != NULL) {
fh = fopen(conffile, "r");
if (fh == NULL) {
- char errbuf[1024];
- ERROR("sensors plugin: fopen(%s) failed: %s", conffile,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("sensors plugin: fopen(%s) failed: %s", conffile, STRERRNO);
return -1;
}
}
/* there are a variety of names for the serial device */
if ((fh = fopen("/proc/tty/driver/serial", "r")) == NULL &&
(fh = fopen("/proc/tty/driver/ttyS", "r")) == NULL) {
- char errbuf[1024];
- WARNING("serial: fopen: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("serial: fopen: %s", STRERRNO);
return -1;
}
status = plugin_thread_create(&sr_thread, NULL, sigrok_read_thread, NULL,
"sigrok read");
if (status != 0) {
- char errbuf[1024];
- ERROR("sigrok plugin: Failed to create thread: %s.",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("sigrok plugin: Failed to create thread: %s.", STRERRNO);
return -1;
}
sr_thread_running = TRUE;
struct data_definition_s *next;
char **ignores;
size_t ignores_len;
- int invert_match;
+ _Bool invert_match;
};
typedef struct data_definition_s data_definition_t;
char *name;
char *address;
int version;
+ cdtime_t timeout;
+ int retries;
/* snmpv1/2 options */
char *community;
return 0;
} /* int csnmp_config_add_data_blacklist */
-static int csnmp_config_add_data_blacklist_match_inverted(data_definition_t *dd,
- oconfig_item_t *ci) {
- if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) {
- WARNING("snmp plugin: `InvertMatch' needs exactly one boolean argument.");
- return -1;
- }
-
- dd->invert_match = ci->values[0].value.boolean ? 1 : 0;
-
- return 0;
-} /* int csnmp_config_add_data_blacklist_match_inverted */
-
static int csnmp_config_add_data(oconfig_item_t *ci) {
- data_definition_t *dd;
- int status = 0;
-
- dd = calloc(1, sizeof(*dd));
+ data_definition_t *dd = calloc(1, sizeof(*dd));
if (dd == NULL)
return -1;
- status = cf_util_get_string(ci, &dd->name);
+ int status = cf_util_get_string(ci, &dd->name);
if (status != 0) {
- free(dd);
+ sfree(dd);
return -1;
}
else if (strcasecmp("Ignore", option->key) == 0)
status = csnmp_config_add_data_blacklist(dd, option);
else if (strcasecmp("InvertMatch", option->key) == 0)
- status = csnmp_config_add_data_blacklist_match_inverted(dd, option);
+ status = cf_util_get_boolean(option, &dd->invert_match);
else {
WARNING("snmp plugin: Option `%s' not allowed here.", option->key);
status = -1;
}
DEBUG("snmp plugin: dd = { name = %s, type = %s, is_table = %s, values_len = "
- "%zu }",
+ "%" PRIsz " }",
dd->name, dd->type, (dd->is_table != 0) ? "true" : "false",
dd->values_len);
hd->sess_handle = NULL;
hd->interval = 0;
+ /* These mean that we have not set a timeout or retry value */
+ hd->timeout = 0;
+ hd->retries = -1;
+
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *option = ci->children + i;
status = 0;
status = cf_util_get_string(option, &hd->community);
else if (strcasecmp("Version", option->key) == 0)
status = csnmp_config_add_host_version(hd, option);
+ else if (strcasecmp("Timeout", option->key) == 0)
+ cf_util_get_cdtime(option, &hd->timeout);
+ else if (strcasecmp("Retries", option->key) == 0)
+ cf_util_get_int(option, &hd->retries);
else if (strcasecmp("Collect", option->key) == 0)
csnmp_config_add_host_collect(hd, option);
else if (strcasecmp("Interval", option->key) == 0)
});
if (status != 0) {
ERROR("snmp plugin: Registering complex read function failed.");
- csnmp_host_definition_destroy(hd);
return -1;
}
sess.community_len = strlen(host->community);
}
+ /* Set timeout & retries, if they have been changed from the default */
+ if (host->timeout != 0) {
+ /* net-snmp expects microseconds */
+ sess.timeout = CDTIME_T_TO_US(host->timeout);
+ }
+ if (host->retries >= 0) {
+ sess.retries = host->retries;
+ }
+
/* snmp_sess_open will copy the `struct snmp_session *'. */
host->sess_handle = snmp_sess_open(&sess);
struct variable_list *vb;
oid_t vb_name;
int status;
- uint32_t is_matched;
/* Set vb on the last variable */
for (vb = res->variables; (vb != NULL) && (vb->next_variable != NULL);
char *ptr;
csnmp_strvbcopy(il->instance, vb, sizeof(il->instance));
- is_matched = 0;
+ _Bool is_matched = 0;
for (uint32_t i = 0; i < dd->ignores_len; i++) {
status = fnmatch(dd->ignores[i], il->instance, 0);
if (status == 0) {
- if (dd->invert_match == 0) {
+ if (!dd->invert_match) {
sfree(il);
return 0;
} else {
}
}
}
- if (dd->invert_match != 0 && is_matched == 0) {
+ if (dd->invert_match && !is_matched) {
sfree(il);
return 0;
}
value_t val = csnmp_value_list_to_value(
vb, DS_TYPE_COUNTER,
/* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
- snprintf(il->instance, sizeof(il->instance), "%llu", val.counter);
+ snprintf(il->instance, sizeof(il->instance), "%" PRIu64,
+ (uint64_t)val.counter);
}
/* TODO: Debugging output */
}
if (ds->ds_num != data->values_len) {
- ERROR("snmp plugin: DataSet `%s' requires %zu values, but config talks "
- "about %zu",
+ ERROR("snmp plugin: DataSet `%s' requires %" PRIsz
+ " values, but config talks "
+ "about %" PRIsz,
data->type, ds->ds_num, data->values_len);
return -1;
}
status = 0;
while (status == 0) {
- int oid_list_todo_num;
-
req = snmp_pdu_create(SNMP_MSG_GETNEXT);
if (req == NULL) {
ERROR("snmp plugin: snmp_pdu_create failed.");
break;
}
- oid_list_todo_num = 0;
+ size_t oid_list_todo_num = 0;
+ size_t var_idx[oid_list_len];
+ memset(var_idx, 0, sizeof(var_idx));
+
for (i = 0; i < oid_list_len; i++) {
/* Do not rerequest already finished OIDs */
if (!oid_list_todo[i])
continue;
- oid_list_todo_num++;
snmp_add_null_var(req, oid_list[i].oid, oid_list[i].oid_len);
+ var_idx[oid_list_todo_num] = i;
+ oid_list_todo_num++;
}
if (oid_list_todo_num == 0) {
/* The request is still empty - so we are finished */
DEBUG("snmp plugin: all variables have left their subtree");
+ snmp_free_pdu(req);
status = 0;
break;
}
res = NULL;
status = snmp_sess_synch_response(host->sess_handle, req, &res);
+
+ /* snmp_sess_synch_response always frees our req PDU */
+ req = NULL;
+
if ((status != STAT_SUCCESS) || (res == NULL)) {
char *errstr = NULL;
snmp_free_pdu(res);
res = NULL;
- /* snmp_synch_response already freed our PDU */
- req = NULL;
sfree(errstr);
csnmp_host_close_session(host);
break;
}
+ if (res->errstat != SNMP_ERR_NOERROR) {
+ if (res->errindex != 0) {
+ /* Find the OID which caused error */
+ for (i = 1, vb = res->variables; vb != NULL && i != res->errindex;
+ vb = vb->next_variable, i++)
+ /* do nothing */;
+ }
+
+ if ((res->errindex == 0) || (vb == NULL)) {
+ ERROR("snmp plugin: host %s; data %s: response error: %s (%li) ",
+ host->name, data->name, snmp_errstring(res->errstat),
+ res->errstat);
+ status = -1;
+ break;
+ }
+
+ char oid_buffer[1024] = {0};
+ snprint_objid(oid_buffer, sizeof(oid_buffer) - 1, vb->name,
+ vb->name_length);
+ NOTICE("snmp plugin: host %s; data %s: OID `%s` failed: %s", host->name,
+ data->name, oid_buffer, snmp_errstring(res->errstat));
+
+ /* Get value index from todo list and skip OID found */
+ assert(res->errindex <= oid_list_todo_num);
+ i = var_idx[res->errindex - 1];
+ assert(i < oid_list_len);
+ oid_list_todo[i] = 0;
+
+ snmp_free_pdu(res);
+ res = NULL;
+ continue;
+ }
+
for (vb = res->variables, i = 0; (vb != NULL);
vb = vb->next_variable, i++) {
/* Calculate value index from todo list */
- while ((i < oid_list_len) && !oid_list_todo[i])
+ while ((i < oid_list_len) && !oid_list_todo[i]) {
i++;
+ }
+ if (i >= oid_list_len) {
+ break;
+ }
/* An instance is configured and the res variable we process is the
* instance value (last index) */
* suffix is increasing. This also checks if we left the subtree */
ret = csnmp_oid_suffix(&suffix, &vb_name, data->values + i);
if (ret != 0) {
- DEBUG("snmp plugin: host = %s; data = %s; i = %zu; "
+ DEBUG("snmp plugin: host = %s; data = %s; i = %" PRIsz "; "
"Value probably left its subtree.",
host->name, data->name, i);
oid_list_todo[i] = 0;
* table matching algorithm will get confused. */
if ((value_list_tail[i] != NULL) &&
(csnmp_oid_compare(&suffix, &value_list_tail[i]->suffix) <= 0)) {
- DEBUG("snmp plugin: host = %s; data = %s; i = %zu; "
+ DEBUG("snmp plugin: host = %s; data = %s; i = %" PRIsz "; "
"Suffix is not increasing.",
host->name, data->name, i);
oid_list_todo[i] = 0;
snmp_free_pdu(res);
res = NULL;
- if (req != NULL)
- snmp_free_pdu(req);
- req = NULL;
-
if (status == 0)
csnmp_dispatch_table(host, data, instance_list_head, value_list_head);
}
if (ds->ds_num != data->values_len) {
- ERROR("snmp plugin: DataSet `%s' requires %zu values, but config talks "
- "about %zu",
+ ERROR("snmp plugin: DataSet `%s' requires %" PRIsz
+ " values, but config talks "
+ "about %" PRIsz,
data->type, ds->ds_num, data->values_len);
return -1;
}
DEBUG(PLUGIN_NAME ": TypeInstance: %s", dd->type_instance);
for (size_t i = 0; i < dd->oids_len; i++) {
snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &dd->oids[i]);
- DEBUG(PLUGIN_NAME ": OID[%zu]: %s", i, oid_str);
+ DEBUG(PLUGIN_NAME ": OID[%" PRIsz "]: %s", i, oid_str);
}
DEBUG(PLUGIN_NAME ": Scale: %g", dd->scale);
DEBUG(PLUGIN_NAME ": Shift: %g", dd->shift);
DEBUG(PLUGIN_NAME ": TypeInstance: %s", dd->type_instance);
for (size_t i = 0; i < dd->oids_len; i++) {
snmp_agent_oid_to_string(oid_str, sizeof(oid_str), &dd->oids[i]);
- DEBUG(PLUGIN_NAME ": OID[%zu]: %s", i, oid_str);
+ DEBUG(PLUGIN_NAME ": OID[%" PRIsz "]: %s", i, oid_str);
}
DEBUG(PLUGIN_NAME ": Scale: %g", dd->scale);
DEBUG(PLUGIN_NAME ": Shift: %g", dd->shift);
}
}
- llentry_t *entry = llentry_create(td->name, td);
- if (entry == NULL) {
- snmp_agent_free_table(&td);
- return -ENOMEM;
- }
-
td->instance_index =
c_avl_create((int (*)(const void *, const void *))strcmp);
if (td->instance_index == NULL) {
return -ENOMEM;
}
+ llentry_t *entry = llentry_create(td->name, td);
+ if (entry == NULL) {
+ snmp_agent_free_table(&td);
+ return -ENOMEM;
+ }
llist_append(g_agent->tables, entry);
return 0;
status = recv(fd, buffer, sizeof(buffer), /* flags = */ MSG_DONTWAIT);
if (status < 0) {
- char errbuf[1024];
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
return;
- ERROR("statsd plugin: recv(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("statsd plugin: recv(2) failed: %s", STRERRNO);
return;
}
fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (fd < 0) {
- char errbuf[1024];
- ERROR("statsd plugin: socket(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("statsd plugin: socket(2) failed: %s", STRERRNO);
continue;
}
status = bind(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0) {
- char errbuf[1024];
- ERROR("statsd plugin: bind(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("statsd plugin: bind(2) failed: %s", STRERRNO);
close(fd);
continue;
}
while (!network_thread_shutdown) {
status = poll(fds, (nfds_t)fds_num, /* timeout = */ -1);
if (status < 0) {
- char errbuf[1024];
if ((errno == EINTR) || (errno == EAGAIN))
continue;
- ERROR("statsd plugin: poll(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("statsd plugin: poll(2) failed: %s", STRERRNO);
break;
}
/* attr = */ NULL, statsd_network_thread,
/* args = */ NULL);
if (status != 0) {
- char errbuf[1024];
pthread_mutex_unlock(&metrics_lock);
- ERROR("statsd plugin: pthread_create failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("statsd plugin: pthread_create failed: %s", STRERRNO);
return status;
}
}
static _Bool values_absolute = 1;
static _Bool values_percentage = 0;
+static _Bool report_io = 1;
static int swap_config(oconfig_item_t *ci) /* {{{ */
{
cf_util_get_boolean(child, &values_absolute);
else if (strcasecmp("ValuesPercentage", child->key) == 0)
cf_util_get_boolean(child, &values_percentage);
+ else if (strcasecmp("ReportIO", child->key) == 0)
+ cf_util_get_boolean(child, &report_io);
else
WARNING("swap plugin: Unknown config option: \"%s\"", child->key);
}
fh = fopen("/proc/swaps", "r");
if (fh == NULL) {
- char errbuf[1024];
- WARNING("swap plugin: fopen (/proc/swaps) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("swap plugin: fopen (/proc/swaps) failed: %s", STRERRNO);
return -1;
}
fh = fopen("/proc/meminfo", "r");
if (fh == NULL) {
- char errbuf[1024];
- WARNING("swap plugin: fopen (/proc/meminfo) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("swap plugin: fopen (/proc/meminfo) failed: %s", STRERRNO);
return -1;
}
/* /proc/vmstat does not exist in kernels <2.6 */
fh = fopen("/proc/stat", "r");
if (fh == NULL) {
- char errbuf[1024];
- WARNING("swap: fopen: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("swap: fopen: %s", STRERRNO);
return -1;
} else
old_kernel = 1;
else
swap_read_combined();
- swap_read_io();
+ if (report_io)
+ swap_read_io();
return 0;
} /* }}} int swap_read */
struct anoninfo ai;
if (swapctl(SC_AINFO, &ai) == -1) {
- char errbuf[1024];
- ERROR("swap plugin: swapctl failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("swap plugin: swapctl failed: %s", STRERRNO);
return -1;
}
status = swapctl(SC_LIST, s);
if (status < 0) {
- char errbuf[1024];
- ERROR("swap plugin: swapctl (SC_LIST) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("swap plugin: swapctl (SC_LIST) failed: %s", STRERRNO);
sfree(s_paths);
sfree(s);
return -1;
status =
perfstat_memory_total(NULL, &pmemory, sizeof(perfstat_memory_total_t), 1);
if (status < 0) {
- char errbuf[1024];
- WARNING("swap plugin: perfstat_memory_total failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("swap plugin: perfstat_memory_total failed: %s", STRERRNO);
return -1;
}
reserved = (gauge_t)(pmemory.pgsp_rsvd * pagesize);
swap_submit_usage(NULL, total - free, free, "reserved", reserved);
- swap_submit_derive("in", (derive_t)pmemory.pgspins * pagesize);
- swap_submit_derive("out", (derive_t)pmemory.pgspouts * pagesize);
+
+ if (report_io) {
+ swap_submit_derive("in", (derive_t)pmemory.pgspins * pagesize);
+ swap_submit_derive("out", (derive_t)pmemory.pgspouts * pagesize);
+ }
return 0;
} /* }}} int swap_read */
--- /dev/null
+/**
+ * collectd - src/synproxy.c
+ * Copyright (C) 2017 Marek Becka
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Marek Becka <https://github.com/marekbecka>
+ **/
+
+#include "collectd.h"
+
+#include "common.h"
+#include "plugin.h"
+
+#if !KERNEL_LINUX
+#error "No applicable input method."
+#endif
+
+#define SYNPROXY_FIELDS 6
+
+static const char *synproxy_stat_path = "/proc/net/stat/synproxy";
+
+static const char *column_names[SYNPROXY_FIELDS] = {
+ "entries", "syn_received", "invalid",
+ "valid", "retransmission", "reopened"};
+static const char *column_types[SYNPROXY_FIELDS] = {
+ "current_connections", "connections", "cookies", "cookies", "cookies",
+ "connections"};
+
+static void synproxy_submit(value_t *results) {
+ value_list_t vl = VALUE_LIST_INIT;
+
+ /* 1st column (entries) is hardcoded to 0 in kernel code */
+ for (size_t n = 1; n < SYNPROXY_FIELDS; n++) {
+ vl.values = &results[n];
+ vl.values_len = 1;
+
+ sstrncpy(vl.plugin, "synproxy", sizeof(vl.plugin));
+ sstrncpy(vl.type, column_types[n], sizeof(vl.type));
+ sstrncpy(vl.type_instance, column_names[n], sizeof(vl.type_instance));
+
+ plugin_dispatch_values(&vl);
+ }
+}
+
+static int synproxy_read(void) {
+ char buf[1024];
+ value_t results[SYNPROXY_FIELDS];
+ int is_header = 1, status = 0;
+
+ FILE *fh = fopen(synproxy_stat_path, "r");
+ if (fh == NULL) {
+ ERROR("synproxy plugin: unable to open %s", synproxy_stat_path);
+ return -1;
+ }
+
+ memset(results, 0, sizeof(results));
+
+ while (fgets(buf, sizeof(buf), fh) != NULL) {
+ char *fields[SYNPROXY_FIELDS], *endprt;
+
+ if (is_header) {
+ is_header = 0;
+ continue;
+ }
+
+ int numfields = strsplit(buf, fields, STATIC_ARRAY_SIZE(fields));
+ if (numfields != SYNPROXY_FIELDS) {
+ ERROR("synproxy plugin: unexpected number of columns in %s",
+ synproxy_stat_path);
+ status = -1;
+ break;
+ }
+
+ /* 1st column (entries) is hardcoded to 0 in kernel code */
+ for (size_t n = 1; n < SYNPROXY_FIELDS; n++) {
+ char *endptr = NULL;
+ errno = 0;
+
+ results[n].derive += strtoull(fields[n], &endprt, 16);
+ if ((endptr == fields[n]) || errno != 0) {
+ ERROR("synproxy plugin: unable to parse value: %s", fields[n]);
+ fclose(fh);
+ return -1;
+ }
+ }
+ }
+
+ fclose(fh);
+
+ if (status == 0) {
+ synproxy_submit(results);
+ }
+
+ return status;
+}
+
+void module_register(void) {
+ plugin_register_read("synproxy", synproxy_read);
+} /* void module_register */
typedef struct {
char *file;
char *sep;
+ char *plugin_name;
char *instance;
tbl_result_t *results;
} /* tbl_result_setup */
static void tbl_result_clear(tbl_result_t *res) {
+ if (res == NULL) {
+ return;
+ }
+
sfree(res->type);
sfree(res->instance_prefix);
static void tbl_setup(tbl_t *tbl, char *file) {
tbl->file = sstrdup(file);
tbl->sep = NULL;
+ tbl->plugin_name = NULL;
tbl->instance = NULL;
tbl->results = NULL;
} /* tbl_setup */
static void tbl_clear(tbl_t *tbl) {
+ if (tbl == NULL) {
+ return;
+ }
+
sfree(tbl->file);
sfree(tbl->sep);
+ sfree(tbl->plugin_name);
sfree(tbl->instance);
+ /* (tbl->results == NULL) -> (tbl->results_num == 0) */
+ assert((tbl->results != NULL) || (tbl->results_num == 0));
for (size_t i = 0; i < tbl->results_num; ++i)
tbl_result_clear(tbl->results + i);
sfree(tbl->results);
tmp = realloc(*var, ((*len) + num) * sizeof(**var));
if (NULL == tmp) {
- char errbuf[1024];
- log_err("realloc failed: %s.", sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("realloc failed: %s.", STRERRNO);
return -1;
}
*var = tmp;
} /* tbl_config_append_array_s */
static int tbl_config_result(tbl_t *tbl, oconfig_item_t *ci) {
- tbl_result_t *res;
-
- int status = 0;
-
if (0 != ci->values_num) {
log_err("<Result> does not expect any arguments.");
return 1;
}
- res = realloc(tbl->results, (tbl->results_num + 1) * sizeof(*tbl->results));
+ tbl_result_t *res =
+ realloc(tbl->results, (tbl->results_num + 1) * sizeof(*tbl->results));
if (res == NULL) {
- char errbuf[1024];
- log_err("realloc failed: %s.", sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("realloc failed: %s.", STRERRNO);
return -1;
}
tbl->results = res;
- ++tbl->results_num;
- res = tbl->results + tbl->results_num - 1;
+ res = tbl->results + tbl->results_num;
tbl_result_setup(res);
for (int i = 0; i < ci->children_num; ++i) {
c->key);
}
+ int status = 0;
if (NULL == res->type) {
- log_err("No \"Type\" option specified for <Result> "
- "in table \"%s\".",
+ log_err("No \"Type\" option specified for <Result> in table \"%s\".",
tbl->file);
status = 1;
}
if (NULL == res->values) {
- log_err("No \"ValuesFrom\" option specified for <Result> "
- "in table \"%s\".",
+ log_err("No \"ValuesFrom\" option specified for <Result> in table \"%s\".",
tbl->file);
status = 1;
}
if (0 != status) {
tbl_result_clear(res);
- --tbl->results_num;
return status;
}
+
+ tbl->results_num++;
return 0;
} /* tbl_config_result */
static int tbl_config_table(oconfig_item_t *ci) {
- tbl_t *tbl;
-
- int status = 0;
-
if ((1 != ci->values_num) || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
log_err("<Table> expects a single string argument.");
return 1;
}
- tbl = realloc(tables, (tables_num + 1) * sizeof(*tables));
+ tbl_t *tbl = realloc(tables, (tables_num + 1) * sizeof(*tables));
if (NULL == tbl) {
- char errbuf[1024];
- log_err("realloc failed: %s.", sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("realloc failed: %s.", STRERRNO);
return -1;
}
tables = tbl;
- ++tables_num;
- tbl = tables + tables_num - 1;
+ tbl = tables + tables_num;
tbl_setup(tbl, ci->values[0].value.string);
for (size_t i = 0; i < ((size_t)ci->children_num); ++i) {
if (0 == strcasecmp(c->key, "Separator"))
tbl_config_set_s(c->key, &tbl->sep, c);
+ else if (0 == strcasecmp(c->key, "Plugin"))
+ tbl_config_set_s(c->key, &tbl->plugin_name, c);
else if (0 == strcasecmp(c->key, "Instance"))
tbl_config_set_s(c->key, &tbl->instance, c);
else if (0 == strcasecmp(c->key, "Result"))
c->key, tbl->file);
}
+ int status = 0;
if (NULL == tbl->sep) {
log_err("Table \"%s\" does not specify any separator.", tbl->file);
status = 1;
}
if (NULL == tbl->results) {
+ assert(tbl->results_num == 0);
log_err("Table \"%s\" does not specify any (valid) results.", tbl->file);
status = 1;
}
if (0 != status) {
tbl_clear(tbl);
- --tables_num;
return status;
}
if (res->values[j] > tbl->max_colnum)
tbl->max_colnum = res->values[j];
}
+
+ tables_num++;
return 0;
} /* tbl_config_table */
}
if (res->values_num != res->ds->ds_num) {
- log_err("Invalid type \"%s\". Expected %zu data source%s, "
- "got %zu.",
+ log_err("Invalid type \"%s\". Expected %" PRIsz " data source%s, "
+ "got %" PRIsz ".",
res->type, res->values_num, (1 == res->values_num) ? "" : "s",
res->ds->ds_num);
return -1;
vl.values = values;
vl.values_len = STATIC_ARRAY_SIZE(values);
- sstrncpy(vl.plugin, "table", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (tbl->plugin_name != NULL) ? tbl->plugin_name : "table",
+ sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, tbl->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, res->type, sizeof(vl.type));
if (i <= tbl->max_colnum) {
log_warn("Not enough columns in line "
- "(expected at least %zu, got %zu).",
+ "(expected at least %" PRIsz ", got %" PRIsz ").",
tbl->max_colnum + 1, i);
return -1;
}
fh = fopen(tbl->file, "r");
if (NULL == fh) {
- char errbuf[1024];
- log_err("Failed to open file \"%s\": %s.", tbl->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("Failed to open file \"%s\": %s.", tbl->file, STRERRNO);
return -1;
}
}
if (0 != ferror(fh)) {
- char errbuf[1024];
- log_err("Failed to read from file \"%s\": %s.", tbl->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ log_err("Failed to read from file \"%s\": %s.", tbl->file, STRERRNO);
fclose(fh);
return -1;
}
/*
* <Plugin tail>
* <File "/var/log/exim4/mainlog">
- * Instance "exim"
+ * Plugin "mail"
+ * Instance "exim"
* Interval 60
* <Match>
* Regex "S=([1-9][0-9]*)"
} /* int ctail_config_add_match_dstype */
static int ctail_config_add_match(cu_tail_match_t *tm,
+ const char *plugin_name,
const char *plugin_instance,
oconfig_item_t *ci, cdtime_t interval) {
ctail_config_match_t cm = {0};
if (status == 0) {
// TODO(octo): there's nothing "simple" about the latency stuff …
status = tail_match_add_match_simple(
- tm, cm.regex, cm.excluderegex, cm.flags, "tail", plugin_instance,
+ tm, cm.regex, cm.excluderegex, cm.flags,
+ (plugin_name != NULL) ? plugin_name : "tail", plugin_instance,
cm.type, cm.type_instance, cm.latency, interval);
if (status != 0)
static int ctail_config_add_file(oconfig_item_t *ci) {
cu_tail_match_t *tm;
cdtime_t interval = 0;
+ char *plugin_name = NULL;
char *plugin_instance = NULL;
int num_matches = 0;
oconfig_item_t *option = ci->children + i;
int status = 0;
- if (strcasecmp("Instance", option->key) == 0)
+ if (strcasecmp("Plugin", option->key) == 0)
+ status = cf_util_get_string (option, &plugin_name);
+ else if (strcasecmp("Instance", option->key) == 0)
status = cf_util_get_string(option, &plugin_instance);
else if (strcasecmp("Interval", option->key) == 0)
cf_util_get_cdtime(option, &interval);
else if (strcasecmp("Match", option->key) == 0) {
- status = ctail_config_add_match(tm, plugin_instance, option, interval);
+ status = ctail_config_add_match(tm, plugin_name, plugin_instance, option,
+ interval);
if (status == 0)
num_matches++;
/* Be mild with failed matches.. */
break;
} /* for (i = 0; i < ci->children_num; i++) */
+ sfree(plugin_name);
sfree(plugin_instance);
if (num_matches == 0) {
typedef struct metric_definition_s metric_definition_t;
struct instance_definition_s {
+ char *plugin_name;
char *instance;
char *path;
cu_tail_t *tail;
vl.values_len = 1;
vl.values = &v;
- sstrncpy(vl.plugin, "tail_csv", sizeof(vl.plugin));
+ sstrncpy(vl.plugin, (id->plugin_name != NULL) ? id->plugin_name : "tail_csv",
+ sizeof(vl.plugin));
if (id->instance != NULL)
sstrncpy(vl.plugin_instance, id->instance, sizeof(vl.plugin_instance));
sstrncpy(vl.type, md->type, sizeof(vl.type));
return 1;
ERROR("tail_csv plugin: Metric \"%s\": Request for index %zd when "
- "only %zu fields are available.",
+ "only %" PRIsz " fields are available.",
name, index, fields_num);
return 0;
}
cu_tail_destroy(id->tail);
id->tail = NULL;
+ sfree(id->plugin_name);
sfree(id->instance);
sfree(id->path);
sfree(id->metric_list);
id = calloc(1, sizeof(*id));
if (id == NULL)
return -1;
+ id->plugin_name = NULL;
id->instance = NULL;
id->path = NULL;
id->metric_list = NULL;
cf_util_get_cdtime(option, &id->interval);
else if (strcasecmp("TimeFrom", option->key) == 0)
status = tcsv_config_get_index(option, &id->time_from);
+ else if (strcasecmp("Plugin", option->key) == 0)
+ status = cf_util_get_string(option, &id->plugin_name);
else {
WARNING("tail_csv plugin: Option `%s' not allowed here.", option->key);
status = -1;
});
if (status != 0) {
ERROR("tail_csv plugin: Registering complex read function failed.");
- tcsv_instance_definition_destroy(id);
return -1;
}
md->type, md->name);
continue;
} else if (ds->ds_num != 1) {
- ERROR("tail_csv plugin: The type \"%s\" has %zu data sources. "
+ ERROR("tail_csv plugin: The type \"%s\" has %" PRIsz " data sources. "
"Only types with a single data source are supported.",
ds->type, ds->ds_num);
continue;
#error "No applicable input method."
#endif
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#define MAX_NUMTAPE 256
extern kstat_ctl_t *kc;
static kstat_t *ksp[MAX_NUMTAPE];
char template[DATA_MAX_NAME_LEN];
char value_str[DATA_MAX_NAME_LEN];
- snprintf(template, sizeof(template), "%%{ds:%s}", ds->ds[i].name);
+ const char *format = "%%{ds:%.*s}";
+ snprintf(template, sizeof(template), format,
+ DATA_MAX_NAME_LEN - strlen(format), ds->ds[i].name);
if (ds->ds[i].type != DS_TYPE_GAUGE) {
if ((rates == NULL) && (rates_failed == 0)) {
subst_status = subst(temp, sizeof(temp), buffer, (size_t)matches[0].rm_so,
(size_t)matches[0].rm_eo, act->replacement);
if (subst_status == NULL) {
- ERROR("Target `replace': subst (buffer = %s, start = %zu, end = %zu, "
+ ERROR("Target `replace': subst (buffer = %s, start = %" PRIsz
+ ", end = %" PRIsz ", "
"replacement = %s) failed.",
buffer, (size_t)matches[0].rm_so, (size_t)matches[0].rm_eo,
act->replacement);
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, "
+ ERROR("Target `replace': subst (value = %s, start = %" PRIsz
+ ", end = %" PRIsz ", "
"replacement = %s) failed.",
value, (size_t)matches[0].rm_so, (size_t)matches[0].rm_eo,
act->replacement);
if (vl->meta != NULL) {
char **meta_toc = NULL;
- int meta_entries = meta_data_toc(vl->meta, &meta_toc);
- if (meta_entries <= 0)
+ int status = meta_data_toc(vl->meta, &meta_toc);
+ if (status <= 0)
return;
+ size_t meta_entries = (size_t)status;
- for (int i = 0; i < meta_entries; i++) {
+ for (size_t i = 0; i < meta_entries; i++) {
char meta_name[DATA_MAX_NAME_LEN];
char *value_str;
const char *key = meta_toc[i];
if (data->meta != NULL) {
char temp[DATA_MAX_NAME_LEN * 2];
- int meta_entries;
char **meta_toc;
if ((new_meta = meta_data_create()) == NULL) {
return -ENOMEM;
}
- meta_entries = meta_data_toc(data->meta, &meta_toc);
- for (int i = 0; i < meta_entries; i++) {
+ int status = meta_data_toc(data->meta, &meta_toc);
+ if (status < 0) {
+ ERROR("Target `set': meta_data_toc failed with status %d.", status);
+ meta_data_destroy(new_meta);
+ return status;
+ }
+ size_t meta_entries = (size_t)status;
+
+ for (size_t i = 0; i < meta_entries; i++) {
const char *key = meta_toc[i];
char *string;
int status;
if (status) {
ERROR("Target `set': Unable to get replacement metadata value `%s'.",
key);
- strarray_free(meta_toc, (size_t)meta_entries);
+ strarray_free(meta_toc, meta_entries);
meta_data_destroy(new_meta);
return status;
}
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);
+ strarray_free(meta_toc, meta_entries);
meta_data_destroy(new_meta);
return status;
}
}
- strarray_free(meta_toc, (size_t)meta_entries);
+ strarray_free(meta_toc, meta_entries);
}
#define SUBST_FIELD(f) \
if (fd < 0) {
ERROR("tcpconns plugin: conn_read_netlink: socket(AF_NETLINK, SOCK_RAW, "
"NETLINK_INET_DIAG) failed: %s",
- sstrerror(errno, buf, sizeof(buf)));
+ STRERRNO);
return -1;
}
if (sendmsg(fd, &msg, 0) < 0) {
ERROR("tcpconns plugin: conn_read_netlink: sendmsg(2) failed: %s",
- sstrerror(errno, buf, sizeof(buf)));
+ STRERRNO);
close(fd);
return -1;
}
continue;
ERROR("tcpconns plugin: conn_read_netlink: recvmsg(2) failed: %s",
- sstrerror(errno, buf, sizeof(buf)));
+ STRERRNO);
close(fd);
return -1;
} else if (status == 0) {
/* Create socket */
sd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (sd < 0) {
- char errbuf[1024];
- WARNING("teamspeak2 plugin: socket failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("teamspeak2 plugin: socket failed: %s", STRERRNO);
continue;
}
/* Try to connect */
status = connect(sd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0) {
- char errbuf[1024];
- WARNING("teamspeak2 plugin: connect failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("teamspeak2 plugin: connect failed: %s", STRERRNO);
close(sd);
sd = -1;
continue;
/* Create file objects from sockets */
global_read_fh = fdopen(sd, "r");
if (global_read_fh == NULL) {
- char errbuf[1024];
- ERROR("teamspeak2 plugin: fdopen failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("teamspeak2 plugin: fdopen failed: %s", STRERRNO);
close(sd);
return -1;
}
global_write_fh = fdopen(sd, "w");
if (global_write_fh == NULL) {
- char errbuf[1024];
- ERROR("teamspeak2 plugin: fdopen failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("teamspeak2 plugin: fdopen failed: %s", STRERRNO);
tss2_close_socket();
return -1;
}
*/
temp = fgets(buffer, buffer_size, fh);
if (temp == NULL) {
- char errbuf[1024];
- ERROR("teamspeak2 plugin: fgets failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("teamspeak2 plugin: fgets failed: %s", STRERRNO);
tss2_close_socket();
return -1;
}
status = write(fd, pkt_request, sizeof(pkt_request));
if (status <= 0) {
- ERROR("ted plugin: swrite failed.");
+ ERROR("ted plugin: write failed.");
return -1;
}
/* Some signal or something. Start over.. */
continue;
} else if (status < 0) {
- char errbuf[1024];
- ERROR("ted plugin: select failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ted plugin: select failed: %s", STRERRNO);
return -1;
}
receive_buffer_length = read(fd, receive_buffer, sizeof(receive_buffer));
if (receive_buffer_length < 0) {
- char errbuf[1024];
if ((errno == EAGAIN) || (errno == EINTR))
continue;
- ERROR("ted plugin: read(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("ted plugin: read(2) failed: %s", STRERRNO);
return -1;
} else if (receive_buffer_length == 0) {
/* Should we close the FD in this case? */
#include "plugin.h"
#include "utils_time.h"
-#include <asm/msr-index.h>
+#include "msr-index.h"
#include <cpuid.h>
#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
/* If not using logical core numbering, set core id */
if (!config_lcn) {
- snprintf(name, sizeof(name), "core%02d", c->core_id);
+ if (topology.num_packages > 1)
+ snprintf(name, sizeof(name), "pkg%02d-core%02d", p->package_id,
+ c->core_id);
+ else
+ snprintf(name, sizeof(name), "core%02d", c->core_id);
}
if (do_core_cstate & (1 << 3))
case 0x45: /* HSW */
case 0x46: /* HSW */
case 0x3D: /* BDW */
+ case 0x5E: /* SKL */
do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX;
break;
case 0x3F: /* HSX */
connections value:DERIVE:0:U
conntrack value:GAUGE:0:4294967295
contextswitch value:DERIVE:0:U
+cookies value:DERIVE:0:U
count value:GAUGE:0:U
counter value:COUNTER:U:U
cpu value:DERIVE:0:U
current_connections value:GAUGE:0:U
current_sessions value:GAUGE:0:U
delay value:GAUGE:-1000000:1000000
+delay_rate value:GAUGE:0:U
derive value:DERIVE:0:U
df used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623
df_complex value:GAUGE:0:U
ping_droprate value:GAUGE:0:100
ping_stddev value:GAUGE:0:65535
players value:GAUGE:0:1000000
+pools value:GAUGE:0:U
power value:GAUGE:U:U
pressure value:GAUGE:0:U
protocol_counter value:DERIVE:0:U
timeleft value:GAUGE:0:U
total_bytes value:DERIVE:0:U
total_connections value:DERIVE:0:U
+total_events value:DERIVE:0:U
total_objects value:DERIVE:0:U
total_operations value:DERIVE:0:U
total_requests value:DERIVE:0:U
sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0) {
- char errbuf[1024];
- ERROR("unixsock plugin: socket failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: socket failed: %s", STRERRNO);
return -1;
}
errno = 0;
status = unlink(sa.sun_path);
if ((status != 0) && (errno != ENOENT)) {
- char errbuf[1024];
WARNING("unixsock plugin: Deleting socket file \"%s\" failed: %s",
- sa.sun_path, sstrerror(errno, errbuf, sizeof(errbuf)));
+ sa.sun_path, STRERRNO);
} else if (status == 0) {
INFO("unixsock plugin: Successfully deleted socket file \"%s\".",
sa.sun_path);
status = bind(sock_fd, (struct sockaddr *)&sa, sizeof(sa));
if (status != 0) {
- char errbuf[1024];
- sstrerror(errno, errbuf, sizeof(errbuf));
- ERROR("unixsock plugin: bind failed: %s", errbuf);
+ ERROR("unixsock plugin: bind failed: %s", STRERRNO);
close(sock_fd);
sock_fd = -1;
return -1;
status = chmod(sa.sun_path, sock_perms);
if (status == -1) {
- char errbuf[1024];
- ERROR("unixsock plugin: chmod failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: chmod failed: %s", STRERRNO);
close(sock_fd);
sock_fd = -1;
return -1;
status = listen(sock_fd, 8);
if (status != 0) {
- char errbuf[1024];
- ERROR("unixsock plugin: listen failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: listen failed: %s", STRERRNO);
close(sock_fd);
sock_fd = -1;
return -1;
const char *grpname;
struct group *g;
struct group sg;
- char grbuf[4096];
+
+ long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (grbuf_size <= 0)
+ grbuf_size = sysconf(_SC_PAGESIZE);
+ if (grbuf_size <= 0)
+ grbuf_size = 4096;
+ char grbuf[grbuf_size];
grpname = (sock_group != NULL) ? sock_group : COLLECTD_GRP_NAME;
g = NULL;
status = getgrnam_r(grpname, &sg, grbuf, sizeof(grbuf), &g);
if (status != 0) {
- char errbuf[1024];
WARNING("unixsock plugin: getgrnam_r (%s) failed: %s", grpname,
- sstrerror(status, errbuf, sizeof(errbuf)));
+ STRERROR(status));
break;
}
if (g == NULL) {
if (chown((sock_file != NULL) ? sock_file : US_DEFAULT_PATH, (uid_t)-1,
g->gr_gid) != 0) {
- char errbuf[1024];
WARNING("unixsock plugin: chown (%s, -1, %i) failed: %s",
(sock_file != NULL) ? sock_file : US_DEFAULT_PATH, (int)g->gr_gid,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
}
} while (0);
fdout = dup(fdin);
if (fdout < 0) {
- char errbuf[1024];
- ERROR("unixsock plugin: dup failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: dup failed: %s", STRERRNO);
close(fdin);
pthread_exit((void *)1);
}
fhin = fdopen(fdin, "r");
if (fhin == NULL) {
- char errbuf[1024];
- ERROR("unixsock plugin: fdopen failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: fdopen failed: %s", STRERRNO);
close(fdin);
close(fdout);
pthread_exit((void *)1);
fhout = fdopen(fdout, "w");
if (fhout == NULL) {
- char errbuf[1024];
- ERROR("unixsock plugin: fdopen failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: fdopen failed: %s", STRERRNO);
fclose(fhin); /* this closes fdin as well */
close(fdout);
pthread_exit((void *)1);
/* change output buffer to line buffered mode */
if (setvbuf(fhout, NULL, _IOLBF, 0) != 0) {
- char errbuf[1024];
- ERROR("unixsock plugin: setvbuf failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: setvbuf failed: %s", STRERRNO);
fclose(fhin);
fclose(fhout);
pthread_exit((void *)1);
continue;
if (errno != 0) {
- char errbuf[1024];
WARNING("unixsock plugin: failed to read from socket #%i: %s",
- fileno(fhin), sstrerror(errno, errbuf, sizeof(errbuf)));
+ fileno(fhin), STRERRNO);
}
break;
}
cmd_handle_flush(fhout, buffer);
} else {
if (fprintf(fhout, "-1 Unknown command: %s\n", fields[0]) < 0) {
- char errbuf[1024];
WARNING("unixsock plugin: failed to write to socket #%i: %s",
- fileno(fhout), sstrerror(errno, errbuf, sizeof(errbuf)));
+ fileno(fhout), STRERRNO);
break;
}
}
DEBUG("unixsock plugin: Calling accept..");
status = accept(sock_fd, NULL, NULL);
if (status < 0) {
- char errbuf[1024];
if (errno == EINTR)
continue;
- ERROR("unixsock plugin: accept failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: accept failed: %s", STRERRNO);
close(sock_fd);
sock_fd = -1;
pthread_attr_destroy(&th_attr);
remote_fd = malloc(sizeof(*remote_fd));
if (remote_fd == NULL) {
- char errbuf[1024];
- WARNING("unixsock plugin: malloc failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("unixsock plugin: malloc failed: %s", STRERRNO);
close(status);
continue;
}
status = plugin_thread_create(&th, &th_attr, us_handle_client,
(void *)remote_fd, "unixsock conn");
if (status != 0) {
- char errbuf[1024];
- WARNING("unixsock plugin: pthread_create failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("unixsock plugin: pthread_create failed: %s", STRERRNO);
close(*remote_fd);
free(remote_fd);
continue;
status = unlink((sock_file != NULL) ? sock_file : US_DEFAULT_PATH);
if (status != 0) {
- char errbuf[1024];
NOTICE("unixsock plugin: unlink (%s) failed: %s",
- (sock_file != NULL) ? sock_file : US_DEFAULT_PATH,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ (sock_file != NULL) ? sock_file : US_DEFAULT_PATH, STRERRNO);
}
return (void *)0;
status = plugin_thread_create(&listen_thread, NULL, us_server_thread, NULL,
"unixsock listen");
if (status != 0) {
- char errbuf[1024];
- ERROR("unixsock plugin: pthread_create failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("unixsock plugin: pthread_create failed: %s", STRERRNO);
return -1;
}
#include "plugin.h"
#if KERNEL_LINUX
-#define STAT_FILE "/proc/stat"
-/* Using /proc filesystem to retrieve the boot time, Linux only. */
+#include <sys/sysinfo.h>
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
/*
* Global variables
*/
-/* boottime always used, no OS distinction */
-static time_t boottime;
+
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
#if HAVE_LIBKSTAT
extern kstat_ctl_t *kc;
plugin_dispatch_values(&vl);
}
-static int uptime_init(void) /* {{{ */
-{
/*
* On most unix systems the uptime is calculated by looking at the boot
* time (stored in unix time, since epoch) and the current one. We are
* the boot time, the plugin is unregistered and there is no chance to
* try again later. Nevertheless, this is very unlikely to happen.
*/
-
+static time_t uptime_get_sys(void) { /* {{{ */
+ time_t result;
#if KERNEL_LINUX
- unsigned long starttime;
- char buffer[1024];
- int ret;
- FILE *fh;
-
- ret = 0;
-
- fh = fopen(STAT_FILE, "r");
-
- if (fh == NULL) {
- char errbuf[1024];
- ERROR("uptime plugin: Cannot open " STAT_FILE ": %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- return -1;
- }
-
- while (fgets(buffer, 1024, fh) != NULL) {
- /* look for the btime string and read the value */
- ret = sscanf(buffer, "btime %lu", &starttime);
- /* avoid further loops if btime has been found and read
- * correctly (hopefully) */
- if (ret == 1)
- break;
- }
-
- fclose(fh);
+ struct sysinfo info;
+ int status;
- /* loop done, check if no value has been found/read */
- if (ret != 1) {
- ERROR("uptime plugin: No value read from " STAT_FILE "");
+ status = sysinfo(&info);
+ if (status != 0) {
+ ERROR("uptime plugin: Error calling sysinfo: %s", STRERRNO);
return -1;
}
- boottime = (time_t)starttime;
-
- if (boottime == 0) {
- ERROR("uptime plugin: btime read from " STAT_FILE ", "
- "but `boottime' is zero!");
- return -1;
- }
+ result = (time_t)info.uptime;
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
return -1;
}
- boottime = (time_t)knp->value.ui32;
-
- if (boottime == 0) {
+ if (knp->value.ui32 == 0) {
ERROR("uptime plugin: kstat_data_lookup returned success, "
"but `boottime' is zero!");
return -1;
}
+
+ result = time(NULL) - (time_t)knp->value.ui32;
/* #endif HAVE_LIBKSTAT */
#elif HAVE_SYS_SYSCTL_H
status = sysctl(mib, STATIC_ARRAY_SIZE(mib), &boottv, &boottv_len,
/* new_value = */ NULL, /* new_length = */ 0);
if (status != 0) {
- char errbuf[1024];
- ERROR("uptime plugin: No value read from sysctl interface: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("uptime plugin: No value read from sysctl interface: %s", STRERRNO);
return -1;
}
- boottime = boottv.tv_sec;
-
- if (boottime == 0) {
+ if (boottv.tv_sec == 0) {
ERROR("uptime plugin: sysctl(3) returned success, "
"but `boottime' is zero!");
return -1;
}
+
+ result = time(NULL) - boottv.tv_sec;
/* #endif HAVE_SYS_SYSCTL_H */
#elif HAVE_PERFSTAT
status = perfstat_cpu_total(NULL, &cputotal, sizeof(perfstat_cpu_total_t), 1);
if (status < 0) {
- char errbuf[1024];
- ERROR("uptime plugin: perfstat_cpu_total: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("uptime plugin: perfstat_cpu_total: %s", STRERRNO);
return -1;
}
if (hertz <= 0)
hertz = HZ;
- boottime = time(NULL) - cputotal.lbolt / hertz;
+ result = cputotal.lbolt / hertz;
#endif /* HAVE_PERFSTAT */
- return 0;
-} /* }}} int uptime_init */
+ return result;
+} /* }}} int uptime_get_sys */
static int uptime_read(void) {
gauge_t uptime;
time_t elapsed;
/* calculate the amount of time elapsed since boot, AKA uptime */
- elapsed = time(NULL) - boottime;
+ elapsed = uptime_get_sys();
uptime = (gauge_t)elapsed;
}
void module_register(void) {
- plugin_register_init("uptime", uptime_init);
plugin_register_read("uptime", uptime_read);
} /* void module_register */
#define print_to_socket(fh, ...) \
if (fprintf(fh, __VA_ARGS__) < 0) { \
- char errbuf[1024]; \
WARNING("handle_getthreshold: failed to write to socket #%i: %s", \
- fileno(fh), sstrerror(errno, errbuf, sizeof(errbuf))); \
+ fileno(fh), STRERRNO); \
return -1; \
}
i++;
/* Print the response */
- print_to_socket(fh, "%zu Threshold found\n", i);
+ print_to_socket(fh, "%" PRIsz " Threshold found\n", i);
if (threshold.host[0] != 0)
print_to_socket(fh, "Host: %s\n", threshold.host);
#define print_to_socket(fh, ...) \
do { \
if (fprintf(fh, __VA_ARGS__) < 0) { \
- char errbuf[1024]; \
WARNING("cmd_handle_getval: failed to write to socket #%i: %s", \
- fileno(fh), sstrerror(errno, errbuf, sizeof(errbuf))); \
+ fileno(fh), STRERRNO); \
return -1; \
} \
fflush(fh); \
}
if (ds->ds_num != values_num) {
- ERROR("ds[%s]->ds_num = %zu, "
- "but uc_get_rate_by_name returned %zu values.",
+ ERROR("ds[%s]->ds_num = %" PRIsz ", "
+ "but uc_get_rate_by_name returned %" PRIsz " values.",
ds->type, ds->ds_num, values_num);
cmd_error(CMD_ERROR, &err, "Error reading value from cache.");
sfree(values);
return CMD_ERROR;
}
- print_to_socket(fh, "%zu Value%s found\n", values_num,
+ print_to_socket(fh, "%" PRIsz " Value%s found\n", values_num,
(values_num == 1) ? "" : "s");
for (size_t i = 0; i < values_num; i++) {
print_to_socket(fh, "%s=", ds->ds[i].name);
#define print_to_socket(fh, ...) \
do { \
if (fprintf(fh, __VA_ARGS__) < 0) { \
- char errbuf[1024]; \
WARNING("handle_listval: failed to write to socket #%i: %s", fileno(fh), \
- sstrerror(errno, errbuf, sizeof(errbuf))); \
+ STRERRNO); \
free_everything_and_return(CMD_ERROR); \
} \
fflush(fh); \
#define print_to_socket(fh, ...) \
do { \
if (fprintf(fh, __VA_ARGS__) < 0) { \
- char errbuf[1024]; \
WARNING("handle_putnotif: failed to write to socket #%i: %s", \
- fileno(fh), sstrerror(errno, errbuf, sizeof(errbuf))); \
+ fileno(fh), STRERRNO); \
return -1; \
} \
fflush(fh); \
* Sebastian 'tokkee' Harl <sh at tokkee.org>
**/
-#include "utils_cmds.h"
#include "daemon/common.h"
#include "utils_cmd_flush.h"
#include "utils_cmd_getval.h"
#include "utils_cmd_listval.h"
#include "utils_cmd_putval.h"
+#include "utils_cmds.h"
#include "utils_parse_option.h"
#include <stdbool.h>
vsnprintf(buf, sizeof(buf), format, ap);
buf[sizeof(buf) - 1] = '\0';
if (fprintf(fh, "%i %s\n", code, buf) < 0) {
- char errbuf[1024];
WARNING("utils_cmds: failed to write to file-handle #%i: %s", fileno(fh),
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return;
}
if (s == NULL)
return 0;
- if ((curl == NULL) || (hostname == NULL) || (plugin == NULL)) {
+ if ((curl == NULL) || (plugin == NULL)) {
ERROR("curl stats: dispatch() called with missing arguments "
- "(curl=%p; hostname=%s; plugin=%s)",
- curl, hostname == NULL ? "<NULL>" : hostname,
- plugin == NULL ? "<NULL>" : plugin);
+ "(curl=%p; plugin=%s)",
+ curl, plugin == NULL ? "<NULL>" : plugin);
return -1;
}
- sstrncpy(vl.host, hostname, sizeof(vl.host));
+ if (hostname != NULL)
+ sstrncpy(vl.host, hostname, sizeof(vl.host));
sstrncpy(vl.plugin, plugin, sizeof(vl.plugin));
if (plugin_instance != NULL)
sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
if (prep_area->ds->ds_num != r->values_num) {
ERROR("db query utils: udb_result_prepare_result: The type `%s' "
- "requires exactly %zu value%s, but the configuration specifies %zu.",
+ "requires exactly %" PRIsz
+ " value%s, but the configuration specifies %" PRIsz ".",
r->type, prep_area->ds->ds_num,
(prep_area->ds->ds_num == 1) ? "" : "s", r->values_num);
BAIL_OUT(-1);
do {
for (size_t i = 0; i < prep_area->column_num; i++) {
DEBUG("db query utils: udb_query_handle_result (%s, %s): "
- "column[%zu] = %s;",
+ "column[%" PRIsz "] = %s;",
prep_area->db_name, q->name, i, column_values[i]);
}
} while (0);
do {
for (size_t i = 0; i < column_num; i++) {
DEBUG("db query utils: udb_query_prepare_result: "
- "query = %s; column[%zu] = %s;",
+ "query = %s; column[%" PRIsz "] = %s;",
q->name, i, column_names[i]);
}
} while (0);
#include "utils_dpdk.h"
#define DPDK_DEFAULT_RTE_CONFIG "/var/run/.rte_config"
-#define DPDK_EAL_ARGC 5
-#define DPDK_MAX_BUFFER_SIZE (4096 * 4)
+#define DPDK_EAL_ARGC 10
+// Complete trace should fit into 1024 chars. Trace contain some headers
+// and text together with traced data from pipe. This is the reason why
+// we need to limit DPDK_MAX_BUFFER_SIZE value.
+#define DPDK_MAX_BUFFER_SIZE 896
#define DPDK_CDM_DEFAULT_TIMEOUT 10000
enum DPDK_HELPER_STATUS {
status = cf_util_get_string_buffer(child, prefix, sizeof(prefix));
if (status == 0) {
snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN,
- "/var/run/.%s_config", prefix);
+ "/var/run/.%s_config", prefix);
DEBUG("dpdk_common: EAL:File prefix %s", phc->eal_config.file_prefix);
}
+ } else if (strcasecmp("LogLevel", child->key) == 0) {
+ status = cf_util_get_string_buffer(child, phc->eal_config.log_level,
+ sizeof(phc->eal_config.log_level));
+ DEBUG("dpdk_common: EAL:LogLevel %s", phc->eal_config.log_level);
+ } else if (strcasecmp("RteDriverLibPath", child->key) == 0) {
+ status = cf_util_get_string_buffer(
+ child, phc->eal_config.rte_driver_lib_path,
+ sizeof(phc->eal_config.rte_driver_lib_path));
+ DEBUG("dpdk_common: EAL:RteDriverLibPath %s",
+ phc->eal_config.rte_driver_lib_path);
} else {
ERROR("dpdk_common: Invalid '%s' configuration option", child->key);
status = -EINVAL;
static int dpdk_shm_init(const char *name, size_t size, void **map) {
DPDK_HELPER_TRACE(name);
- char errbuf[ERR_BUF_SIZE];
-
int fd = shm_open(name, O_CREAT | O_TRUNC | O_RDWR, 0666);
if (fd < 0) {
- WARNING("dpdk_shm_init: Failed to open %s as SHM:%s", name,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("dpdk_shm_init: Failed to open %s as SHM:%s", name, STRERRNO);
*map = NULL;
return -1;
}
int ret = ftruncate(fd, size);
if (ret != 0) {
- WARNING("dpdk_shm_init: Failed to resize SHM:%s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("dpdk_shm_init: Failed to resize SHM:%s", STRERRNO);
close(fd);
*map = NULL;
dpdk_shm_cleanup(name, size, NULL);
*map = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (*map == MAP_FAILED) {
- WARNING("dpdk_shm_init:Failed to mmap SHM:%s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("dpdk_shm_init:Failed to mmap SHM:%s", STRERRNO);
close(fd);
*map = NULL;
dpdk_shm_cleanup(name, size, NULL);
static void dpdk_shm_cleanup(const char *name, size_t size, void *map) {
DPDK_HELPER_TRACE(name);
- char errbuf[ERR_BUF_SIZE];
/*
* Call shm_unlink first, as 'name' might be no longer accessible after munmap
*/
if (shm_unlink(name))
- ERROR("shm_unlink failure %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("shm_unlink failure %s", STRERRNO);
if (map != NULL) {
if (munmap(map, size))
- ERROR("munmap failure %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("munmap failure %s", STRERRNO);
}
}
dpdk_helper_ctx_t **pphc) {
dpdk_helper_ctx_t *phc = NULL;
size_t shm_size = sizeof(dpdk_helper_ctx_t) + data_size;
- char errbuf[ERR_BUF_SIZE];
if (pphc == NULL) {
ERROR("%s:Invalid argument(pphc)", __FUNCTION__);
err = sem_init(&phc->sema_cmd_start, 1, 0);
if (err != 0) {
- ERROR("sema_cmd_start semaphore init failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("sema_cmd_start semaphore init failed: %s", STRERRNO);
int errno_m = errno;
dpdk_shm_cleanup(name, shm_size, (void *)phc);
return -errno_m;
err = sem_init(&phc->sema_cmd_complete, 1, 0);
if (err != 0) {
- ERROR("sema_cmd_complete semaphore init failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("sema_cmd_complete semaphore init failed: %s", STRERRNO);
sem_destroy(&phc->sema_cmd_start);
int errno_m = errno;
dpdk_shm_cleanup(name, shm_size, (void *)phc);
}
static int dpdk_helper_spawn(dpdk_helper_ctx_t *phc) {
- char errbuf[ERR_BUF_SIZE];
if (phc == NULL) {
ERROR("Invalid argument(phc)");
return -EINVAL;
}
if (pipe(phc->pipes) != 0) {
- DEBUG("dpdk_helper_spawn: Could not create helper pipe: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ DEBUG("dpdk_helper_spawn: Could not create helper pipe: %s", STRERRNO);
return -1;
}
int pipe0_flags = fcntl(phc->pipes[0], F_GETFL, 0);
int pipe1_flags = fcntl(phc->pipes[1], F_GETFL, 0);
if (pipe0_flags == -1 || pipe1_flags == -1) {
- WARNING("dpdk_helper_spawn: error setting up pipe flags: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("dpdk_helper_spawn: error setting up pipe flags: %s", STRERRNO);
}
int pipe0_err = fcntl(phc->pipes[0], F_SETFL, pipe1_flags | O_NONBLOCK);
int pipe1_err = fcntl(phc->pipes[1], F_SETFL, pipe0_flags | O_NONBLOCK);
if (pipe0_err == -1 || pipe1_err == -1) {
- WARNING("dpdk_helper_spawn: error setting up pipes: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("dpdk_helper_spawn: error setting up pipes: %s", STRERRNO);
}
pid_t pid = fork();
dpdk_helper_worker(phc);
exit(0);
} else {
- ERROR("dpdk_helper_start: Failed to fork helper process: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("dpdk_helper_start: Failed to fork helper process: %s", STRERRNO);
return -1;
}
static int dpdk_helper_exit_command(dpdk_helper_ctx_t *phc,
enum DPDK_HELPER_STATUS status) {
- char errbuf[ERR_BUF_SIZE];
DPDK_HELPER_TRACE(phc->shm_name);
close(phc->pipes[1]);
int err = kill(phc->pid, SIGKILL);
if (err) {
- ERROR("%s error sending kill to helper: %s", __FUNCTION__,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("%s error sending kill to helper: %s", __FUNCTION__, STRERRNO);
}
}
} else {
int err = kill(phc->pid, SIGKILL);
if (err) {
- ERROR("%s error sending kill to helper: %s", __FUNCTION__,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("%s error sending kill to helper: %s", __FUNCTION__, STRERRNO);
}
}
argp[argc++] = "--proc-type";
argp[argc++] = "secondary";
+ if (strcasecmp(phc->eal_config.log_level, "") != 0) {
+ argp[argc++] = "--log-level";
+ argp[argc++] = phc->eal_config.log_level;
+ }
+ if (strcasecmp(phc->eal_config.rte_driver_lib_path, "") != 0) {
+ argp[argc++] = "-d";
+ argp[argc++] = phc->eal_config.rte_driver_lib_path;
+ }
+
assert(argc <= (DPDK_EAL_ARGC * 2 + 1));
int ret = rte_eal_init(argc, argp);
DPDK_CHILD_LOG("%s:%s:%d post sema_cmd_complete (pid=%lu)\n", phc->shm_name,
__FUNCTION__, __LINE__, (long)getpid());
if (err) {
- char errbuf[ERR_BUF_SIZE];
DPDK_CHILD_LOG("dpdk_helper_worker: error posting sema_cmd_complete "
"semaphore (%s)\n",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
}
#if COLLECT_DEBUG
static int dpdk_helper_status_check(dpdk_helper_ctx_t *phc) {
DEBUG("%s:%s:%d pid=%u %s", phc->shm_name, __FUNCTION__, __LINE__, getpid(),
dpdk_helper_status_str(phc->status));
- char errbuf[ERR_BUF_SIZE];
if (phc->status == DPDK_HELPER_GRACEFUL_QUIT) {
return 0;
__LINE__);
int err = dpdk_helper_spawn(phc);
if (err) {
- ERROR("dpdkstat: error spawning helper %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("dpdkstat: error spawning helper %s", STRERRNO);
}
return -1;
}
__LINE__);
int err = dpdk_helper_spawn(phc);
if (err) {
- ERROR("dpdkstat: error spawning helper %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("dpdkstat: error spawning helper %s", STRERRNO);
}
return -1;
}
.fd = phc->pipes[0], .events = POLLIN,
};
int data_avail = poll(&fds, 1, 0);
+ DEBUG("%s:dpdk_helper_check_pipe: poll data_avail=%d", phc->shm_name,
+ data_avail);
if (data_avail < 0) {
if (errno != EINTR || errno != EAGAIN) {
- char errbuf[ERR_BUF_SIZE];
- ERROR("%s: poll(2) failed: %s", phc->shm_name,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("%s: poll(2) failed: %s", phc->shm_name, STRERRNO);
}
}
while (data_avail) {
- int nbytes = read(phc->pipes[0], buf, sizeof(buf));
+ int nbytes = read(phc->pipes[0], buf, (sizeof(buf) - 1));
+ DEBUG("%s:dpdk_helper_check_pipe: read nbytes=%d", phc->shm_name, nbytes);
if (nbytes <= 0)
break;
- sstrncpy(out, buf, nbytes);
+ buf[nbytes] = '\0';
+ sstrncpy(out, buf, sizeof(out));
DEBUG("%s: helper process:\n%s", phc->shm_name, out);
}
}
/* kick helper to process command */
int err = sem_post(&phc->sema_cmd_start);
if (err) {
- char errbuf[ERR_BUF_SIZE];
ERROR("dpdk_helper_worker: error posting sema_cmd_start semaphore (%s)",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
}
#if COLLECT_DEBUG
return lcore_mask;
} else {
char low_str[DATA_MAX_NAME_LEN];
- char high_str[DATA_MAX_NAME_LEN];
+ char high_str[DATA_MAX_NAME_LEN * 2];
memset(high_str, 0, sizeof(high_str));
memset(low_str, 0, sizeof(low_str));
char memory_channels[DATA_MAX_NAME_LEN];
char socket_memory[DATA_MAX_NAME_LEN];
char file_prefix[DATA_MAX_NAME_LEN];
+ char log_level[DATA_MAX_NAME_LEN];
+ char rte_driver_lib_path[PATH_MAX];
};
typedef struct dpdk_eal_config_s dpdk_eal_config_t;
else if (rates != NULL)
BUFFER_ADD("%f", rates[ds_num]);
else if (ds->ds[ds_num].type == DS_TYPE_COUNTER)
- BUFFER_ADD("%llu", vl->values[ds_num].counter);
+ BUFFER_ADD("%" PRIu64, (uint64_t)vl->values[ds_num].counter);
else if (ds->ds[ds_num].type == DS_TYPE_DERIVE)
BUFFER_ADD("%" PRIi64, vl->values[ds_num].derive);
else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
(unsigned int)CDTIME_T_TO_TIME_T(vl->time));
if (message_len >= sizeof(message)) {
ERROR("format_graphite: message buffer too small: "
- "Need %zu bytes.",
+ "Need %" PRIsz " bytes.",
message_len + 1);
sfree(rates);
return -ENOMEM;
else
BUFFER_ADD("null");
} else if (ds->ds[i].type == DS_TYPE_COUNTER)
- BUFFER_ADD("%llu", vl->values[i].counter);
+ BUFFER_ADD("%" PRIu64, (uint64_t)vl->values[i].counter);
else if (ds->ds[i].type == DS_TYPE_DERIVE)
BUFFER_ADD("%" PRIi64, vl->values[i].derive);
else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
} \
} while (0)
+#define CHECK_SUCCESS(cmd) \
+ do { \
+ yajl_gen_status s = (cmd); \
+ if (s != yajl_gen_status_ok) { \
+ return (int)s; \
+ } \
+ } while (0)
+
static int format_json_meta(yajl_gen g, notification_meta_t *meta) /* {{{ */
{
if (meta == NULL)
default:
ERROR("format_json_meta: unknown meta data type %d (name \"%s\")",
meta->type, meta->name);
- yajl_gen_null(g);
+ CHECK_SUCCESS(yajl_gen_null(g));
}
return format_json_meta(g, meta->next);
static int format_alert(yajl_gen g, notification_t const *n) /* {{{ */
{
- yajl_gen_array_open(g);
- yajl_gen_map_open(g); /* BEGIN alert */
+ CHECK_SUCCESS(yajl_gen_array_open(g)); /* BEGIN array */
+ CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN alert */
/*
* labels
*/
JSON_ADD(g, "labels");
- yajl_gen_map_open(g); /* BEGIN labels */
+ CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN labels */
JSON_ADD(g, "alertname");
if (strncmp(n->plugin, n->type, strlen(n->plugin)) == 0)
JSON_ADD(g, "service");
JSON_ADD(g, "collectd");
- yajl_gen_map_close(g); /* END labels */
+ CHECK_SUCCESS(yajl_gen_map_close(g)); /* END labels */
/*
* annotations
*/
JSON_ADD(g, "annotations");
- yajl_gen_map_open(g); /* BEGIN annotations */
+ CHECK_SUCCESS(yajl_gen_map_open(g)); /* BEGIN annotations */
JSON_ADD(g, "summary");
JSON_ADD(g, n->message);
- if (format_json_meta(g, n->meta) != 0)
+ if (format_json_meta(g, n->meta) != 0) {
return -1;
+ }
- yajl_gen_map_close(g); /* END annotations */
+ CHECK_SUCCESS(yajl_gen_map_close(g)); /* END annotations */
JSON_ADD(g, "startsAt");
- format_time(g, n->time);
+ if (format_time(g, n->time) != 0) {
+ return -1;
+ }
- yajl_gen_map_close(g); /* END alert */
- yajl_gen_array_close(g);
+ CHECK_SUCCESS(yajl_gen_map_close(g)); /* END alert */
+ CHECK_SUCCESS(yajl_gen_array_close(g)); /* END array */
return 0;
} /* }}} format_alert */
}
/* copy to output buffer */
- yajl_gen_get_buf(g, &out, &unused_out_len);
+ if (yajl_gen_get_buf(g, &out, &unused_out_len) != yajl_gen_status_ok) {
+ yajl_gen_clear(g);
+ yajl_gen_free(g);
+ return -1;
+ }
sstrncpy(buffer, (void *)out, buffer_size);
yajl_gen_clear(g);
BUFFER_ADD("[[");
BUFFER_ADD("%" PRIu64, CDTIME_T_TO_MS(vl->time));
BUFFER_ADD(",");
- BUFFER_ADD("%llu", vl->values[ds_idx].counter);
+ BUFFER_ADD("%" PRIu64, (uint64_t)vl->values[ds_idx].counter);
} else if (ds->ds[ds_idx].type == DS_TYPE_DERIVE) {
BUFFER_ADD("[[");
BUFFER_ADD("%" PRIu64, CDTIME_T_TO_MS(vl->time));
const data_set_t *ds, const value_list_t *vl,
int store_rates,
char const *const *http_attrs,
- size_t http_attrs_num, int data_ttl) {
+ size_t http_attrs_num, int data_ttl,
+ char const *metrics_prefix) {
char temp[512];
size_t offset = 0;
int status;
for (size_t i = 0; i < ds->ds_num; i++) {
/* All value lists have a leading comma. The first one will be replaced with
* a square bracket in `format_kairosdb_finalize'. */
- BUFFER_ADD(",{");
+ BUFFER_ADD(",{\"name\":\"");
- BUFFER_ADD("\"name\":\"collectd");
+ if (metrics_prefix != NULL) {
+ BUFFER_ADD("%s.", metrics_prefix);
+ }
- BUFFER_ADD(".%s", vl->plugin);
+ BUFFER_ADD("%s", vl->plugin);
status = values_to_kairosdb(temp, sizeof(temp), ds, vl, store_rates, i);
if (status != 0)
char *buffer, /* {{{ */
size_t *ret_buffer_fill, size_t *ret_buffer_free, const data_set_t *ds,
const value_list_t *vl, int store_rates, size_t temp_size,
- char const *const *http_attrs, size_t http_attrs_num, int data_ttl) {
+ char const *const *http_attrs, size_t http_attrs_num, int data_ttl,
+ char const *metrics_prefix) {
char temp[temp_size];
int status;
status = value_list_to_kairosdb(temp, sizeof(temp), ds, vl, store_rates,
- http_attrs, http_attrs_num, data_ttl);
+ http_attrs, http_attrs_num, data_ttl,
+ metrics_prefix);
if (status != 0)
return status;
temp_size = strlen(temp);
size_t *ret_buffer_fill, size_t *ret_buffer_free,
const data_set_t *ds, const value_list_t *vl,
int store_rates, char const *const *http_attrs,
- size_t http_attrs_num, int data_ttl) {
+ size_t http_attrs_num, int data_ttl,
+ char const *metrics_prefix) {
if ((buffer == NULL) || (ret_buffer_fill == NULL) ||
(ret_buffer_free == NULL) || (ds == NULL) || (vl == NULL))
return -EINVAL;
return format_kairosdb_value_list_nocheck(
buffer, ret_buffer_fill, ret_buffer_free, ds, vl, store_rates,
- (*ret_buffer_free) - 2, http_attrs, http_attrs_num, data_ttl);
+ (*ret_buffer_free) - 2, http_attrs, http_attrs_num, data_ttl,
+ metrics_prefix);
} /* }}} int format_kairosdb_value_list */
/* vim: set sw=2 sts=2 et fdm=marker : */
size_t *ret_buffer_free, const data_set_t *ds,
const value_list_t *vl, int store_rates,
char const *const *http_attrs,
- size_t http_attrs_num, int data_ttl);
+ size_t http_attrs_num, int data_ttl,
+ char const *metrics_prefix);
int format_kairosdb_finalize(char *buffer, size_t *ret_buffer_fill,
size_t *ret_buffer_free);
* When a value above this range is added, Histogram's range is increased by
* increasing the bin width (note that number of bins remains always at 1000).
* This operation of increasing bin width is little expensive as each bin need
-* to be visited to update it's count. To reduce frequent change of bin width,
+* to be visited to update its count. To reduce frequent change of bin width,
* new bin width will be the next nearest power of 2. Example: 2, 4, 8, 16, 32,
* 64, 128, 256, 512, 1024, 2048, 5086, ...
*
status = latency_config_add_percentile(conf, child, plugin);
else if (strcasecmp("Bucket", child->key) == 0)
status = latency_config_add_bucket(conf, child, plugin);
+ else if (strcasecmp("BucketType", child->key) == 0)
+ status = cf_util_get_string(child, &conf->bucket_type);
else
WARNING("%s plugin: \"%s\" is not a valid option within a \"%s\" block.",
plugin, child->key, ci->key);
return ENOMEM;
}
+ if (src.bucket_type != NULL) {
+ dst->bucket_type = strdup(src.bucket_type);
+ if (dst->bucket_type == NULL) {
+ latency_config_free(*dst);
+ return ENOMEM;
+ }
+ }
+
memmove(dst->percentile, src.percentile,
dst->percentile_num * sizeof(*dst->percentile));
memmove(dst->buckets, src.buckets, dst->buckets_num * sizeof(*dst->buckets));
void latency_config_free(latency_config_t conf) {
sfree(conf.percentile);
sfree(conf.buckets);
+ sfree(conf.bucket_type);
} /* void latency_config_free */
latency_bucket_t *buckets;
size_t buckets_num;
+ char *bucket_type;
/*
_Bool lower;
#define DBL_PRECISION 1e-6
-#include "common.h" /* for STATIC_ARRAY_SIZE */
#include "collectd.h"
+#include "common.h" /* for STATIC_ARRAY_SIZE */
#include "testing.h"
#include "utils_latency.h"
CHECK_NOT_NULL(l = latency_counter_create());
for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
- printf("# case %zu: DOUBLE_TO_CDTIME_T(%g) = %" PRIu64 "\n", i,
+ printf("# case %" PRIsz ": DOUBLE_TO_CDTIME_T(%g) = %" PRIu64 "\n", i,
cases[i].val, DOUBLE_TO_CDTIME_T(cases[i].val));
latency_counter_add(l, DOUBLE_TO_CDTIME_T(cases[i].val));
* GCC will complain about the macro definition. */
#define DONT_POISON_SPRINTF_YET
-#include "utils_lua.h"
#include "common.h"
+#include "utils_lua.h"
static int ltoc_values(lua_State *L, /* {{{ */
const data_set_t *ds, value_t *ret_values) {
} /* while (lua_next) */
if (i != ds->ds_num) {
- WARNING("ltoc_values: invalid size for datasource \"%s\": expected %zu, "
- "got %zu",
+ WARNING("ltoc_values: invalid size for datasource \"%s\": expected %" PRIsz
+ ", got %" PRIsz,
ds->type, ds->ds_num, i);
return -1;
}
/* Reset GAUGE metrics only and except GAUGE_PERSIST. */
if ((mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE) &&
!(mv->ds_type & UTILS_MATCH_CF_GAUGE_PERSIST)) {
- mv->value.gauge = NAN;
+ mv->value.gauge = (mv->ds_type & UTILS_MATCH_CF_GAUGE_INC) ? 0 : NAN;
mv->values_num = 0;
}
} /* }}} void match_value_reset */
struct tabmntent *mntlist;
if (listmntent(&mntlist, COLLECTD_MNTTAB, NULL, NULL) < 0) {
#if COLLECT_DEBUG
- char errbuf[1024];
- DEBUG("utils_mount: calling listmntent() failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ DEBUG("utils_mount: calling listmntent() failed: %s", STRERRNO);
#endif /* COLLECT_DEBUG */
}
/* Get the number of mounted file systems */
if ((bufsize = CMD_STATFS(NULL, 0, FLAGS_STATFS)) < 1) {
#if COLLECT_DEBUG
- char errbuf[1024];
- DEBUG("utils_mount: getv?fsstat failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ DEBUG("utils_mount: getv?fsstat failed: %s", STRERRNO);
#endif /* COLLECT_DEBUG */
return NULL;
}
if ((num = CMD_STATFS(buf, bufsize * sizeof(STRUCT_STATFS), FLAGS_STATFS)) <
1) {
#if COLLECT_DEBUG
- char errbuf[1024];
- DEBUG("utils_mount: getv?fsstat failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ DEBUG("utils_mount: getv?fsstat failed: %s", STRERRNO);
#endif /* COLLECT_DEBUG */
free(buf);
return NULL;
DEBUG("utils_mount: (void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
if ((fp = fopen(COLLECTD_MNTTAB, "r")) == NULL) {
- char errbuf[1024];
- ERROR("fopen (%s): %s", COLLECTD_MNTTAB,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("fopen (%s): %s", COLLECTD_MNTTAB, STRERRNO);
return NULL;
}
return first;
} /* static cu_mount_t *cu_mount_gen_getmntent (void) */
- /* #endif HAVE_TWO_GETMNTENT || HAVE_GEN_GETMNTENT || HAVE_SUN_GETMNTENT */
#elif HAVE_SEQ_GETMNTENT
#warn "This version of `getmntent' hat not yet been implemented!"
DEBUG("utils_mount: (void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
if ((fp = setmntent(COLLECTD_MNTTAB, "r")) == NULL) {
- char errbuf[1024];
- ERROR("setmntent (%s): %s", COLLECTD_MNTTAB,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("setmntent (%s): %s", COLLECTD_MNTTAB, STRERRNO);
return NULL;
}
DEBUG("utils_mount: (void); COLLECTD_MNTTAB = %s", COLLECTD_MNTTAB);
if ((fp = setmntent(COLLECTD_MNTTAB, "r")) == NULL) {
- char errbuf[1024];
- ERROR("setmntent (%s): %s", COLLECTD_MNTTAB,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("setmntent (%s): %s", COLLECTD_MNTTAB, STRERRNO);
return NULL;
}
#include "testing.h"
#include "utils_mount.h"
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#if HAVE_LIBKSTAT
kstat_ctl_t *kc;
#endif /* HAVE_LIBKSTAT */
#define OVS_DB_POLL_READ_BLOCK_SIZE 512 /* read block size (bytes) */
#define OVS_DB_DEFAULT_DB_NAME "Open_vSwitch"
+#define OVS_DB_EVENT_NONE 0
#define OVS_DB_EVENT_TIMEOUT 5 /* event thread timeout (sec) */
#define OVS_DB_EVENT_TERMINATE 1
#define OVS_DB_EVENT_CONN_ESTABLISHED 2
/* Remove all callbacks form OVS DB object */
static void ovs_db_callback_remove_all(ovs_db_t *pdb) {
pthread_mutex_lock(&pdb->mutex);
- for (ovs_callback_t *del_cb = pdb->remote_cb; pdb->remote_cb;
- del_cb = pdb->remote_cb) {
+ while (pdb->remote_cb != NULL) {
+ ovs_callback_t *del_cb = pdb->remote_cb;
pdb->remote_cb = del_cb->next;
- free(del_cb);
+ sfree(del_cb);
}
- pdb->remote_cb = NULL;
pthread_mutex_unlock(&pdb->mutex);
}
return -1;
sstrncpy(sjson, data, len + 1);
- OVS_DEBUG("[len=%zu] %s", len, sjson);
+ OVS_DEBUG("[len=%" PRIsz "] %s", len, sjson);
/* parse json data */
jnode = yajl_tree_parse(sjson, yajl_errbuf, sizeof(yajl_errbuf));
}
/* try to connect to the server */
for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) {
- char errbuff[OVS_ERROR_BUFF_SIZE];
int sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock < 0) {
- sstrerror(errno, errbuff, sizeof(errbuff));
- OVS_DEBUG("socket(): %s", errbuff);
+ OVS_DEBUG("socket(): %s", STRERRNO);
continue;
}
if (connect(sock, rp->ai_addr, rp->ai_addrlen) < 0) {
close(sock);
- sstrerror(errno, errbuff, sizeof(errbuff));
- OVS_DEBUG("connect(): %s [family=%d]", errbuff, rp->ai_family);
+ OVS_DEBUG("connect(): %s [family=%d]", STRERRNO, rp->ai_family);
} else {
/* send notification to event thread */
- ovs_db_event_post(pdb, OVS_DB_EVENT_CONN_ESTABLISHED);
pdb->sock = sock;
+ ovs_db_event_post(pdb, OVS_DB_EVENT_CONN_ESTABLISHED);
break;
}
}
/* poll data */
while (ovs_db_poll_is_running(pdb)) {
- char errbuff[OVS_ERROR_BUFF_SIZE];
poll_fd.fd = pdb->sock;
int poll_ret = poll(&poll_fd, 1, /* ms */ OVS_DB_POLL_TIMEOUT * 1000);
if (poll_ret < 0) {
- sstrerror(errno, errbuff, sizeof(errbuff));
- OVS_ERROR("poll(): %s", errbuff);
+ OVS_ERROR("poll(): %s", STRERRNO);
break;
} else if (poll_ret == 0) {
OVS_DEBUG("poll(): timeout");
char buff[OVS_DB_POLL_READ_BLOCK_SIZE];
ssize_t nbytes = recv(poll_fd.fd, buff, sizeof(buff), 0);
if (nbytes < 0) {
- sstrerror(errno, errbuff, sizeof(errbuff));
- OVS_ERROR("recv(): %s", errbuff);
+ OVS_ERROR("recv(): %s", STRERRNO);
/* read error? Try to reconnect */
close(poll_fd.fd);
continue;
ts.tv_sec += (OVS_DB_EVENT_TIMEOUT);
int ret = pthread_cond_timedwait(&pdb->event_thread.cond,
&pdb->event_thread.mutex, &ts);
- if (!ret) {
+ if (!ret || ret == ETIMEDOUT) {
/* handle the event */
OVS_DEBUG("handle event %d", pdb->event_thread.value);
switch (pdb->event_thread.value) {
case OVS_DB_EVENT_CONN_ESTABLISHED:
if (pdb->cb.post_conn_init)
pdb->cb.post_conn_init(pdb);
+ /* reset event */
+ pdb->event_thread.value = OVS_DB_EVENT_NONE;
break;
case OVS_DB_EVENT_CONN_TERMINATED:
if (pdb->cb.post_conn_terminate)
pdb->cb.post_conn_terminate();
+ /* reset event */
+ pdb->event_thread.value = OVS_DB_EVENT_NONE;
+ break;
+ case OVS_DB_EVENT_NONE:
+ /* wait timeout */
+ OVS_DEBUG("no event received (timeout)");
break;
default:
OVS_DEBUG("unknown event received");
break;
}
- } else if (ret == ETIMEDOUT) {
- /* wait timeout */
- OVS_DEBUG("no event received (timeout)");
- continue;
} else {
/* unexpected error */
OVS_ERROR("pthread_cond_timedwait() failed");
/* Initialize EVENT thread */
static int ovs_db_event_thread_init(ovs_db_t *pdb) {
- pdb->event_thread.tid = (pthread_t)-1;
+ pdb->event_thread.tid = (pthread_t){0};
/* init event thread condition variable */
if (pthread_cond_init(&pdb->event_thread.cond, NULL)) {
return -1;
return 0;
}
-/* Destroy EVENT thread */
-static int ovs_db_event_thread_destroy(ovs_db_t *pdb) {
- if (pdb->event_thread.tid == (pthread_t)-1)
- /* already destroyed */
+/* Terminate EVENT thread */
+static int ovs_db_event_thread_terminate(ovs_db_t *pdb) {
+ if (pthread_equal(pdb->event_thread.tid, (pthread_t){0})) {
+ /* already terminated */
return 0;
+ }
ovs_db_event_post(pdb, OVS_DB_EVENT_TERMINATE);
if (pthread_join(pdb->event_thread.tid, NULL) != 0)
return -1;
* performs some task (handles event) and releases it when
* while sleeping. Thus, if event thread exits, the mutex
* remains locked */
+ pdb->event_thread.tid = (pthread_t){0};
pthread_mutex_unlock(&pdb->event_thread.mutex);
+ return 0;
+}
+
+/* Destroy EVENT thread private data */
+static void ovs_db_event_thread_data_destroy(ovs_db_t *pdb) {
+ /* destroy mutex */
pthread_mutex_destroy(&pdb->event_thread.mutex);
pthread_cond_destroy(&pdb->event_thread.cond);
- pdb->event_thread.tid = (pthread_t)-1;
- return 0;
}
/* Initialize POLL thread */
static int ovs_db_poll_thread_init(ovs_db_t *pdb) {
- pdb->poll_thread.tid = (pthread_t)-1;
+ pdb->poll_thread.tid = (pthread_t){0};
/* init event thread mutex */
if (pthread_mutex_init(&pdb->poll_thread.mutex, NULL)) {
return -1;
}
/* Destroy POLL thread */
+/* XXX: Must hold pdb->mutex when calling! */
static int ovs_db_poll_thread_destroy(ovs_db_t *pdb) {
- if (pdb->poll_thread.tid == (pthread_t)-1)
+ if (pthread_equal(pdb->poll_thread.tid, (pthread_t){0})) {
/* already destroyed */
return 0;
+ }
/* change thread state */
pthread_mutex_lock(&pdb->poll_thread.mutex);
pdb->poll_thread.state = OVS_DB_POLL_STATE_EXITING;
if (pthread_join(pdb->poll_thread.tid, NULL) != 0)
return -1;
pthread_mutex_destroy(&pdb->poll_thread.mutex);
- pdb->poll_thread.tid = (pthread_t)-1;
+ pdb->poll_thread.tid = (pthread_t){0};
return 0;
}
ovs_db_t *ovs_db_init(const char *node, const char *service,
const char *unix_path, ovs_db_callback_t *cb) {
+ int ret;
+
/* sanity check */
if (node == NULL || service == NULL || unix_path == NULL)
return NULL;
/* allocate db data & fill it */
- ovs_db_t *pdb = pdb = calloc(1, sizeof(*pdb));
+ ovs_db_t *pdb = calloc(1, sizeof(*pdb));
if (pdb == NULL)
return NULL;
+ pdb->sock = -1;
/* store the OVS DB address */
sstrncpy(pdb->node, node, sizeof(pdb->node));
/* init event thread */
if (ovs_db_event_thread_init(pdb) < 0) {
- ovs_db_destroy(pdb);
- return NULL;
+ ret = ovs_db_destroy(pdb);
+ if (ret > 0)
+ goto failure;
}
/* init polling thread */
- pdb->sock = -1;
if (ovs_db_poll_thread_init(pdb) < 0) {
- ovs_db_destroy(pdb);
- return NULL;
+ ret = ovs_db_destroy(pdb);
+ if (ret > 0) {
+ ovs_db_event_thread_data_destroy(pdb);
+ goto failure;
+ }
}
return pdb;
+
+failure:
+ pthread_mutex_destroy(&pdb->mutex);
+ sfree(pdb);
+ return NULL;
}
int ovs_db_send_request(ovs_db_t *pdb, const char *method, const char *params,
if (pdb == NULL)
return -1;
+ /* stop event thread */
+ if (ovs_db_event_thread_terminate(pdb) < 0) {
+ OVS_ERROR("stop event thread failed");
+ ovs_db_ret = -1;
+ }
+
/* try to lock the structure before releasing */
if ((ret = pthread_mutex_lock(&pdb->mutex))) {
OVS_ERROR("pthread_mutex_lock() DB mutex lock failed (%d)", ret);
- return -1;
+ return ret;
}
- /* stop poll thread */
- if (ovs_db_event_thread_destroy(pdb) < 0) {
+ /* stop poll thread and destroy thread's private data */
+ if (ovs_db_poll_thread_destroy(pdb) < 0) {
OVS_ERROR("destroy poll thread failed");
- ovs_db_ret = (-1);
+ ovs_db_ret = -1;
}
- /* stop event thread */
- if (ovs_db_poll_thread_destroy(pdb) < 0) {
- OVS_ERROR("stop event thread failed");
- ovs_db_ret = (-1);
- }
+ /* destroy event thread private data */
+ ovs_db_event_thread_data_destroy(pdb);
+
+ pthread_mutex_unlock(&pdb->mutex);
/* unsubscribe callbacks */
ovs_db_callback_remove_all(pdb);
close(pdb->sock);
/* release DB handler */
- pthread_mutex_unlock(&pdb->mutex);
pthread_mutex_destroy(&pdb->mutex);
sfree(pdb);
return ovs_db_ret;
/* check first element of the array */
str_val = YAJL_GET_STRING(array_values[0]);
- if (strcmp("map", str_val) != 0)
+ if (str_val == NULL || strcmp("map", str_val) != 0)
return NULL;
/* try to find map value by map key */
+ if (YAJL_GET_ARRAY(array_values[1]) == NULL)
+ return NULL;
+
map_len = YAJL_GET_ARRAY(array_values[1])->len;
map_values = YAJL_GET_ARRAY(array_values[1])->values;
for (size_t i = 0; i < map_len; i++) {
/* check YAJL array */
- if (!YAJL_IS_ARRAY(map_values[i]))
+ if (!YAJL_IS_ARRAY(map_values[i]) || YAJL_GET_ARRAY(map_values[i]) == NULL)
break;
/* check a database pair value (2-element, first one represents a key
/* return map value if given key equals map key */
str_val = YAJL_GET_STRING(array_values[0]);
- if (strcmp(key, str_val) == 0)
+ if (str_val != NULL && strcmp(key, str_val) == 0)
return array_values[1];
}
return NULL;
ds_def = calloc(ds->ds_num, sizeof(*ds_def));
if (ds_def == NULL) {
- char errbuf[1024];
- ERROR("rrdtool plugin: calloc failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("rrdtool plugin: calloc failed: %s", STRERRNO);
return -1;
}
status = rename(tmpfile, args->filename);
if (status != 0) {
- char errbuf[1024];
ERROR("srrd_create_thread: rename (\"%s\", \"%s\") failed: %s", tmpfile,
- args->filename, sstrerror(errno, errbuf, sizeof(errbuf)));
+ args->filename, STRERRNO);
unlink(tmpfile);
unlock_file(args->filename);
srrd_create_args_destroy(args);
status = pthread_create(&thread, &attr, srrd_create_thread, args);
if (status != 0) {
- char errbuf[1024];
- ERROR("srrd_create_async: pthread_create failed: %s",
- sstrerror(status, errbuf, sizeof(errbuf)));
+ ERROR("srrd_create_async: pthread_create failed: %s", STRERROR(status));
pthread_attr_destroy(&attr);
srrd_create_args_destroy(args);
return status;
argc = ds_num + rra_num;
if ((argv = malloc(sizeof(*argv) * (argc + 1))) == NULL) {
- char errbuf[1024];
- ERROR("cu_rrd_create_file failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("cu_rrd_create_file failed: %s", STRERRNO);
rra_free(rra_num, rra_def);
ds_free(ds_num, ds_def);
return -1;
status = stat(obj->file, &stat_buf);
if (status != 0) {
- char errbuf[1024];
- ERROR("utils_tail: stat (%s) failed: %s", obj->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("utils_tail: stat (%s) failed: %s", obj->file, STRERRNO);
return -1;
}
INFO("utils_tail: File `%s' was truncated.", obj->file);
status = fseek(obj->fh, 0, SEEK_SET);
if (status != 0) {
- char errbuf[1024];
- ERROR("utils_tail: fseek (%s) failed: %s", obj->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("utils_tail: fseek (%s) failed: %s", obj->file, STRERRNO);
fclose(obj->fh);
obj->fh = NULL;
return -1;
fh = fopen(obj->file, "r");
if (fh == NULL) {
- char errbuf[1024];
- ERROR("utils_tail: fopen (%s) failed: %s", obj->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("utils_tail: fopen (%s) failed: %s", obj->file, STRERRNO);
return -1;
}
if (seek_end != 0) {
status = fseek(fh, 0, SEEK_END);
if (status != 0) {
- char errbuf[1024];
- ERROR("utils_tail: fseek (%s) failed: %s", obj->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("utils_tail: fseek (%s) failed: %s", obj->file, STRERRNO);
fclose(fh);
return -1;
}
}
if (ferror(obj->fh) != 0) {
- char errbuf[1024];
WARNING("utils_tail: fgets (%s) returned an error: %s", obj->file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
fclose(obj->fh);
obj->fh = NULL;
return -1;
if (match_value == NULL)
return -1;
- sstrncpy(vl.host, hostname_g, sizeof(vl.host));
sstrncpy(vl.plugin, data->plugin, sizeof(vl.plugin));
sstrncpy(vl.plugin_instance, data->plugin_instance,
sizeof(vl.plugin_instance));
sstrncpy(vl.type, data->type, sizeof(vl.type));
for (size_t i = 0; i < data->latency_config.percentile_num; i++) {
if (strlen(data->type_instance) != 0)
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%.0f",
+ snprintf(vl.type_instance, sizeof(vl.type_instance), "%.50s-%.5g",
data->type_instance, data->latency_config.percentile[i]);
else
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%.0f",
+ snprintf(vl.type_instance, sizeof(vl.type_instance), "%.5g",
data->latency_config.percentile[i]);
vl.values = &(value_t){
}
/* Submit buckets */
- sstrncpy(vl.type, "bucket", sizeof(vl.type));
+ if (data->latency_config.bucket_type != NULL)
+ sstrncpy(vl.type, data->latency_config.bucket_type, sizeof(vl.type));
+ else
+ sstrncpy(vl.type, "bucket", sizeof(vl.type));
+
for (size_t i = 0; i < data->latency_config.buckets_num; i++) {
latency_bucket_t bucket = data->latency_config.buckets[i];
bucket.upper_bound ? CDTIME_T_TO_DOUBLE(bucket.upper_bound) : INFINITY;
if (strlen(data->type_instance) != 0)
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s-%g_%g",
+ snprintf(vl.type_instance, sizeof(vl.type_instance), "%.50s-%.50s-%g_%g",
data->type, data->type_instance, lower_bound, upper_bound);
else
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%g_%g",
+ snprintf(vl.type_instance, sizeof(vl.type_instance), "%.50s-%g_%g",
data->type, lower_bound, upper_bound);
vl.values = &(value_t){
--- /dev/null
+/**
+ * collectd - src/utils_taskstats.c
+ * Copyright (C) 2017 Florian octo Forster
+ *
+ * ISC License (ISC)
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ */
+
+#include "collectd.h"
+#include "utils_taskstats.h"
+
+#include "common.h"
+#include "plugin.h"
+#include "utils_time.h"
+
+#include <libmnl/libmnl.h>
+#include <linux/genetlink.h>
+#include <linux/taskstats.h>
+
+struct ts_s {
+ struct mnl_socket *nl;
+ pid_t pid;
+ uint32_t seq;
+ uint16_t genl_id_taskstats;
+ unsigned int port_id;
+};
+
+/* nlmsg_errno returns the errno encoded in nlh or zero if not an error. */
+static int nlmsg_errno(struct nlmsghdr *nlh, size_t sz) {
+ if (!mnl_nlmsg_ok(nlh, (int)sz)) {
+ ERROR("utils_taskstats: mnl_nlmsg_ok failed.");
+ return EPROTO;
+ }
+
+ if (nlh->nlmsg_type != NLMSG_ERROR) {
+ return 0;
+ }
+
+ struct nlmsgerr *nlerr = mnl_nlmsg_get_payload(nlh);
+ /* (struct nlmsgerr).error holds a negative errno. */
+ return nlerr->error * (-1);
+}
+
+static int get_taskstats_attr_cb(const struct nlattr *attr, void *data) {
+ struct taskstats *ret_taskstats = data;
+
+ uint16_t type = mnl_attr_get_type(attr);
+ switch (type) {
+ case TASKSTATS_TYPE_STATS:
+ if (mnl_attr_get_payload_len(attr) != sizeof(*ret_taskstats)) {
+ ERROR("utils_taskstats: mnl_attr_get_payload_len(attr) = %" PRIu32
+ ", want %zu",
+ mnl_attr_get_payload_len(attr), sizeof(*ret_taskstats));
+ return MNL_CB_ERROR;
+ }
+ struct taskstats *ts = mnl_attr_get_payload(attr);
+ memmove(ret_taskstats, ts, sizeof(*ret_taskstats));
+ return MNL_CB_OK;
+
+ case TASKSTATS_TYPE_AGGR_PID: /* fall through */
+ case TASKSTATS_TYPE_AGGR_TGID:
+ return mnl_attr_parse_nested(attr, get_taskstats_attr_cb, ret_taskstats);
+
+ case TASKSTATS_TYPE_PID: /* fall through */
+ case TASKSTATS_TYPE_TGID:
+ /* ignore */
+ return MNL_CB_OK;
+
+ default:
+ DEBUG("utils_taskstats: unknown attribute %" PRIu16
+ ", want one of TASKSTATS_TYPE_AGGR_PID/TGID, TASKSTATS_TYPE_STATS",
+ type);
+ }
+ return MNL_CB_OK;
+}
+
+static int get_taskstats_msg_cb(const struct nlmsghdr *nlh, void *data) {
+ return mnl_attr_parse(nlh, sizeof(struct genlmsghdr), get_taskstats_attr_cb,
+ data);
+}
+
+static int get_taskstats(ts_t *ts, uint32_t tgid,
+ struct taskstats *ret_taskstats) {
+ char buffer[MNL_SOCKET_BUFFER_SIZE];
+ uint32_t seq = ts->seq++;
+
+ struct nlmsghdr *nlh = mnl_nlmsg_put_header(buffer);
+ *nlh = (struct nlmsghdr){
+ .nlmsg_len = nlh->nlmsg_len,
+ .nlmsg_type = ts->genl_id_taskstats,
+ .nlmsg_flags = NLM_F_REQUEST,
+ .nlmsg_seq = seq,
+ .nlmsg_pid = ts->pid,
+ };
+
+ struct genlmsghdr *genh = mnl_nlmsg_put_extra_header(nlh, sizeof(*genh));
+ *genh = (struct genlmsghdr){
+ .cmd = TASKSTATS_CMD_GET,
+ .version = TASKSTATS_GENL_VERSION, // or TASKSTATS_VERSION?
+ };
+
+ // mnl_attr_put_u32(nlh, TASKSTATS_CMD_ATTR_PID, tgid);
+ mnl_attr_put_u32(nlh, TASKSTATS_CMD_ATTR_TGID, tgid);
+
+ if (mnl_socket_sendto(ts->nl, nlh, nlh->nlmsg_len) < 0) {
+ int status = errno;
+ ERROR("utils_taskstats: mnl_socket_sendto() = %s", STRERROR(status));
+ return status;
+ }
+
+ int status = mnl_socket_recvfrom(ts->nl, buffer, sizeof(buffer));
+ if (status < 0) {
+ status = errno;
+ ERROR("utils_taskstats: mnl_socket_recvfrom() = %s", STRERROR(status));
+ return status;
+ } else if (status == 0) {
+ ERROR("utils_taskstats: mnl_socket_recvfrom() = 0");
+ return ECONNABORTED;
+ }
+ size_t buffer_size = (size_t)status;
+
+ if ((status = nlmsg_errno((void *)buffer, buffer_size)) != 0) {
+ ERROR("utils_taskstats: TASKSTATS_CMD_GET(TASKSTATS_CMD_ATTR_TGID = "
+ "%" PRIu32 ") = %s",
+ (uint32_t)tgid, STRERROR(status));
+ return status;
+ }
+
+ status = mnl_cb_run(buffer, buffer_size, seq, ts->port_id,
+ get_taskstats_msg_cb, ret_taskstats);
+ if (status < MNL_CB_STOP) {
+ ERROR("utils_taskstats: Parsing message failed.");
+ return EPROTO;
+ }
+
+ return 0;
+}
+
+static int get_family_id_attr_cb(const struct nlattr *attr, void *data) {
+ uint16_t type = mnl_attr_get_type(attr);
+ if (type != CTRL_ATTR_FAMILY_ID) {
+ return MNL_CB_OK;
+ }
+
+ if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
+ ERROR("mnl_attr_validate() = %s", STRERRNO);
+ return MNL_CB_ERROR;
+ }
+
+ uint16_t *ret_family_id = data;
+ *ret_family_id = mnl_attr_get_u16(attr);
+ return MNL_CB_STOP;
+}
+
+static int get_family_id_msg_cb(const struct nlmsghdr *nlh, void *data) {
+ return mnl_attr_parse(nlh, sizeof(struct genlmsghdr), get_family_id_attr_cb,
+ data);
+}
+
+/* get_family_id initializes ts->genl_id_taskstats. Returns 0 on success and
+ * an error code otherwise. */
+static int get_family_id(ts_t *ts) {
+ char buffer[MNL_SOCKET_BUFFER_SIZE];
+ uint32_t seq = ts->seq++;
+
+ struct nlmsghdr *nlh = mnl_nlmsg_put_header(buffer);
+ *nlh = (struct nlmsghdr){
+ .nlmsg_len = nlh->nlmsg_len,
+ .nlmsg_type = GENL_ID_CTRL,
+ .nlmsg_flags = NLM_F_REQUEST,
+ .nlmsg_seq = seq,
+ .nlmsg_pid = ts->pid,
+ };
+
+ struct genlmsghdr *genh = mnl_nlmsg_put_extra_header(nlh, sizeof(*genh));
+ *genh = (struct genlmsghdr){
+ .cmd = CTRL_CMD_GETFAMILY, .version = 0x01,
+ };
+
+ mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TASKSTATS_GENL_NAME);
+
+ assert(genh->cmd == CTRL_CMD_GETFAMILY);
+ assert(genh->version == TASKSTATS_GENL_VERSION);
+
+ if (mnl_socket_sendto(ts->nl, nlh, nlh->nlmsg_len) < 0) {
+ int status = errno;
+ ERROR("utils_taskstats: mnl_socket_sendto() = %s", STRERROR(status));
+ return status;
+ }
+
+ ts->genl_id_taskstats = 0;
+ while (42) {
+ int status = mnl_socket_recvfrom(ts->nl, buffer, sizeof(buffer));
+ if (status < 0) {
+ status = errno;
+ ERROR("utils_taskstats: mnl_socket_recvfrom() = %s", STRERROR(status));
+ return status;
+ } else if (status == 0) {
+ break;
+ }
+ size_t buffer_size = (size_t)status;
+
+ if ((status = nlmsg_errno((void *)buffer, buffer_size)) != 0) {
+ ERROR("utils_taskstats: CTRL_CMD_GETFAMILY(\"%s\"): %s",
+ TASKSTATS_GENL_NAME, STRERROR(status));
+ return status;
+ }
+
+ status = mnl_cb_run(buffer, buffer_size, seq, ts->port_id,
+ get_family_id_msg_cb, &ts->genl_id_taskstats);
+ if (status < MNL_CB_STOP) {
+ ERROR("utils_taskstats: Parsing message failed.");
+ return EPROTO;
+ } else if (status == MNL_CB_STOP) {
+ break;
+ }
+ }
+
+ if (ts->genl_id_taskstats == 0) {
+ ERROR("utils_taskstats: Netlink communication succeeded, but "
+ "genl_id_taskstats is still zero.");
+ return ENOENT;
+ }
+
+ return 0;
+}
+
+void ts_destroy(ts_t *ts) {
+ if (ts == NULL) {
+ return;
+ }
+
+ if (ts->nl != NULL) {
+ mnl_socket_close(ts->nl);
+ ts->nl = NULL;
+ }
+
+ sfree(ts);
+}
+
+ts_t *ts_create(void) {
+ ts_t *ts = calloc(1, sizeof(*ts));
+ if (ts == NULL) {
+ ERROR("utils_taskstats: calloc failed: %s", STRERRNO);
+ return NULL;
+ }
+
+ if ((ts->nl = mnl_socket_open(NETLINK_GENERIC)) == NULL) {
+ ERROR("utils_taskstats: mnl_socket_open(NETLINK_GENERIC) = %s", STRERRNO);
+ ts_destroy(ts);
+ return NULL;
+ }
+
+ if (mnl_socket_bind(ts->nl, 0, MNL_SOCKET_AUTOPID) != 0) {
+ ERROR("utils_taskstats: mnl_socket_bind() = %s", STRERRNO);
+ ts_destroy(ts);
+ return NULL;
+ }
+
+ ts->pid = getpid();
+ ts->port_id = mnl_socket_get_portid(ts->nl);
+
+ int status = get_family_id(ts);
+ if (status != 0) {
+ ERROR("utils_taskstats: get_family_id() = %s", STRERROR(status));
+ ts_destroy(ts);
+ return NULL;
+ }
+
+ return ts;
+}
+
+int ts_delay_by_tgid(ts_t *ts, uint32_t tgid, ts_delay_t *out) {
+ if ((ts == NULL) || (out == NULL)) {
+ return EINVAL;
+ }
+
+ struct taskstats raw = {0};
+
+ int status = get_taskstats(ts, tgid, &raw);
+ if (status != 0) {
+ return status;
+ }
+
+ *out = (ts_delay_t){
+ .cpu_ns = raw.cpu_delay_total,
+ .blkio_ns = raw.blkio_delay_total,
+ .swapin_ns = raw.swapin_delay_total,
+ .freepages_ns = raw.freepages_delay_total,
+ };
+ return 0;
+}
--- /dev/null
+/**
+ * collectd - src/utils_taskstats.h
+ * Copyright (C) 2017 Florian octo Forster
+ *
+ * ISC License (ISC)
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Authors:
+ * Florian octo Forster <octo at collectd.org>
+ */
+
+#ifndef UTILS_TASKSTATS_H
+#define UTILS_TASKSTATS_H 1
+
+#include "collectd.h"
+
+#include "utils_time.h"
+
+struct ts_s;
+typedef struct ts_s ts_t;
+
+typedef struct {
+ uint64_t cpu_ns;
+ uint64_t blkio_ns;
+ uint64_t swapin_ns;
+ uint64_t freepages_ns;
+} ts_delay_t;
+
+ts_t *ts_create(void);
+void ts_destroy(ts_t *);
+
+/* ts_delay_by_tgid returns Linux delay accounting information for the task
+ * identified by tgid. Returns zero on success and an errno otherwise. */
+int ts_delay_by_tgid(ts_t *ts, uint32_t tgid, ts_delay_t *out);
+
+#endif /* UTILS_TASKSTATS_H */
#include "utils_avltree.h"
#include "utils_vl_lookup.h"
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
#if HAVE_LIBKSTAT
kstat_ctl_t *kc;
#endif /* HAVE_LIBKSTAT */
char *uuid = uuid_get_local();
if (uuid) {
- sstrncpy(hostname_g, uuid, DATA_MAX_NAME_LEN);
+ hostname_set(uuid);
sfree(uuid);
return 0;
}
* Jérôme Renard <jerome.renard at gmail.com>
* Marc Fournier <marc.fournier at camptocamp.com>
* Florian octo Forster <octo at collectd.org>
+ * Denes Matetelki <dmatetelki at varnish-software.com>
**/
#include "collectd.h"
#include "common.h"
#include "plugin.h"
-#if HAVE_VARNISH_V4
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
#include <vapi/vsc.h>
#include <vapi/vsm.h>
typedef struct VSC_C_main c_varnish_stats_t;
_Bool collect_sms;
#if HAVE_VARNISH_V2
_Bool collect_sm;
+#endif
+#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
_Bool collect_sma;
#endif
_Bool collect_struct;
_Bool collect_totals;
-#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
_Bool collect_uptime;
#endif
_Bool collect_vcl;
_Bool collect_workers;
-#if HAVE_VARNISH_V4
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
_Bool collect_vsm;
+ _Bool collect_lck;
+ _Bool collect_mempool;
+ _Bool collect_mgt;
+ _Bool collect_smf;
+ _Bool collect_vbe;
+ _Bool collect_mse;
#endif
};
typedef struct user_config_s user_config_t; /* }}} */
});
} /* }}} int varnish_submit_derive */
-#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
static int varnish_monitor(void *priv,
const struct VSC_point *const pt) /* {{{ */
{
uint64_t val;
const user_config_t *conf;
- const char *class;
const char *name;
if (pt == NULL)
conf = priv;
-#if HAVE_VARNISH_V4
- class = pt->section->fantom->type;
- name = pt->desc->name;
+#if HAVE_VARNISH_V5
+ char namebuff[DATA_MAX_NAME_LEN];
- if (strcmp(class, "MAIN") != 0)
+ char const *c = strrchr(pt->name, '.');
+ if (c == NULL) {
+ return EINVAL;
+ }
+ sstrncpy(namebuff, c + 1, sizeof(namebuff));
+ name = namebuff;
+
+#elif HAVE_VARNISH_V4
+ if (strcmp(pt->section->fantom->type, "MAIN") != 0)
return 0;
+ name = pt->desc->name;
#elif HAVE_VARNISH_V3
- class = pt->class;
- name = pt->name;
-
- if (strcmp(class, "") != 0)
+ if (strcmp(pt->class, "") != 0)
return 0;
+
+ name = pt->name;
#endif
val = *(const volatile uint64_t *)pt->ptr;
else if (strcmp(name, "client_req") == 0)
return varnish_submit_derive(conf->instance, "connections", "connections",
"received", val);
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ else if (strcmp(name, "client_req_400") == 0)
+ return varnish_submit_derive(conf->instance, "connections", "connections",
+ "error_400", val);
+ else if (strcmp(name, "client_req_417") == 0)
+ return varnish_submit_derive(conf->instance, "connections", "connections",
+ "error_417", val);
+#endif
}
#ifdef HAVE_VARNISH_V3
else if (strcmp(name, "esi_warnings") == 0)
return varnish_submit_derive(conf->instance, "esi", "total_operations",
"warning", val);
+ else if (strcmp(name, "esi_maxdepth") == 0)
+ return varnish_submit_derive(conf->instance, "esi", "total_operations",
+ "max_depth", val);
}
if (conf->collect_backend) {
else if (strcmp(name, "fetch_304") == 0)
return varnish_submit_derive(conf->instance, "fetch", "http_requests",
"no_body_304", val);
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ else if (strcmp(name, "fetch_no_thread") == 0)
+ return varnish_submit_derive(conf->instance, "fetch", "http_requests",
+ "no_thread", val);
+ else if (strcmp(name, "fetch_none") == 0)
+ return varnish_submit_derive(conf->instance, "fetch", "http_requests",
+ "none", val);
+ else if (strcmp(name, "busy_sleep") == 0)
+ return varnish_submit_derive(conf->instance, "fetch", "http_requests",
+ "busy_sleep", val);
+ else if (strcmp(name, "busy_wakeup") == 0)
+ return varnish_submit_derive(conf->instance, "fetch", "http_requests",
+ "busy_wakeup", val);
+#endif
}
if (conf->collect_hcb) {
else if (strcmp(name, "n_objoverflow") == 0)
return varnish_submit_derive(conf->instance, "objects", "total_objects",
"workspace_overflow", val);
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ else if (strcmp(name, "exp_mailed") == 0)
+ return varnish_submit_gauge(conf->instance, "struct", "objects",
+ "exp_mailed", val);
+ else if (strcmp(name, "exp_received") == 0)
+ return varnish_submit_gauge(conf->instance, "struct", "objects",
+ "exp_received", val);
+#endif
}
#if HAVE_VARNISH_V3
"duplicate", val);
}
#endif
-#if HAVE_VARNISH_V4
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
if (conf->collect_ban) {
if (strcmp(name, "bans") == 0)
return varnish_submit_derive(conf->instance, "ban", "total_operations",
else if (strcmp(name, "bans_dups") == 0)
return varnish_submit_derive(conf->instance, "ban", "total_operations",
"duplicate", val);
+ else if (strcmp(name, "bans_tested") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_operations",
+ "tested", val);
+ else if (strcmp(name, "bans_lurker_contention") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_operations",
+ "lurker_contention", val);
+ else if (strcmp(name, "bans_lurker_obj_killed") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_operations",
+ "lurker_obj_killed", val);
+ else if (strcmp(name, "bans_lurker_tested") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_operations",
+ "lurker_tested", val);
+ else if (strcmp(name, "bans_lurker_tests_tested") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_operations",
+ "lurker_tests_tested", val);
+ else if (strcmp(name, "bans_obj_killed") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_operations",
+ "obj_killed", val);
+ else if (strcmp(name, "bans_persisted_bytes") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_bytes",
+ "persisted_bytes", val);
+ else if (strcmp(name, "bans_persisted_fragmentation") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_bytes",
+ "persisted_fragmentation", val);
+ else if (strcmp(name, "bans_tests_tested") == 0)
+ return varnish_submit_derive(conf->instance, "ban", "total_operations",
+ "tests_tested", val);
}
#endif
else if (strcmp(name, "sess_herd") == 0)
return varnish_submit_derive(conf->instance, "session",
"total_operations", "herd", val);
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ else if (strcmp(name, "sess_closed_err") == 0)
+ return varnish_submit_derive(conf->instance, "session",
+ "total_operations", "closed_err", val);
+ else if (strcmp(name, "sess_dropped") == 0)
+ return varnish_submit_derive(conf->instance, "session",
+ "total_operations", "dropped_for_thread",
+ val);
+#endif
}
if (conf->collect_shm) {
else if (strcmp(name, "s_req_bodybytes") == 0)
return varnish_submit_derive(conf->instance, "totals", "total_bytes",
"req_body", val);
+ else if (strcmp(name, "s_req_protobytes") == 0)
+ return varnish_submit_derive(conf->instance, "totals", "total_bytes",
+ "req_proto", val);
else if (strcmp(name, "s_resp_hdrbytes") == 0)
return varnish_submit_derive(conf->instance, "totals", "total_bytes",
"resp_header", val);
else if (strcmp(name, "s_resp_bodybytes") == 0)
return varnish_submit_derive(conf->instance, "totals", "total_bytes",
"resp_body", val);
+ else if (strcmp(name, "s_resp_protobytes") == 0)
+ return varnish_submit_derive(conf->instance, "totals", "total_bytes",
+ "resp_proto", val);
else if (strcmp(name, "s_pipe_hdrbytes") == 0)
return varnish_submit_derive(conf->instance, "totals", "total_bytes",
"pipe_header", val);
return varnish_submit_derive(conf->instance, "workers", "total_threads",
"dropped", val);
else if (strcmp(name, "thread_queue_len") == 0)
- return varnish_submit_derive(conf->instance, "workers", "queue_length",
- "threads", val);
+ return varnish_submit_gauge(conf->instance, "workers", "queue_length",
+ "threads", val);
else if (strcmp(name, "n_wrk") == 0)
return varnish_submit_gauge(conf->instance, "workers", "threads",
"worker", val);
else if (strcmp(name, "n_wrk_lqueue") == 0)
return varnish_submit_derive(conf->instance, "workers", "total_requests",
"queue_length", val);
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ else if (strcmp(name, "pools") == 0)
+ return varnish_submit_gauge(conf->instance, "workers", "pools", "pools",
+ val);
+ else if (strcmp(name, "busy_killed") == 0)
+ return varnish_submit_derive(conf->instance, "workers", "http_requests",
+ "busy_killed", val);
+#endif
}
-#if HAVE_VARNISH_V4
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
if (conf->collect_vsm) {
if (strcmp(name, "vsm_free") == 0)
return varnish_submit_gauge(conf->instance, "vsm", "bytes", "free", val);
return varnish_submit_derive(conf->instance, "vsm", "total_bytes",
"overflowed", val);
}
+
+ if (conf->collect_vbe) {
+ /* @TODO figure out the collectd type for bitmap
+ if (strcmp(name, "happy") == 0)
+ return varnish_submit_derive(conf->instance, "vbe",
+ "bitmap", "happy_hprobes", val);
+ */
+ if (strcmp(name, "bereq_hdrbytes") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "bereq_hdrbytes", val);
+ else if (strcmp(name, "bereq_bodybytes") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "bereq_bodybytes", val);
+ else if (strcmp(name, "bereq_protobytes") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "bereq_protobytes", val);
+ else if (strcmp(name, "beresp_hdrbytes") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "beresp_hdrbytes", val);
+ else if (strcmp(name, "beresp_bodybytes") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "beresp_bodybytes", val);
+ else if (strcmp(name, "beresp_protobytes") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "beresp_protobytes", val);
+ else if (strcmp(name, "pipe_hdrbytes") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "pipe_hdrbytes", val);
+ else if (strcmp(name, "pipe_out") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "pipe_out", val);
+ else if (strcmp(name, "pipe_in") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "total_bytes",
+ "pipe_in", val);
+ else if (strcmp(name, "conn") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "connections",
+ "c_conns", val);
+ else if (strcmp(name, "req") == 0)
+ return varnish_submit_derive(conf->instance, "vbe", "http_requests",
+ "b_reqs", val);
+ }
+
+ /* All Stevedores support these counters */
+ if (conf->collect_sma || conf->collect_smf || conf->collect_mse) {
+
+ char category[4];
+ if (conf->collect_sma)
+ strncpy(category, "sma", 4);
+ else if (conf->collect_smf)
+ strncpy(category, "smf", 4);
+ else
+ strncpy(category, "mse", 4);
+
+ if (strcmp(name, "c_req") == 0)
+ return varnish_submit_derive(conf->instance, category, "total_operations",
+ "alloc_req", val);
+ else if (strcmp(name, "c_fail") == 0)
+ return varnish_submit_derive(conf->instance, category, "total_operations",
+ "alloc_fail", val);
+ else if (strcmp(name, "c_bytes") == 0)
+ return varnish_submit_derive(conf->instance, category, "total_bytes",
+ "bytes_allocated", val);
+ else if (strcmp(name, "c_freed") == 0)
+ return varnish_submit_derive(conf->instance, category, "total_bytes",
+ "bytes_freed", val);
+ else if (strcmp(name, "g_alloc") == 0)
+ return varnish_submit_derive(conf->instance, category, "total_operations",
+ "alloc_outstanding", val);
+ else if (strcmp(name, "g_bytes") == 0)
+ return varnish_submit_gauge(conf->instance, category, "bytes",
+ "bytes_outstanding", val);
+ else if (strcmp(name, "g_space") == 0)
+ return varnish_submit_gauge(conf->instance, category, "bytes",
+ "bytes_available", val);
+ }
+
+ /* No SMA specific counters */
+
+ if (conf->collect_smf) {
+ if (strcmp(name, "g_smf") == 0)
+ return varnish_submit_gauge(conf->instance, "smf", "objects",
+ "n_struct_smf", val);
+ else if (strcmp(name, "g_smf_frag") == 0)
+ return varnish_submit_gauge(conf->instance, "smf", "objects",
+ "n_small_free_smf", val);
+ else if (strcmp(name, "g_smf_large") == 0)
+ return varnish_submit_gauge(conf->instance, "smf", "objects",
+ "n_large_free_smf", val);
+ }
+
+ if (conf->collect_mgt) {
+ if (strcmp(name, "uptime") == 0)
+ return varnish_submit_gauge(conf->instance, "mgt", "uptime",
+ "mgt_proc_uptime", val);
+ else if (strcmp(name, "child_start") == 0)
+ return varnish_submit_derive(conf->instance, "mgt", "total_operations",
+ "child_start", val);
+ else if (strcmp(name, "child_exit") == 0)
+ return varnish_submit_derive(conf->instance, "mgt", "total_operations",
+ "child_exit", val);
+ else if (strcmp(name, "child_stop") == 0)
+ return varnish_submit_derive(conf->instance, "mgt", "total_operations",
+ "child_stop", val);
+ else if (strcmp(name, "child_died") == 0)
+ return varnish_submit_derive(conf->instance, "mgt", "total_operations",
+ "child_died", val);
+ else if (strcmp(name, "child_dump") == 0)
+ return varnish_submit_derive(conf->instance, "mgt", "total_operations",
+ "child_dump", val);
+ else if (strcmp(name, "child_panic") == 0)
+ return varnish_submit_derive(conf->instance, "mgt", "total_operations",
+ "child_panic", val);
+ }
+
+ if (conf->collect_lck) {
+ if (strcmp(name, "creat") == 0)
+ return varnish_submit_gauge(conf->instance, "lck", "objects", "created",
+ val);
+ else if (strcmp(name, "destroy") == 0)
+ return varnish_submit_gauge(conf->instance, "lck", "objects", "destroyed",
+ val);
+ else if (strcmp(name, "locks") == 0)
+ return varnish_submit_derive(conf->instance, "lck", "total_operations",
+ "lock_ops", val);
+ }
+
+ if (conf->collect_mempool) {
+ if (strcmp(name, "live") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "objects",
+ "in_use", val);
+ else if (strcmp(name, "pool") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "objects",
+ "in_pool", val);
+ else if (strcmp(name, "sz_wanted") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "bytes",
+ "size_requested", val);
+ else if (strcmp(name, "sz_actual") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "bytes",
+ "size_allocated", val);
+ else if (strcmp(name, "allocs") == 0)
+ return varnish_submit_derive(conf->instance, "mempool",
+ "total_operations", "allocations", val);
+ else if (strcmp(name, "frees") == 0)
+ return varnish_submit_derive(conf->instance, "mempool",
+ "total_operations", "frees", val);
+ else if (strcmp(name, "recycle") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "objects",
+ "recycled", val);
+ else if (strcmp(name, "timeout") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "objects",
+ "timed_out", val);
+ else if (strcmp(name, "toosmall") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "objects",
+ "too_small", val);
+ else if (strcmp(name, "surplus") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "objects",
+ "surplus", val);
+ else if (strcmp(name, "randry") == 0)
+ return varnish_submit_gauge(conf->instance, "mempool", "objects",
+ "ran_dry", val);
+ }
+
+ if (conf->collect_mse) {
+ if (strcmp(name, "c_full") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_operations",
+ "full_allocs", val);
+ else if (strcmp(name, "c_truncated") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_operations",
+ "truncated_allocs", val);
+ else if (strcmp(name, "c_expanded") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_operations",
+ "expanded_allocs", val);
+ else if (strcmp(name, "c_failed") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_operations",
+ "failed_allocs", val);
+ else if (strcmp(name, "c_bytes") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_bytes",
+ "bytes_allocated", val);
+ else if (strcmp(name, "c_freed") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_bytes",
+ "bytes_freed", val);
+ else if (strcmp(name, "g_fo_alloc") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_operations",
+ "fo_allocs_outstanding", val);
+ else if (strcmp(name, "g_fo_bytes") == 0)
+ return varnish_submit_gauge(conf->instance, "mse", "bytes",
+ "fo_bytes_outstanding", val);
+ else if (strcmp(name, "g_membuf_alloc") == 0)
+ return varnish_submit_gauge(conf->instance, "mse", "objects",
+ "membufs_allocated", val);
+ else if (strcmp(name, "g_membuf_inuse") == 0)
+ return varnish_submit_gauge(conf->instance, "mse", "objects",
+ "membufs_inuse", val);
+ else if (strcmp(name, "g_bans_bytes") == 0)
+ return varnish_submit_gauge(conf->instance, "mse", "bytes",
+ "persisted_banspace_used", val);
+ else if (strcmp(name, "g_bans_space") == 0)
+ return varnish_submit_gauge(conf->instance, "mse", "bytes",
+ "persisted_banspace_available", val);
+ else if (strcmp(name, "g_bans_persisted") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_operations",
+ "bans_persisted", val);
+ else if (strcmp(name, "g_bans_lost") == 0)
+ return varnish_submit_derive(conf->instance, "mse", "total_operations",
+ "bans_lost", val);
+
+ /* mse seg */
+ else if (strcmp(name, "g_journal_bytes") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_reg", "bytes",
+ "journal_bytes_used", val);
+ else if (strcmp(name, "g_journal_space") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_reg", "bytes",
+ "journal_bytes_free", val);
+
+ /* mse segagg */
+ else if (strcmp(name, "g_bigspace") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_segagg", "bytes",
+ "big_extents_bytes_available", val);
+ else if (strcmp(name, "g_extfree") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_segagg", "objects",
+ "free_extents", val);
+ else if (strcmp(name, "g_sparenode") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_segagg", "objects",
+ "spare_nodes_available", val);
+ else if (strcmp(name, "g_objnode") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_segagg", "objects",
+ "object_nodes_in_use", val);
+ else if (strcmp(name, "g_extnode") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_segagg", "objects",
+ "extent_nodes_in_use", val);
+ else if (strcmp(name, "g_bigextfree") == 0)
+ return varnish_submit_gauge(conf->instance, "mse_segagg", "objects",
+ "free_big_extents", val);
+ else if (strcmp(name, "c_pruneloop") == 0)
+ return varnish_submit_derive(conf->instance, "mse_segagg",
+ "total_operations", "prune_loops", val);
+ else if (strcmp(name, "c_pruned") == 0)
+ return varnish_submit_derive(conf->instance, "mse_segagg",
+ "total_objects", "pruned_objects", val);
+ else if (strcmp(name, "c_spared") == 0)
+ return varnish_submit_derive(conf->instance, "mse_segagg",
+ "total_operations", "spared_objects", val);
+ else if (strcmp(name, "c_skipped") == 0)
+ return varnish_submit_derive(conf->instance, "mse_segagg",
+ "total_operations", "missed_objects", val);
+ else if (strcmp(name, "c_nuked") == 0)
+ return varnish_submit_derive(conf->instance, "mse_segagg",
+ "total_operations", "nuked_objects", val);
+ else if (strcmp(name, "c_sniped") == 0)
+ return varnish_submit_derive(conf->instance, "mse_segagg",
+ "total_operations", "sniped_objects", val);
+ }
+
#endif
return 0;
} /* }}} void varnish_monitor */
#endif
-#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
static int varnish_read(user_data_t *ud) /* {{{ */
{
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
struct VSM_data *vd;
- const c_varnish_stats_t *stats;
_Bool ok;
+ const c_varnish_stats_t *stats;
+#elif HAVE_VARNISH_V5
+ struct vsm *vd;
+ struct vsc *vsc;
+ int vsm_status;
+#endif
user_config_t *conf;
conf = ud->data;
vd = VSM_New();
+
+#if HAVE_VARNISH_V5
+ vsc = VSC_New();
+#endif
+
#if HAVE_VARNISH_V3
VSC_Setup(vd);
#endif
if (conf->instance != NULL) {
int status;
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
status = VSM_n_Arg(vd, conf->instance);
+#elif HAVE_VARNISH_V5
+ status = VSM_Arg(vd, 'n', conf->instance);
+#endif
+
if (status < 0) {
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
VSM_Delete(vd);
- ERROR("varnish plugin: VSM_n_Arg (\"%s\") failed "
+#elif HAVE_VARNISH_V5
+ VSC_Destroy(&vsc, vd);
+ VSM_Destroy(&vd);
+#endif
+ ERROR("varnish plugin: VSM_Arg (\"%s\") failed "
"with status %i.",
conf->instance, status);
return -1;
#if HAVE_VARNISH_V3
ok = (VSC_Open(vd, /* diag = */ 1) == 0);
-#else /* if HAVE_VARNISH_V4 */
+#elif HAVE_VARNISH_V4
ok = (VSM_Open(vd) == 0);
#endif
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
if (!ok) {
VSM_Delete(vd);
ERROR("varnish plugin: Unable to open connection.");
-
return -1;
}
+#endif
#if HAVE_VARNISH_V3
stats = VSC_Main(vd);
-#else /* if HAVE_VARNISH_V4 */
+#elif HAVE_VARNISH_V4
stats = VSC_Main(vd, NULL);
#endif
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
if (!stats) {
VSM_Delete(vd);
ERROR("varnish plugin: Unable to get statistics.");
+ return -1;
+ }
+#endif
+
+#if HAVE_VARNISH_V5
+ if (VSM_Attach(vd, STDERR_FILENO)) {
+ ERROR("varnish plugin: Cannot attach to varnish. %s", VSM_Error(vd));
+ VSC_Destroy(&vsc, vd);
+ VSM_Destroy(&vd);
+ return -1;
+ }
+ vsm_status = VSM_Status(vd);
+ if (vsm_status & ~(VSM_MGT_RUNNING | VSM_WRK_RUNNING)) {
+ ERROR("varnish plugin: Unable to get statistics.");
+ VSC_Destroy(&vsc, vd);
+ VSM_Destroy(&vd);
return -1;
}
+#endif
#if HAVE_VARNISH_V3
VSC_Iter(vd, varnish_monitor, conf);
-#else /* if HAVE_VARNISH_V4 */
+#elif HAVE_VARNISH_V4
VSC_Iter(vd, NULL, varnish_monitor, conf);
+#elif HAVE_VARNISH_V5
+ VSC_Iter(vsc, vd, varnish_monitor, conf);
#endif
+
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
VSM_Delete(vd);
+#elif HAVE_VARNISH_V5
+ VSC_Destroy(&vsc, vd);
+ VSM_Destroy(&vd);
+#endif
return 0;
} /* }}} */
conf->collect_shm = 1;
#if HAVE_VARNISH_V2
conf->collect_sm = 0;
+#endif
+#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
conf->collect_sma = 0;
#endif
conf->collect_sms = 0;
conf->collect_struct = 0;
conf->collect_totals = 0;
-#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
conf->collect_uptime = 0;
#endif
conf->collect_vcl = 0;
conf->collect_workers = 0;
-#if HAVE_VARNISH_V4
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
conf->collect_vsm = 0;
+ conf->collect_lck = 0;
+ conf->collect_mempool = 0;
+ conf->collect_mgt = 0;
+ conf->collect_smf = 0;
+ conf->collect_vbe = 0;
+ conf->collect_mse = 0;
#endif
return 0;
else if (strcasecmp("CollectSMS", child->key) == 0)
cf_util_get_boolean(child, &conf->collect_sms);
else if (strcasecmp("CollectSMA", child->key) == 0)
-#if HAVE_VARNISH_V2
+#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
cf_util_get_boolean(child, &conf->collect_sma);
#else
WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
- child->key, "v2");
+ child->key, "v2 and v4");
#endif
else if (strcasecmp("CollectSM", child->key) == 0)
#if HAVE_VARNISH_V2
else if (strcasecmp("CollectTotals", child->key) == 0)
cf_util_get_boolean(child, &conf->collect_totals);
else if (strcasecmp("CollectUptime", child->key) == 0)
-#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
cf_util_get_boolean(child, &conf->collect_uptime);
#else
WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
else if (strcasecmp("CollectWorkers", child->key) == 0)
cf_util_get_boolean(child, &conf->collect_workers);
else if (strcasecmp("CollectVSM", child->key) == 0)
-#if HAVE_VARNISH_V4
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
cf_util_get_boolean(child, &conf->collect_vsm);
#else
WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
child->key, "v4");
#endif
+ else if (strcasecmp("CollectLock", child->key) == 0)
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ cf_util_get_boolean(child, &conf->collect_lck);
+#else
+ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
+ child->key, "v4");
+#endif
+ else if (strcasecmp("CollectMempool", child->key) == 0)
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ cf_util_get_boolean(child, &conf->collect_mempool);
+#else
+ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
+ child->key, "v4");
+#endif
+ else if (strcasecmp("CollectManagement", child->key) == 0)
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ cf_util_get_boolean(child, &conf->collect_mgt);
+#else
+ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
+ child->key, "v4");
+#endif
+ else if (strcasecmp("CollectSMF", child->key) == 0)
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ cf_util_get_boolean(child, &conf->collect_smf);
+#else
+ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
+ child->key, "v4");
+#endif
+ else if (strcasecmp("CollectSMF", child->key) == 0)
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ cf_util_get_boolean(child, &conf->collect_smf);
+#else
+ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
+ child->key, "v4");
+#endif
+ else if (strcasecmp("CollectVBE", child->key) == 0)
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ cf_util_get_boolean(child, &conf->collect_vbe);
+#else
+ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
+ child->key, "v4");
+#endif
+ else if (strcasecmp("CollectMSE", child->key) == 0)
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ cf_util_get_boolean(child, &conf->collect_mse);
+#else
+ WARNING("Varnish plugin: \"%s\" is available for Varnish %s only.",
+ child->key, "Plus v4");
+#endif
else {
WARNING("Varnish plugin: Ignoring unknown "
"configuration option: \"%s\". Did "
#endif
&& !conf->collect_session && !conf->collect_shm && !conf->collect_sms
#if HAVE_VARNISH_V2
- && !conf->collect_sma && !conf->collect_sm
+ && !conf->collect_sm
+#endif
+#if HAVE_VARNISH_V2 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ && !conf->collect_sma
#endif
&& !conf->collect_struct && !conf->collect_totals
-#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4
+#if HAVE_VARNISH_V3 || HAVE_VARNISH_V4 || HAVE_VARNISH_V5
&& !conf->collect_uptime
#endif
&& !conf->collect_vcl && !conf->collect_workers
-#if HAVE_VARNISH_V4
- && !conf->collect_vsm
+#if HAVE_VARNISH_V4 || HAVE_VARNISH_V5
+ && !conf->collect_vsm && !conf->collect_vbe && !conf->collect_smf &&
+ !conf->collect_mgt && !conf->collect_lck && !conf->collect_mempool &&
+ !conf->collect_mse
#endif
) {
WARNING("Varnish plugin: No metric has been configured for "
#ifdef HAVE_BLOCK_STATS_FLAGS
#define GET_BLOCK_INFO_VALUE(NAME, FIELD) \
- do { \
- if (!strcmp(param[i].field, NAME)) { \
- binfo->FIELD = param[i].value.l; \
- continue; \
- } \
- } while (0)
+ if (!strcmp(param[i].field, NAME)) { \
+ binfo->FIELD = param[i].value.l; \
+ continue; \
+ }
static int get_block_info(struct lv_block_info *binfo,
virTypedParameterPtr param, int nparams) {
(time_diff_sec * node_cpus * NANOSEC_IN_SEC);
}
- DEBUG(PLUGIN_NAME ": node_cpus=%u cpu_time_old=%llu cpu_time_new=%llu"
- "cpu_time_diff=%llu time_diff_sec=%f percent=%f",
- node_cpus, cpu_time_old, cpu_time_new, cpu_time_diff, time_diff_sec,
- percent);
+ DEBUG(PLUGIN_NAME ": node_cpus=%u cpu_time_old=%" PRIu64
+ " cpu_time_new=%" PRIu64 "cpu_time_diff=%" PRIu64
+ " time_diff_sec=%f percent=%f",
+ node_cpus, (uint64_t)cpu_time_old, (uint64_t)cpu_time_new,
+ (uint64_t)cpu_time_diff, time_diff_sec, percent);
return percent;
}
memset(lv_ud, 0, sizeof(*lv_ud));
- snprintf(inst->tag, sizeof(inst->tag), "%s-%zu", PLUGIN_NAME, i);
+ snprintf(inst->tag, sizeof(inst->tag), "%s-%" PRIsz, PLUGIN_NAME, i);
inst->id = i;
user_data_t *ud = &(lv_ud->ud);
fh = fopen("/proc/vmstat", "r");
if (fh == NULL) {
- char errbuf[1024];
- ERROR("vmem plugin: fopen (/proc/vmstat) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("vmem plugin: fopen (/proc/vmstat) failed: %s", STRERRNO);
return -1;
}
errno = 0;
proc = opendir(PROCDIR);
if (proc == NULL) {
- char errbuf[1024];
- ERROR("vserver plugin: fopen (%s): %s", PROCDIR,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("vserver plugin: fopen (%s): %s", PROCDIR, STRERRNO);
return -1;
}
errno = 0;
dent = readdir(proc);
if (dent == NULL) {
- char errbuf[4096];
-
if (errno == 0) /* end of directory */
break;
ERROR("vserver plugin: failed to read directory %s: %s", PROCDIR,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
closedir(proc);
return -1;
}
status = stat(file, &statbuf);
if (status != 0) {
- char errbuf[4096];
- WARNING("vserver plugin: stat (%s) failed: %s", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("vserver plugin: stat (%s) failed: %s", file, STRERRNO);
continue;
}
continue;
if (NULL == (fh = fopen(file, "r"))) {
- char errbuf[1024];
- ERROR("Cannot open '%s': %s", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("Cannot open '%s': %s", file, STRERRNO);
}
while ((fh != NULL) && (NULL != fgets(buffer, BUFSIZE, fh))) {
continue;
if (NULL == (fh = fopen(file, "r"))) {
- char errbuf[1024];
- ERROR("Cannot open '%s': %s", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("Cannot open '%s': %s", file, STRERRNO);
}
while ((fh != NULL) && (NULL != fgets(buffer, BUFSIZE, fh))) {
continue;
if (NULL == (fh = fopen(file, "r"))) {
- char errbuf[1024];
- ERROR("Cannot open '%s': %s", file,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("Cannot open '%s': %s", file, STRERRNO);
}
while ((fh != NULL) && (NULL != fgets(buffer, BUFSIZE, fh))) {
/* there are a variety of names for the wireless device */
if ((fh = fopen(WIRELESS_PROC_FILE, "r")) == NULL) {
- char errbuf[1024];
- WARNING("wireless: fopen: %s", sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("wireless: fopen: %s", STRERRNO);
return -1;
}
status = swrite(cb->sock_fd, cb->send_buf, strlen(cb->send_buf));
if (status != 0) {
if (cb->log_send_errors) {
- char errbuf[1024];
ERROR("write_graphite plugin: send to %s:%s (%s) failed with status %zi "
"(%s)",
- cb->node, cb->service, cb->protocol, status,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ cb->node, cb->service, cb->protocol, status, STRERRNO);
}
close(cb->sock_fd);
int status;
DEBUG("write_graphite plugin: wg_flush_nolock: timeout = %.3f; "
- "send_buf_fill = %zu;",
+ "send_buf_fill = %" PRIsz ";",
(double)timeout, cb->send_buf_fill);
/* timeout == 0 => flush unconditionally */
cb->sock_fd =
socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
if (cb->sock_fd < 0) {
- char errbuf[1024];
- snprintf(connerr, sizeof(connerr), "failed to open socket: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ snprintf(connerr, sizeof(connerr), "failed to open socket: %s", STRERRNO);
continue;
}
status = connect(cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0) {
- char errbuf[1024];
- snprintf(connerr, sizeof(connerr), "failed to connect to remote "
- "host: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ snprintf(connerr, sizeof(connerr), "failed to connect to remote host: %s",
+ STRERRNO);
close(cb->sock_fd);
cb->sock_fd = -1;
continue;
freeaddrinfo(ai_list);
if (cb->sock_fd < 0) {
- if (connerr[0] == '\0')
- /* this should not happen but try to get a message anyway */
- sstrerror(errno, connerr, sizeof(connerr));
c_complain(LOG_ERR, &cb->init_complaint,
"write_graphite plugin: Connecting to %s:%s via %s failed. "
"The last error was: %s",
sfree(cb->prefix);
sfree(cb->postfix);
+ pthread_mutex_unlock(&cb->send_lock);
pthread_mutex_destroy(&cb->send_lock);
sfree(cb);
cb->send_buf_fill += message_len;
cb->send_buf_free -= message_len;
- DEBUG("write_graphite plugin: [%s]:%s (%s) buf %zu/%zu (%.1f %%) \"%s\"",
+ DEBUG("write_graphite plugin: [%s]:%s (%s) buf %" PRIsz "/%" PRIsz
+ " (%.1f %%) \"%s\"",
cb->node, cb->service, cb->protocol, cb->send_buf_fill,
sizeof(cb->send_buf),
100.0 * ((double)cb->send_buf_fill) / ((double)sizeof(cb->send_buf)),
#define WRITE_HTTP_DEFAULT_BUFFER_SIZE 4096
#endif
+#ifndef WRITE_HTTP_DEFAULT_PREFIX
+#define WRITE_HTTP_DEFAULT_PREFIX "collectd"
+#endif
+
/*
* Private variables
*/
pthread_mutex_t send_lock;
int data_ttl;
+ char *metrics_prefix;
};
typedef struct wh_callback_s wh_callback_t;
int status;
DEBUG("write_http plugin: wh_flush_nolock: timeout = %.3f; "
- "send_buffer_fill = %zu;",
+ "send_buffer_fill = %" PRIsz ";",
CDTIME_T_TO_DOUBLE(timeout), cb->send_buffer_fill);
/* timeout == 0 => flush unconditionally */
sfree(cb->clientcert);
sfree(cb->clientkeypass);
sfree(cb->send_buffer);
+ sfree(cb->metrics_prefix);
sfree(cb);
} /* }}} void wh_callback_free */
CDTIME_T_TO_DOUBLE(vl->interval), values);
if (command_len >= sizeof(command)) {
ERROR("write_http plugin: Command buffer too small: "
- "Need %zu bytes.",
+ "Need %" PRIsz " bytes.",
command_len + 1);
return -1;
}
cb->send_buffer_fill += command_len;
cb->send_buffer_free -= command_len;
- DEBUG("write_http plugin: <%s> buffer %zu/%zu (%g%%) \"%s\"", cb->location,
- cb->send_buffer_fill, cb->send_buffer_size,
+ DEBUG("write_http plugin: <%s> buffer %" PRIsz "/%" PRIsz " (%g%%) \"%s\"",
+ cb->location, cb->send_buffer_fill, cb->send_buffer_size,
100.0 * ((double)cb->send_buffer_fill) / ((double)cb->send_buffer_size),
command);
return status;
}
- DEBUG("write_http plugin: <%s> buffer %zu/%zu (%g%%)", cb->location,
- cb->send_buffer_fill, cb->send_buffer_size,
+ DEBUG("write_http plugin: <%s> buffer %" PRIsz "/%" PRIsz " (%g%%)",
+ cb->location, cb->send_buffer_fill, cb->send_buffer_size,
100.0 * ((double)cb->send_buffer_fill) /
((double)cb->send_buffer_size));
status = format_kairosdb_value_list(
cb->send_buffer, &cb->send_buffer_fill, &cb->send_buffer_free, ds, vl,
cb->store_rates, (char const *const *)http_attrs, http_attrs_num,
- cb->data_ttl);
+ cb->data_ttl, cb->metrics_prefix);
if (status == -ENOMEM) {
status = wh_flush_nolock(/* timeout = */ 0, cb);
if (status != 0) {
status = format_kairosdb_value_list(
cb->send_buffer, &cb->send_buffer_fill, &cb->send_buffer_free, ds, vl,
cb->store_rates, (char const *const *)http_attrs, http_attrs_num,
- cb->data_ttl);
+ cb->data_ttl, cb->metrics_prefix);
}
if (status != 0) {
pthread_mutex_unlock(&cb->send_lock);
return status;
}
- DEBUG("write_http plugin: <%s> buffer %zu/%zu (%g%%)", cb->location,
- cb->send_buffer_fill, cb->send_buffer_size,
+ DEBUG("write_http plugin: <%s> buffer %" PRIsz "/%" PRIsz " (%g%%)",
+ cb->location, cb->send_buffer_fill, cb->send_buffer_size,
100.0 * ((double)cb->send_buffer_fill) /
((double)cb->send_buffer_size));
cb->send_metrics = 1;
cb->send_notifications = 0;
cb->data_ttl = 0;
+ cb->metrics_prefix = strdup(WRITE_HTTP_DEFAULT_PREFIX);
+
+ if (cb->metrics_prefix == NULL) {
+ ERROR("write_http plugin: strdup failed.");
+ sfree(cb);
+ return -1;
+ }
pthread_mutex_init(&cb->send_lock, /* attr = */ NULL);
sfree(val);
} else if (strcasecmp("TTL", child->key) == 0) {
status = cf_util_get_int(child, &cb->data_ttl);
+ } else if (strcasecmp("Prefix", child->key) == 0) {
+ status = cf_util_get_string(child, &cb->metrics_prefix);
} else {
ERROR("write_http plugin: Invalid configuration "
"option: %s.",
return -1;
}
+ if (strlen(cb->metrics_prefix) == 0)
+ sfree(cb->metrics_prefix);
+
if (cb->low_speed_limit > 0)
cb->low_speed_time = CDTIME_T_TO_TIME_T(plugin_get_interval());
/* Allocate the buffer. */
cb->send_buffer = malloc(cb->send_buffer_size);
if (cb->send_buffer == NULL) {
- ERROR("write_http plugin: malloc(%zu) failed.", cb->send_buffer_size);
+ ERROR("write_http plugin: malloc(%" PRIsz ") failed.",
+ cb->send_buffer_size);
wh_callback_free(cb);
return -1;
}
}
#endif
+static rd_kafka_resp_err_t kafka_error() {
+#if RD_KAFKA_VERSION >= 0x000b00ff
+ return rd_kafka_last_error();
+#else
+ return rd_kafka_errno2err(errno);
+#endif
+}
+
static uint32_t kafka_hash(const char *keydata, size_t keylen) {
uint32_t hash = 5381;
for (; keylen > 0; keylen--)
if ((ctx->topic = rd_kafka_topic_new(ctx->kafka, ctx->topic_name,
topic_conf)) == NULL) {
ERROR("write_kafka plugin: cannot create topic : %s\n",
- rd_kafka_err2str(rd_kafka_errno2err(errno)));
+ rd_kafka_err2str(kafka_error()));
return errno;
}
for (size_t i = 0; i < ds->ds_num; i++) {
char key[16];
- snprintf(key, sizeof(key), "%zu", i);
+ snprintf(key, sizeof(key), "%" PRIsz, i);
if (ds->ds[i].type == DS_TYPE_GAUGE)
BSON_APPEND_DOUBLE(&subarray, key, vl->values[i].gauge);
else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
BSON_APPEND_INT64(&subarray, key, vl->values[i].absolute);
else {
- ERROR("write_mongodb plugin: Unknown ds_type %d for index %zu",
+ ERROR("write_mongodb plugin: Unknown ds_type %d for index %" PRIsz,
ds->ds[i].type, i);
bson_destroy(ret);
return NULL;
for (size_t i = 0; i < ds->ds_num; i++) {
char key[16];
- snprintf(key, sizeof(key), "%zu", i);
+ snprintf(key, sizeof(key), "%" PRIsz, i);
if (store_rates)
BSON_APPEND_UTF8(&subarray, key, "gauge");
for (size_t i = 0; i < ds->ds_num; i++) {
char key[16];
- snprintf(key, sizeof(key), "%zu", i);
+ snprintf(key, sizeof(key), "%" PRIsz, i);
BSON_APPEND_UTF8(&subarray, key, ds->ds[i].name);
}
bson_append_array_end(ret, &subarray); /* }}} dsnames */
size_t error_location;
if (!bson_validate(ret, BSON_VALIDATE_UTF8, &error_location)) {
ERROR("write_mongodb plugin: Error in generated BSON document "
- "at byte %zu",
+ "at byte %" PRIsz,
error_location);
bson_destroy(ret);
return NULL;
#include <microhttpd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
#ifndef PROMETHEUS_DEFAULT_STALENESS_DELTA
#define PROMETHEUS_DEFAULT_STALENESS_DELTA TIME_T_TO_CDTIME_T_STATIC(300)
#endif
static cdtime_t staleness_delta = PROMETHEUS_DEFAULT_STALENESS_DELTA;
-/* Unfortunately, protoc-c doesn't export it's implementation of varint, so we
+/* Unfortunately, protoc-c doesn't export its implementation of varint, so we
* need to implement our own. */
static size_t varint(uint8_t buffer[static VARINT_UINT32_BYTES],
uint32_t value) {
}
/* }}} */
+static void prom_logger(__attribute__((unused)) void *arg, char const *fmt,
+ va_list ap) {
+ /* {{{ */
+ char errbuf[1024];
+ vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
+
+ ERROR("write_prometheus plugin: %s", errbuf);
+} /* }}} prom_logger */
+
+#if MHD_VERSION >= 0x00090000
+static int prom_open_socket(int addrfamily) {
+ /* {{{ */
+ char service[NI_MAXSERV];
+ snprintf(service, sizeof(service), "%hu", httpd_port);
+
+ struct addrinfo *res;
+ int status = getaddrinfo(NULL, service,
+ &(struct addrinfo){
+ .ai_flags = AI_PASSIVE | AI_ADDRCONFIG,
+ .ai_family = addrfamily,
+ .ai_socktype = SOCK_STREAM,
+ },
+ &res);
+ if (status != 0) {
+ return -1;
+ }
+
+ int fd = -1;
+ for (struct addrinfo *ai = res; ai != NULL; ai = ai->ai_next) {
+ fd = socket(ai->ai_family, ai->ai_socktype | SOCK_CLOEXEC, 0);
+ if (fd == -1)
+ continue;
+
+ int tmp = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) != 0) {
+ WARNING("write_prometheus: setsockopt(SO_REUSEADDR) failed: %s",
+ STRERRNO);
+ close(fd);
+ fd = -1;
+ continue;
+ }
+
+ if (bind(fd, ai->ai_addr, ai->ai_addrlen) != 0) {
+ close(fd);
+ fd = -1;
+ continue;
+ }
+
+ if (listen(fd, /* backlog = */ 16) != 0) {
+ close(fd);
+ fd = -1;
+ continue;
+ }
+
+ break;
+ }
+
+ freeaddrinfo(res);
+
+ return fd;
+} /* }}} int prom_open_socket */
+
+static struct MHD_Daemon *prom_start_daemon() {
+ /* {{{ */
+ int fd = prom_open_socket(PF_INET6);
+ if (fd == -1)
+ fd = prom_open_socket(PF_INET);
+ if (fd == -1) {
+ ERROR("write_prometheus plugin: Opening a listening socket failed.");
+ return NULL;
+ }
+
+ struct MHD_Daemon *d = MHD_start_daemon(
+ MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, httpd_port,
+ /* MHD_AcceptPolicyCallback = */ NULL,
+ /* MHD_AcceptPolicyCallback arg = */ NULL, http_handler, NULL,
+ MHD_OPTION_LISTEN_SOCKET, fd, MHD_OPTION_EXTERNAL_LOGGER, prom_logger,
+ NULL, MHD_OPTION_END);
+ if (d == NULL) {
+ ERROR("write_prometheus plugin: MHD_start_daemon() failed.");
+ close(fd);
+ return NULL;
+ }
+
+ return d;
+} /* }}} struct MHD_Daemon *prom_start_daemon */
+#else /* if MHD_VERSION < 0x00090000 */
+static struct MHD_Daemon *prom_start_daemon() {
+ /* {{{ */
+ struct MHD_Daemon *d = MHD_start_daemon(
+ MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, httpd_port,
+ /* MHD_AcceptPolicyCallback = */ NULL,
+ /* MHD_AcceptPolicyCallback arg = */ NULL, http_handler, NULL,
+ MHD_OPTION_EXTERNAL_LOGGER, prom_logger, NULL, MHD_OPTION_END);
+ if (d == NULL) {
+ ERROR("write_prometheus plugin: MHD_start_daemon() failed.");
+ return NULL;
+ }
+
+ return d;
+} /* }}} struct MHD_Daemon *prom_start_daemon */
+#endif
+
/*
* collectd callbacks
*/
}
if (httpd == NULL) {
- unsigned int flags = MHD_USE_THREAD_PER_CONNECTION;
-#if MHD_VERSION >= 0x00093300
- flags |= MHD_USE_DUAL_STACK;
-#endif
-
- httpd = MHD_start_daemon(flags, httpd_port,
- /* MHD_AcceptPolicyCallback = */ NULL,
- /* MHD_AcceptPolicyCallback arg = */ NULL,
- http_handler, NULL, MHD_OPTION_END);
+ httpd = prom_start_daemon();
if (httpd == NULL) {
ERROR("write_prometheus plugin: MHD_start_daemon() failed.");
return -1;
char *prefix;
int database;
int max_set_size;
+ int max_set_duration;
_Bool store_rates;
redisContext *conn;
freeReplyObject(rr);
}
+ if (node->max_set_duration > 0) {
+ /*
+ * remove element, scored less than 'current-max_set_duration'
+ * '(%d' indicates 'less than' in redis CLI.
+ */
+ rr = redisCommand(node->conn, "ZREMRANGEBYSCORE %s -1 (%d", key,
+ (time - node->max_set_duration) + 1);
+ if (rr == NULL)
+ WARNING("ZREMRANGEBYSCORE command error. key:%s message:%s", key,
+ node->conn->errstr);
+ else
+ freeReplyObject(rr);
+ }
+
/* TODO(octo): This is more overhead than necessary. Use the cache and
* metadata to determine if it is a new metric and call SADD only once for
* each metric. */
node->prefix = NULL;
node->database = 0;
node->max_set_size = -1;
+ node->max_set_duration = -1;
node->store_rates = 1;
pthread_mutex_init(&node->lock, /* attr = */ NULL);
status = cf_util_get_int(child, &node->database);
} else if (strcasecmp("MaxSetSize", child->key) == 0) {
status = cf_util_get_int(child, &node->max_set_size);
+ } else if (strcasecmp("MaxSetDuration", child->key) == 0) {
+ status = cf_util_get_int(child, &node->max_set_duration);
} else if (strcasecmp("StoreRates", child->key) == 0) {
status = cf_util_get_boolean(child, &node->store_rates);
} else
{
char ds_index[DATA_MAX_NAME_LEN];
- snprintf(ds_index, sizeof(ds_index), "%zu", index);
+ snprintf(ds_index, sizeof(ds_index), "%" PRIsz, index);
riemann_event_string_attribute_add(event, "ds_index", ds_index);
}
wrr_disconnect(host);
+ pthread_mutex_lock(&host->lock);
pthread_mutex_destroy(&host->lock);
sfree(host);
} /* }}} void wrr_free */
#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "utils_cache.h"
#include <arpa/inet.h>
#include <errno.h>
#include <inttypes.h>
#include <netdb.h>
#include <stddef.h>
-#include "common.h"
-#include "plugin.h"
-#include "utils_cache.h"
#include <stdlib.h>
#define SENSU_HOST "localhost"
// incorporate the data source index
{
char ds_index[DATA_MAX_NAME_LEN];
- snprintf(ds_index, sizeof(ds_index), "%zu", index);
+ snprintf(ds_index, sizeof(ds_index), "%" PRIsz, index);
res = my_asprintf(&temp_str, "%s, \"collectd_data_source_index\": %s",
ret_str, ds_index);
free(ret_str);
return NULL;
}
} else {
- res = my_asprintf(&value_str, "%llu", vl->values[index].counter);
+ res = my_asprintf(&value_str, "%" PRIu64,
+ (uint64_t)vl->values[index].counter);
if (res == -1) {
free(ret_str);
ERROR("write_sensu plugin: Unable to alloc memory");
sensu_close_socket(host);
if (status != 0) {
- char errbuf[1024];
ERROR("write_sensu plugin: Sending to Sensu at %s:%s failed: %s",
(host->node != NULL) ? host->node : SENSU_HOST,
- (host->service != NULL) ? host->service : SENSU_PORT,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ (host->service != NULL) ? host->service : SENSU_PORT, STRERRNO);
return -1;
}
sfree(host->separator);
free_str_list(&(host->metric_handlers));
free_str_list(&(host->notification_handlers));
+
+ pthread_mutex_unlock(&host->lock);
pthread_mutex_destroy(&host->lock);
+
sfree(host);
} /* }}} void sensu_free */
ssize_t status = 0;
status = swrite(cb->sock_fd, cb->send_buf, strlen(cb->send_buf));
- if (status < 0) {
- char errbuf[1024];
+ if (status != 0) {
ERROR("write_tsdb plugin: send failed with status %zi (%s)", status,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
close(cb->sock_fd);
cb->sock_fd = -1;
int status;
DEBUG("write_tsdb plugin: wt_flush_nolock: timeout = %.3f; "
- "send_buf_fill = %zu;",
+ "send_buf_fill = %" PRIsz ";",
(double)timeout, cb->send_buf_fill);
/* timeout == 0 => flush unconditionally */
}
if (cb->sock_fd < 0) {
- char errbuf[1024];
ERROR("write_tsdb plugin: Connecting to %s:%s failed. "
"The last error was: %s",
- node, service, sstrerror(errno, errbuf, sizeof(errbuf)));
+ node, service, STRERRNO);
return -1;
}
sfree(cb->service);
sfree(cb->host_tags);
+ pthread_mutex_unlock(&cb->send_lock);
pthread_mutex_destroy(&cb->send_lock);
sfree(cb);
}
BUFFER_ADD(GAUGE_FORMAT, rates[ds_num]);
} else if (ds->ds[ds_num].type == DS_TYPE_COUNTER)
- BUFFER_ADD("%llu", vl->values[ds_num].counter);
+ BUFFER_ADD("%" PRIu64, (uint64_t)vl->values[ds_num].counter);
else if (ds->ds[ds_num].type == DS_TYPE_DERIVE)
BUFFER_ADD("%" PRIi64, vl->values[ds_num].derive);
else if (ds->ds[ds_num].type == DS_TYPE_ABSOLUTE)
if (message_len >= sizeof(message)) {
ERROR("write_tsdb plugin: message buffer too small: "
- "Need %zu bytes.",
+ "Need %" PRIsz " bytes.",
message_len + 1);
return -1;
}
cb->send_buf_fill += message_len;
cb->send_buf_free -= message_len;
- DEBUG("write_tsdb plugin: [%s]:%s buf %zu/%zu (%.1f %%) \"%s\"", cb->node,
- cb->service, cb->send_buf_fill, sizeof(cb->send_buf),
+ DEBUG("write_tsdb plugin: [%s]:%s buf %" PRIsz "/%" PRIsz " (%.1f %%) \"%s\"",
+ cb->node, cb->service, cb->send_buf_fill, sizeof(cb->send_buf),
100.0 * ((double)cb->send_buf_fill) / ((double)sizeof(cb->send_buf)),
message);
/*
* Global variables
*/
+static value_to_rate_state_t arc_hits_state;
+static value_to_rate_state_t arc_misses_state;
+static value_to_rate_state_t l2_hits_state;
+static value_to_rate_state_t l2_misses_state;
#if defined(KERNEL_LINUX)
#include "utils_llist.h"
}
#elif defined(KERNEL_SOLARIS)
+
+#if HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
extern kstat_ctl_t *kc;
static long long get_zfs_value(kstat_t *ksp, char *name) {
fh = fopen(ZOL_ARCSTATS_FILE, "r");
if (fh == NULL) {
- char errbuf[1024];
ERROR("zfs_arc plugin: Opening \"%s\" failed: %s", ZOL_ARCSTATS_FILE,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ STRERRNO);
return -1;
}
- ksp = llist_create();
- if (ksp == NULL) {
- ERROR("zfs_arc plugin: `llist_create' failed.");
- fclose(fh);
- return -1;
- }
-
- // Ignore the first two lines because they contain information about
- // the rest of the file.
- // See kstat_seq_show_headers module/spl/spl-kstat.c of the spl kernel
- // module.
- if (fgets(buffer, sizeof(buffer), fh) == NULL) {
- ERROR("zfs_arc plugin: \"%s\" does not contain a single line.",
+ /* Ignore the first two lines because they contain information about the rest
+ * of the file.
+ * See kstat_seq_show_headers module/spl/spl-kstat.c of the spl kernel module.
+ */
+ if ((fgets(buffer, sizeof(buffer), fh) == NULL) ||
+ (fgets(buffer, sizeof(buffer), fh) == NULL)) {
+ ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.",
ZOL_ARCSTATS_FILE);
fclose(fh);
return -1;
}
- if (fgets(buffer, sizeof(buffer), fh) == NULL) {
- ERROR("zfs_arc plugin: \"%s\" does not contain at least two lines.",
- ZOL_ARCSTATS_FILE);
+
+ ksp = llist_create();
+ if (ksp == NULL) {
+ ERROR("zfs_arc plugin: `llist_create' failed.");
fclose(fh);
return -1;
}
za_read_derive(ksp, "mru_hits", "cache_result", "mru-hit");
za_read_derive(ksp, "mru_ghost_hits", "cache_result", "mru_ghost-hit");
+ cdtime_t now = cdtime();
+
/* Ratios */
- arc_hits = (gauge_t)get_zfs_value(ksp, "hits");
- arc_misses = (gauge_t)get_zfs_value(ksp, "misses");
- l2_hits = (gauge_t)get_zfs_value(ksp, "l2_hits");
- l2_misses = (gauge_t)get_zfs_value(ksp, "l2_misses");
+ if ((value_to_rate(&arc_hits, (value_t){.derive = get_zfs_value(ksp, "hits")},
+ DS_TYPE_DERIVE, now, &arc_hits_state) == 0) &&
+ (value_to_rate(&arc_misses,
+ (value_t){.derive = get_zfs_value(ksp, "misses")},
+ DS_TYPE_DERIVE, now, &arc_misses_state) == 0)) {
+ za_submit_ratio("arc", arc_hits, arc_misses);
+ }
- za_submit_ratio("arc", arc_hits, arc_misses);
- za_submit_ratio("L2", l2_hits, l2_misses);
+ if ((value_to_rate(&l2_hits,
+ (value_t){.derive = get_zfs_value(ksp, "l2_hits")},
+ DS_TYPE_DERIVE, now, &l2_hits_state) == 0) &&
+ (value_to_rate(&l2_misses,
+ (value_t){.derive = get_zfs_value(ksp, "l2_misses")},
+ DS_TYPE_DERIVE, now, &l2_misses_state) == 0)) {
+ za_submit_ratio("L2", l2_hits, l2_misses);
+ }
/* I/O */
value_t l2_io[] = {
}
if (sread(fd, buf, bufsize) != 0) {
- char errbuf[1024];
- ERROR("zone plugin: Reading \"%s\" failed: %s", procfile,
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("zone plugin: Reading \"%s\" failed: %s", procfile, STRERRNO);
close(fd);
return 1;
}
status = getaddrinfo(host, port, &ai_hints, &ai_list);
if (status != 0) {
- char errbuf[1024];
INFO("getaddrinfo failed: %s",
- (status == EAI_SYSTEM) ? sstrerror(errno, errbuf, sizeof(errbuf))
- : gai_strerror(status));
+ (status == EAI_SYSTEM) ? STRERRNO : gai_strerror(status));
return -1;
}
for (struct addrinfo *ai = ai_list; ai != NULL; ai = ai->ai_next) {
sk = socket(ai->ai_family, SOCK_STREAM, 0);
if (sk < 0) {
- char errbuf[1024];
- WARNING("zookeeper: socket(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("zookeeper: socket(2) failed: %s", STRERRNO);
continue;
}
status = (int)connect(sk, ai->ai_addr, ai->ai_addrlen);
if (status != 0) {
- char errbuf[1024];
close(sk);
sk = -1;
- WARNING("zookeeper: connect(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ WARNING("zookeeper: connect(2) failed: %s", STRERRNO);
continue;
}
status = (int)swrite(sk, "mntr\r\n", strlen("mntr\r\n"));
if (status != 0) {
- char errbuf[1024];
- ERROR("zookeeper: write(2) failed: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("zookeeper: write(2) failed: %s", STRERRNO);
close(sk);
return -1;
}
buffer_size - buffer_fill, /* flags = */ 0)) !=
0) {
if (status < 0) {
- char errbuf[1024];
if ((errno == EAGAIN) || (errno == EINTR))
continue;
- ERROR("zookeeper: Error reading from socket: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
+ ERROR("zookeeper: Error reading from socket: %s", STRERRNO);
close(sk);
return -1;
}
#!/bin/sh
-DEFAULT_VERSION="5.7.2.git"
+DEFAULT_VERSION="5.8.0.git"
if [ -d .git ]; then
VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"