Expose meta_data_toc function in utils_cache.
--- /dev/null
+env:
+ LANG: C
+ CIRRUS_CLONE_DEPTH: 1
+ DEFAULT_CONFIG_OPTS: --enable-debug --without-libstatgrab --disable-dependency-tracking
+
+
+###
+# make distcheck and other sanity checks
+#
+release_ready_task:
+ container:
+ image: collectd/ci:stretch_amd64
+ lint_script:
+ - /checks/check-bashisms.sh
+ - /checks/check-pod.sh
+ configure_script:
+ - ./build.sh
+ - ./configure $DEFAULT_CONFIG_OPTS
+ checks_script:
+ - make -j2 -s distcheck DISTCHECK_CONFIGURE_FLAGS="${DEFAULT_CONFIG_OPTS}"
+
+###
+# Default toolchain and build flags used in deb packages, on a range of Debian
+# and Ubuntu releases (+ Debian/unstable)
+# Most should succeed, and PRs shouldn't break them.
+#
+debian_default_toolchain_task:
+ matrix:
+ - allow_failures: false
+ container:
+ image: collectd/ci:jessie_amd64
+ - allow_failures: false
+ container:
+ image: collectd/ci:stretch_amd64
+ - allow_failures: false
+ container:
+ image: collectd/ci:stretch_i386
+ - allow_failures: false
+ container:
+ image: collectd/ci:trusty_amd64
+ - allow_failures: false
+ container:
+ image: collectd/ci:xenial_amd64
+ # debian/unstable is expected to fail
+ - allow_failures: true
+ skip_notifications: true
+ only_if: $CIRRUS_BRANCH == 'master'
+ container:
+ image: collectd/ci:sid_amd64
+ configure_script:
+ - ./build.sh
+ - gcc --version
+ - >
+ ./configure CC=gcc $DEFAULT_CONFIG_OPTS
+ CFLAGS="$(dpkg-buildflags --get CFLAGS)"
+ CPPLAGS="$(dpkg-buildflags --get CPPFLAGS)"
+ LDFLAGS="$(dpkg-buildflags --get LDFLAGS)"
+ build_script:
+ - make -j2 -sk
+ tests_script:
+ - make -j2 -sk check
+ - /checks/check-built-plugins.sh
+
+###
+# Default toolchain and build flags used in RPM packages, on a range of RedHat
+# and Fedora releases (+ Fedora/rawhide)
+# Most should succeed, and PRs shouldn't break them.
+#
+redhat_default_toolchain_task:
+ matrix:
+ - allow_failures: false
+ skip_notifications: false
+ container:
+ image: collectd/ci:el6_x86_64
+ - allow_failures: true
+ skip_notifications: true
+ container:
+ image: collectd/ci:el7_x86_64 # TODO: fix this platform
+ - allow_failures: true
+ skip_notifications: true
+ container:
+ image: collectd/ci:fedora28_x86_64
+ # fedora/rawhide is expected to fail
+ - allow_failures: true
+ skip_notifications: true
+ only_if: $CIRRUS_BRANCH == 'master'
+ container:
+ image: collectd/ci:fedora_rawhide_x86_64
+ configure_script:
+ - ./build.sh
+ - gcc --version
+ - ./configure CC=gcc $DEFAULT_CONFIG_OPTS CFLAGS="$(rpm --eval '%optflags')"
+ build_script:
+ - make -j2 -sk
+ tests_script:
+ - make -j2 -sk check
+ - /checks/check-built-plugins.sh
+
+
+###
+# Misc non-standard build environment & options on most recent released debian
+# version.
+# Some are expected to fail, others should always pass
+non_standard_toolchains_task:
+ container:
+ image: collectd/ci:stretch_amd64
+ only_if: $CIRRUS_PR == ''
+
+ matrix:
+
+ # build using clang with default build flags, should always pass
+ - env:
+ LABEL: clang
+ allow_failures: true # TODO: fix this platform
+ skip_notifications: true
+ configure_script:
+ - ./build.sh
+ - clang --version
+ - >
+ ./configure CC=clang CXX=clang++
+ $DEFAULT_CONFIG_OPTS
+ CFLAGS="$(dpkg-buildflags --get CFLAGS)"
+ CPPLAGS="$(dpkg-buildflags --get CPPFLAGS)"
+ LDFLAGS="$(dpkg-buildflags --get LDFLAGS)"
+ build_script:
+ - make -j2 -sk
+ tests_script:
+ - make -j2 -sk check
+
+ # build against libstatgrab, should always pass
+ - env:
+ LABEL: statgrab
+ allow_failures: false
+ skip_notifications: false
+ configure_script:
+ - ./build.sh
+ - gcc --version
+ - >
+ ./configure --with-libstatgrab --enable-debug
+ CFLAGS="$(dpkg-buildflags --get CFLAGS)"
+ CPPLAGS="$(dpkg-buildflags --get CPPFLAGS)"
+ LDFLAGS="$(dpkg-buildflags --get LDFLAGS)"
+ build_script:
+ - make -j2 -sk
+ tests_script:
+ - >
+ for i in cpu disk interface load memory swap users; do
+ if ! $(ldd ".libs/${i}.so" 2>/dev/null | grep -q 'libstatgrab.so'); then
+ echo "plugin $i NOT linked against libstatgrab"
+ exit 1
+ fi
+ done
+
+ # build using clang with a collection of strict build flags, will most
+ # probably always fail
+ - env:
+ LABEL: clang strict
+ allow_failures: true
+ skip_notifications: true
+ configure_script:
+ - ./build.sh
+ - clang --version
+ - >
+ ./configure CC=clang CXX=clang++
+ $DEFAULT_CONFIG_OPTS
+ CFLAGS='-Wall
+ -Wno-error
+ -Wextra
+ -Wformat=2
+ -Wformat-security
+ -Wformat-nonliteral
+ -Wmissing-include-dirs
+ -Wold-style-definition
+ -Wpointer-arith
+ -Winit-self
+ -Wmissing-prototypes
+ -Wimplicit-function-declaration
+ -Wmissing-declarations
+ -Wstrict-prototypes
+ -Wmissing-noreturn
+ -Wshadow
+ -Wendif-labels
+ -Wwrite-strings
+ -Wno-unused-parameter
+ -Wno-missing-field-initializers
+ -Wdate-time
+ -Wnested-externs
+ -Wno-typedef-redefinition
+ -Wno-gnu-variable-sized-type-not-at-end'
+ build_script:
+ - make -j2 -sk
+ tests_script:
+ - make -j2 -sk check
+
+###
+# Build using a range of compilers, available in debian/unstable. NB: might
+# fail because of changes to the distro, not the compiler used.
+#
+bleeding_edge_compilers_task:
+ container:
+ image: collectd/ci:sid_amd64
+ only_if: $CIRRUS_BRANCH == 'master'
+ allow_failures: true
+ skip_notifications: true
+ env:
+ matrix:
+ CC: gcc-7
+ CC: gcc-8
+ CC: clang-6.0
+ CC: clang-7
+ CC: clang-8
+ CC: clang-9
+ configure_script:
+ - ./build.sh
+ - $CC --version
+ - >
+ ./configure CC=$CC
+ $DEFAULT_CONFIG_OPTS
+ CFLAGS="$(dpkg-buildflags --get CFLAGS)"
+ CPPLAGS="$(dpkg-buildflags --get CPPFLAGS)"
+ LDFLAGS="$(dpkg-buildflags --get LDFLAGS)"
+ build_script:
+ - make -j2 -sk
+ tests_script:
+ - make -j2 -sk check
+# Travis CI configuration file
+# https://travis-ci.org/collectd/collectd
+language: c
+
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="
+ - MAKEFLAGS="-j 2"
+ # 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="
+
+matrix:
+ include:
+ - os: osx
+ osx_image: xcode11.2
+ compiler: clang
+ jdk: openjdk10
+ env:
+ - CXX=clang++
+ - PATH="/usr/local/opt/mysql-client/bin:$PATH"
+ - JAVA_HOME="/Library/Java/JavaVirtualMachines/openjdk-13.jdk/Contents/Home"
+ - os: linux
+ dist: xenial
+ compiler: clang
+ jdk: openjdk10
+ - os: linux
+ dist: xenial
+ compiler: gcc
+ jdk: openjdk10
-sudo: required
-dist: trusty
-compiler:
- - gcc
- - 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
- libcurl4-gnutls-dev
- libdbi0-dev
- libesmtp-dev
- libganglia1-dev
- libgcrypt11-dev
- libglib2.0-dev
- libgps-dev
- libhiredis-dev
- libi2c-dev
- libldap2-dev
- libltdl-dev
- liblua50-dev
- liblua5.1-0-dev
- liblua5.2-dev
- liblvm2-dev
- libmemcached-dev
- libmicrohttpd-dev
- libmnl-dev
- libmodbus-dev
- libmosquitto0-dev
- libmysqlclient-dev
- libnotify-dev
- libopenipmi-dev
- liboping-dev
- libow-dev
- libpcap-dev
- libperl-dev
- libpq-dev
- libprotobuf-c0-dev
- librabbitmq-dev
- librdkafka-dev
- libriemann-client-dev
- librrd-dev
- libsensors4-dev
- libsigrok-dev
- libsnmp-dev
- libstatgrab-dev
- libtokyocabinet-dev
- libtokyotyrant-dev
- libudev-dev
- libupsclient-dev
- libvarnish-dev
- libvirt-dev
- libxen-dev
- libxml2-dev
- libyajl-dev
- linux-libc-dev
- perl
- protobuf-c-compiler
- python3-dev
- python-dev
- xfslibs-dev
-before_script: autoreconf -fi
+
+before_script: autoreconf -vif
+
script:
- if [[ "${TRAVIS_BRANCH}" == "coverity_scan" ]]; then exit 0; fi
+ - type pkg-config
+ - pkg-config --list-all | sort -u
- ./configure
- - make -j $(nproc)
- - make check
+ - cat config.log
+ - make distcheck DISTCHECK_CONFIGURE_FLAGS="--disable-dependency-tracking --enable-debug"
addons:
+ apt:
+ packages:
+ - autotools-dev
+ - iptables-dev
+ - libatasmart-dev
+ - libcap-dev
+ - libcurl4-gnutls-dev
+ - libdbi0-dev
+ - libesmtp-dev
+ - libganglia1-dev
+ - libgcrypt11-dev
+ - libglib2.0-dev
+ - libgps-dev
+ - libhiredis-dev
+ - libi2c-dev
+ - libldap2-dev
+ - libltdl-dev
+ - liblua50-dev
+ - liblua5.1-0-dev
+ - liblua5.2-dev
+ - libmemcached-dev
+ - libmicrohttpd-dev
+ - libmnl-dev
+ - libmodbus-dev
+ - libmosquitto-dev
+ - libmysqlclient-dev
+ - libnotify-dev
+ - libopenipmi-dev
+ - liboping-dev
+ - libow-dev
+ - libpcap-dev
+ - libperl-dev
+ - libpq-dev
+ - libprotobuf-c0-dev
+ - librabbitmq-dev
+ - librdkafka-dev
+ - libriemann-client-dev
+ - librrd-dev
+ - libsensors4-dev
+ - libsigrok-dev
+ - libsnmp-dev
+ - libtokyocabinet-dev
+ - libtokyotyrant-dev
+ - libudev-dev
+ - libupsclient-dev
+ - libvarnish-dev
+ - libvirt-dev
+ - libxen-dev
+ - libxml2-dev
+ - libyajl-dev
+ - linux-libc-dev
+ - perl
+ - protobuf-c-compiler
+ - python3-dev
+ - python-dev
+ - xfslibs-dev
coverity_scan:
project:
name: "collectd/collectd"
build_command_prepend: "./configure; make clean"
build_command: "make -j $(nproc)"
branch_pattern: coverity_scan
+ homebrew:
+ packages:
+ - curl
+ - glib
+ - hiredis
+ - libdbi
+ - libmemcached
+ - libmicrohttpd
+ - libmodbus
+ - libnotify
+ - liboping
+ - libpcap
+ - librdkafka
+ - libvirt
+ - libxml2
+ - lua
+ - mongo-c-driver
+ - mosquitto
+ - mysql-client
+ - net-snmp
+ - openldap
+ - perl
+ - protobuf
+ - protobuf-c
+ - python
+ - qpid-proton
+ - rabbitmq-c
+ - riemann-client
+ - rrdtool
+ - tokyo-cabinet
+ - varnish
+ - yajl
+
+git:
+ quiet: true
+ submodules: false
+ depth: 1
Andreas Henriksson <andreas at fatal.se>
- libmnl support in the netlink plugin.
+Andrew Bays <abays at redhat.com>
+ - connectivity plugin.
+ - procevent plugin.
+ - sysevent plugin.
+ - connectivity plugin.
+
Andy Parkins <andyp at fussylogic.co.uk>
- battery plugin: sysfs code.
+Aneesh Puttur <aputtur at redhat.com>
+ - connectivity plugin.
+
Andy Smith <ansmith at redhat.com>
- AMQP 1.0 plugin.
+
+Aneesh Puttur <aputtur at redhat.com>
+ - connectivity plugin.
Anthony Dewhurst <dewhurst at gmail.com>
- zfs_arc plugin.
Julien Ammous <j.ammous at gmail.com>
- Lua plugin.
+Shirly Radco <sradco at redhat.com>
+ - write_syslog plugin.
+
Kevin Bowling <kbowling at llnw.com>
- write_tsdb plugin for http://opentsdb.net/
# These owners will be the default owners for everything in the repo. Unless a
# later match takes precedence, # @trusted-contributors will be requested for
# review when someone opens a pull request.
-* @trusted-contributors
/src/intel_pmu.c @kwiatrox @sunkuranganath
/src/intel_rdt.c @kwiatrox @sunkuranganath
/src/virt.c @anaudx @rjablonx
# TODO(#2926): Add the following owners:
#/src/redfish.c @kkepka @mkobyli
+
+# Order is important; the last matching pattern takes the most
+# precedence.
+* @trusted-contributors
+++ /dev/null
-# Contribution guidelines
-
-Thanks for taking the time to contribute to the [collectd
-project](https://collectd.org/)! This document tries to give some guidance to
-make the process of contributing to *collectd* as pleasant as possible.
-
-## Bug reports
-
-Please report bugs as [GitHub
-Issues](https://github.com/collectd/collectd/issues). Try to answer the
-following questions:
-
-* Which version of *collectd* are you using?
-* Which operating system (distribution) are you using at which version?
-* What is the expected behavior / output?
-* What is the actual (observed) behavior / output?
-* How can we reproduce the problem you're having?
-* If *collectd* crashes, try to get a
- [stack trace](https://collectd.org/wiki/index.php/Core_file).
-
-Please monitor your issue for a couple of days and reply to questions. To keep
-the project manageable, we have to do some housekeeping; meaning we will close
-issues that have become stale.
-
-## Code contributions
-
-Please open a [GitHub Pull Request](https://github.com/collectd/collectd/pulls)
-(PR) to contribute bug fixes, features, cleanups, new plugins, … Patches sent to
-the mailing list have a tendency to fall through the cracks.
-
-* *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` 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.
-* *Continuous integration:* Once your PR is created, our continuous
- integration environment will try to build it on a number of platforms. If
- this reports a failure, please investigate and fix the problem. We will at
- best do a very casual review for failing PRs.
-* *Don't rebase:* Rebasing your branch destroys the review history. If a review
- takes a long time, we may ask you to rebase on a more recent *master*, but
- please don't do it without being asked.
-* *types.db:* One of the most common mistakes made by new contributors is the
- addition of (many) new *types* in the file `src/types.db`. The majority of
- usecases can be met with one of the existing entries. If you plan to add new
- entries to `src/types.db`, you should talk to us early in the design
- process.
-
-### ChangeLog
-
-All PRs need to have a one-line description in the initial pull request body.
-This information is used to automatically generate release notes. Follow this
-style:
-
-```
-Foo plugin: A specific issue people had has been fixed.
-```
-
-Start with "Foo plugin" to give the reader context for the information. Other
-common prefixes are "collectd" for the core daemon and "Build system". Use past
-tense and passive voice the for remainder, e.g. "a bug has been fixed", "a
-feature has been added".
-
-Some PRs should not be added to the release notes, e.g. changes to project
-internal documentation (such as this file). Those changes are not interesting
-for external users of the project and would reduce the value of the release
-notes. Maintainers may use the `Unlisted Change` label to mark those PRs.
-
-## Other resources
-
-* [Mailing list](http://mailman.verplant.org/listinfo/collectd)
-* [#collectd IRC channel](https://webchat.freenode.net/?channels=#collectd)
- on *freenode*.
-* [Old patch submission guideline](https://collectd.org/wiki/index.php/Submitting_patches)
+2019-10-01, Version 5.9.2
+ * syslog plugin: Don't fail if syslog loglevel doesn't match. Thanks to
+ Fabien Wernli. #3236 #3238
+ * collectd: Fix ssnprintf wrapper. Thanks to Fabien Wernli. #3237
+ * rdt plugin: Fix compile time issues. Thanks to Matthias Runge. #3245
+
+2019-07-24, Version 5.9.1
+ * collectd: redhat spec: fix build due to new upstream plugins. Thanks
+ to Fabien Wernli. #3175
+ * collectd: regex match: Fix unexpected match with empty meta data .
+ Thanks to Takuro Ashie. #3178
+ * collectd: Fix return value or loglevel for several plugins. Thanks to
+ Fabien Wernli. #3182
+ * collectd: Add standard include early or _FILE_OFFSET_BITS will have
+ definition … . Thanks to Dagobert Michelsen. #3193
+ * collectd: Use GCC-specific flags only when compiling with GCC. Thanks
+ to Dagobert Michelsen. #3195
+ * Use test_utils_proc_pids only when compiling the plugin that uses it.
+ Thanks to Dagobert Michelsen. #3197
+ * DNS plugin: Do not use headers from glibc. Thanks to Pavel Rochnyak.
+ #3156, #3145
+ * collectd: Add missing definitions for libnetsnmpagent. Thanks to
+ Dagobert Michelsen. #3203
+ * collectd: Move Makefile rules for pid_test inside conditional for
+ code. Thanks to Dagobert Michelsen. #3206
+ * collectd: Recover setlocale() call in src/daemon/collectd.c do_init().
+ Thanks to Pavel Rochnyak. #3214, #3181
+ * collectd: Add snprintf wrapper for GCC 8.2/3. Thanks to zebity. #3153,
+ #2895, #3038
+ * collectd: Fix bug that leads to CPPFLAGS gets overridden with CFLAGS
+ when libxmms is enabled. Thanks to Dagobert Michelsen. #3207
+ * Write_Riemann plugin: Copy MetaData to Riemann events in
+ write_riemann. Thanks to Romain Tartière. #3158
+ * virt plugin: Fix memory leak with libvirt MetadataXPath enabled.
+ Thanks to Pavel Rochnyak. #3225, #3230
+
+2019-06-13, Version 5.9.0
+ * Build System: configure.ac: option "--with-libxml2" has been added.
+ Thanks to Dimitrios Apostolou, Pavel Rochnyak. #2864
+ * Build System: configure.ac: run dpdk build tests only if pkgconfig
+ fails. Thanks to Luca Boccassi, Pavel Rochnyak. #3015
+ * Build System: The "df" plugin is now built when "getmntent_r()" is
+ available. Thanks to Florian Forster. #3095
+ * Build System: The ability to turn on collectd "debug" feature in RPMs
+ has been added. Thanks to dehotot. #2755
+ * collectd: A new "UNKNOWN" state as the initial state of metrics has
+ been added. Thanks to Luis Fernández Álvarez, Florian Forster. #2976
+ * collectd: Base port to Windows. Thanks to Sean Campbell. #2810
+ * collectd: Code ownership of five plugins has been handed out to folks
+ from Intel. Thanks to Florian Forster. #3053
+ * collectd: config parser: Improved error reporting on global options.
+ Thanks to Pavel Rochnyak. #2813
+ * collectd: daemon: make plugin_dispatch_multivalue() obey write queue
+ limits. Thanks to Adam Romanek. #2898
+ * collectd: Macros "STRERROR" and "STRERRNO" have been added. Thanks to
+ Florian Forster. #2519
+ * collectd: Plugin name field has been added to plugin context to
+ improve error reporting. Thanks to Pavel Rochnyak. #2821
+ * collectd-tg: Use "CLOCK_REALTIME" for collectd-tg times. Thanks to
+ Andrew Bays. #2837
+ * tree-wide: Don't initialize static pointers to NULL, use "bool" from
+ "stdbool.h" (instead of "_Bool"). Thanks to Ruben Kerkhof. #2771,
+ #2772
+ * tree-wide: Replace zu with "PRIsz" and llu with "PRIu64". Thanks to
+ Sean Campbell. #2512
+ * tree-wide: Use interval value from plugin context, do not set
+ "vl->interval" in plugins more. Thanks to Pavel Rochnyak. #2847
+ * tree-wide: Utilities and libraries have been moved to "src/utils/".
+ Thanks to Florian Forster. #2961
+ * AMPQ1 plugin: A new plugin to write to amqp1 protocol. Thanks to Andy
+ Smith. #2618
+ * Chrony plugin: Ignoring late responses has been added. Thanks to
+ Miroslav Lichvar, Pavel Rochnyak. #2896
+ * CPUFreq plugin: Read number of p-state transitions and time spent in
+ each p-state. Thanks to Sexton Rory. #2803
+ * cURL, cURL-XML plugins: Option "Interval" has been added. Thanks to
+ Pavel Rochnyak. #2847
+ * Disk plugin: Report number of in progress disk IO requests on FreeBSD.
+ Thanks to Nathan Huff. #2878
+ * Exec plugin: Dynamic allocation of grname buffer has been added.
+ Thanks to sreedi, Florian Forster. #2937
+ * GPU NVML plugin: New plugin to collect NVIDIA GPU stats. Thanks to
+ Evgeny Naumov. #2923
+ * gRPC plugin: The "VerifyPeer" option for servers has been added.
+ Thanks to Florian Forster. #2593
+ * Intel RDT plugin: Support for groups of PIDs has been added. Thanks to
+ Wojciech Andralojc, Mateusz Starzyk, Michal Aleksinski. #2891
+ * IPMI plugin: Config options "SELSensor" and "SELIgnoreSelected" have
+ been added. Thanks to Mariusz Szafranski. #2796
+ * Modbus plugin: Support for 64 bit vals has been added, support for
+ CDAB endian 32-bit modbus polls has been added. Thanks to Anthony
+ Vickers, PJ Bostley. #2670, #2660
+ * Modbus plugin: The "Scale" and "Shift" metrics have been added. Thanks
+ to cekstam. #2729
+ * Netlink plugin: Handle new counter from Linux kernel version 4.6+.
+ Thanks to Pavel Rochnyak. #2767
+ * Network plugin: Option "BindAddress" has been added. Thanks to Ofir
+ Hermesh. #2831
+ * Ping plugin: An "AddressFamily" configuration option has been added.
+ Thanks to 依云 lilydjwg. #2961
+ * OVS Stats plugin: Extended metrics "ovs-dpdk" have been added. Thanks
+ to Matteo Croce, Ryan McCabe. #3000
+ * OVS Stats plugin: Support of bond interface and a "InterfaceStats"
+ config option have been added. Thanks to Andrew Bays. #2880
+ * PCIe Errors plugin: New plugin to read "PCIe" errors. Thanks to Kamil
+ Wiatrowski. #2733
+ * Processes plugin: Support for Linux Delay Accounting has been added.
+ Thanks to Florian Forster. #2598
+ * Redis plugin: Keyspace "hitratio" metric has been added, metric
+ "operations_per_second" has been removed, an option for connecting via
+ UNIX socket has been added. Thanks to Pavel Rochnyak. #2838, #2845,
+ #2904
+ * RouterOS plugin: Support for temperature and voltage data has been
+ added, use MAC-address when Radio-name is missing. Thanks to Pavel
+ Rochnyak. #2851, #2854
+ * RRDCacheD plugin: Time resolution has been improved to microseconds.
+ Thanks to Brian T. O'Neill. #3065
+ * Sensors plugin: Checks for upper limit of "SENSORS_API_VERSION" have
+ been removed, support for libsensors older than 3.0.0 has been
+ dropped. Thanks to Pavel Rochnyak. #3013, #3014
+ * SNMP plugin: New options "PluginInstance", "TypeInstance",
+ "TypeInstanceOID", "PluginInstanceOID", "FilterOID", "FilterValues"
+ and "FilterIgnoreSelected" have been added. Thanks to Pavel Rochnyak.
+ #2817, #2819
+ * SNMP Agent plugin: Multiple key indexes to snmp table and other new
+ features have been added, refactoring, coverity scan issues have been
+ fixed. Thanks to Marcin Mozejko. #2702, #2844
+ * Swap plugin: Support for Linux 2.4 has been dropped. Thanks to Pavel
+ Rochnyak. #2979
+ * Turbostat plugin: Configuration option "RestoreAffinityPolicy" has
+ been added. Thanks to Pablo Llopis. #2627
+ * Turbostat plugin: New metrics "P-states", "Turboboost", "Platform
+ TDP", "Uncore bus ratio" have been added. Thanks to Sexton Rory. #2806
+ * Turbostat plugin: Support of reporting GPU power on SKL has been
+ added. Thanks to Gordon Kelly. #2605
+ * virt plugin: Allow read "Hostname" from libvirt metadata. Thanks to
+ Mehdi ABAAKOUK. #2807
+ * virt plugin: Block info statistics for disk devices have been added.
+ Thanks to Radoslaw Jablonski. #2874
+ * Wireless plugin: A "bitrate" metric has been added. Thanks to Florian
+ Forster. #2950
+ * Write Graphite, Write Kafka plugins: Support for Graphite 1.1+ tag has
+ been added. Thanks to Dan Cech. #2631
+ * Write Prometheus plugin: Option "Host" has been added. Thanks to Pavel
+ Rochnyak. #2969
+ * Write Stackdriver plugin: New plugin to write to Google Stackdriver
+ Monitoring. Thanks to Florian Forster. #2472
+ * Write Syslog plugin: "write_syslog" plugin writes values lists as
+ syslog messages. Thanks to Shirly Radco. #3019
+ * Build System: A warning that pkgdatadir and pkglibdir were previously
+ defined has been fixed, additional plugins have been enabled,
+ GNULIB_DIR has been added to LDFLAGS in configure.ac on Windows.
+ Thanks to Sean Campbell. #2907, #2885, #2882
+ * Build System: Including "utils/mount/mount.h" has been fixed. Thanks
+ to Florian Forster. #3097
+ * Build System: The amount of output from ./configure has been reduced,
+ rendering of collectd-lua(5) manpage has been fixed, don't hide errors
+ when creating manpage. Thanks to Ruben Kerkhof. #3086, #3088, #3092
+ * collectd: A bug in "c_avl_iterator_prev" has been fixed. Thanks to
+ volth. #2917
+ * collectd: A stringop compiler warning has been fixed. Thanks to Ruben
+ Kerkhof, Juan Osorio Robles. #3021
+ * collectd: An invalid memory access in the "strjoin()" function has
+ been fixed. Thanks to Florian Forster. #3063
+ * collectd: collectd binary has been refactored. Thanks to Sean
+ Campbell, Sebastian Harl. #2745
+ * collectd: collectdmon cannot exit command line options parse loop has
+ been fixed. Thanks to takahashi-tsc. #2774
+ * collectd: Endianness checks for AIX have been added, gcc issue on Mac
+ byteorder has been fixed, fallback for endianness conversion has been
+ added. Thanks to Dagobert Michelsen. #2761, #2741, #2717
+ * collectd: Handle failure of simple config callbacks. Thanks to Ruben
+ Kerkhof. #3085
+ * collectd: Include "kstat.h" if available to provide "kstat_ctl_t",
+ include "kstat.h" when available. Thanks to Dagobert Michelsen. #2716,
+ #2711
+ * collectd: Parsing option for avoiding making BaseDir has been fixed.
+ Thanks to Mariusz Białończyk. #2856
+ * collectd: Remove empty "cmd_listval_t" data structure and related
+ no-op code. Thanks to Pavel Rochnyak. #2779
+ * collectd: src/daemon/plugin.c: Refactor plugin_load_file(),
+ src/utils_format_json.c: Remove chatty debug messages. Thanks to
+ Florian Forster. #2558, #2938
+ * collectd: Stop poisoning function in debug mode. Thanks to Ruben
+ Kerkhof. #2804
+ * collectd: The number of allocations when parsing types.db has been
+ reduced. Thanks to Ruben Kerkhof. #3091
+ * collectd: The organization of the source repository has been improved.
+ Thanks to Florian Forster. #2961
+ * collectd: Typos have been fixed. Thanks to Florian Forster, Jakub
+ Jankowski, William Pursell. #2944, #2692, #2643
+ * tree-wide: cleanup: cf_util_get* instead of local copy in plugins,
+ prefixed error reporting. Thanks to Pavel Rochnyak. #2833
+ * tree-wide: Some style issues have been fixed. Thanks to Ruben Kerkhof.
+ #3022
+ * tree-wide: "sstrerror()" has been replaced with "STRERRNO". Thanks to
+ Pavel Rochnyak. #2735
+ * AMQP1 plugin: Potential memory leaks found via scan-build have been
+ fixed, a typo in error log message has been fixed, cleanups. Thanks to
+ Andy Smith, Andrew Bays, Ruben Kerkhof. #2802, #2876, #2797
+ * Barometer plugin: Support to "libi2c-4.0" has been added. Thanks to
+ Pavel Rochnyak. #2783
+ * DBI, Oracle, PostgreSQL plugins: Fixes and improvements. Thanks to
+ Pavel Rochnyak. #1705
+ * Disk plugin: "HAVE_UDEV_H" has been changed to "HAVE_LIBUDEV_H".
+ Thanks to Dylan Stephano-Shachter. #2668
+ * Disk plugin: In linux, reset the disk when it disappears from
+ "/proc/diskstats". Thanks to Nikita Kozlov, Pavel Rochnyak. #2551
+ * DPDK Events, DPDK Stats plugins: Buffer size for parsing lcores has
+ been increased, a deprecation warning has been fixed, runtime config
+ file path has been fixed. Thanks to Kevin Laatz. #2722, #2840, #2924
+ * DPDK Stats plugin: A compilation issue has been fixed. Thanks to
+ Volodymyr Mytnyk. #2524
+ * GPS plugin: Build with gpsd version 3.18 has been fixed. Thanks to
+ Baruch Siach. #2947
+ * Intel RDT plugin: Compiler warnings have been fixed. Thanks to Ruben
+ Kerkhof. #3104
+ * Log Logstash plugin: Non-portable struct initialization with "{}" has
+ been fixed. Thanks to Florian Forster. #2988
+ * LUA plugin: A memory leak has been fixed. Thanks to Ruben Kerkhof.
+ #3090
+ * MySQL plugin: Properly cleanup dropped MySQL connections. Thanks to
+ Dhrupad Bhardwaj. #2704
+ * Netlink plugin: Truncation warnings have been fixed. Thanks to Ruben
+ Kerkhof. #2777
+ * NFS plugin: Message "Unexpected number of fields for NFSv4 server
+ statistics: 62" has been fixed. Thanks to Yedidyah Bar David. #2076
+ * NFS plugin: Number of fields for "NFSv4" has been fixed. Thanks to
+ Jan-Philipp Litza. #2915
+ * Notify Email plugin: All notification parameters have been included
+ into email. Thanks to Pavel Rochnyak. #2834
+ * NTPd plugin: Don't treat normal peers as refclocks, skip "0.0.0.0"
+ hosts in ntpd plugin. Thanks to Pavel Rochnyak, Ivan Kurnosov. #2822,
+ #2376
+ * OAuth plugin: src/utils_oauth.c: Renew OAuth tokens 30 seconds before
+ they expire. Thanks to Florian Forster. #2970
+ * OVS Stats plugin: A macro to populate counters list has been added,
+ value of "OpenFlow" has been corrected. Thanks to Matteo Croce. #2966,
+ #2963
+ * OVS Stats plugin: Code style, cleanup and improvements. Thanks to
+ Pavel Rochnyak. #3011, #3012
+ * OVS Stats, OVS Events plugins: utils_ovs: Avoid potential access of
+ freed memory, fixes. Thanks to Ciara Loftus, Mark Kavanagh. #2801,
+ #2731
+ * Processes plugin: Compilation has been fixed when ps_delay() is not
+ used. Thanks to Pavel Rochnyak. #2610
+ * Python plugin: A compilation warning with Python 3.7 has been fixed.
+ Thanks to Manoj Srivastava. #3042
+ * Redis plugin: Bugfixes, extended error reporting, persistent
+ connections and parallel polling, ability to select db for queries has
+ been fixed. Thanks to Pavel Rochnyak, skob. #2826, #2789
+ * Router OS plugin: Unset radio-name showing up as "(null)" has been
+ fixed. Thanks to melak. #2740
+ * RRDCacheD plugin: Cleanup rrdcached plugin a bit. Thanks to Pavel
+ Rochnyak. #3080
+ * RRDTool plugin: Error reporting has been extended. Thanks to Pavel
+ Rochnyak. #2825
+ * Sensors plugin: Support for humidity sensors has been added. Thanks to
+ Sarah Fischmann. #2913
+ * Sensu, OVS Stat, Turbostat, virt, OAuth, Write Prometheus, Intel RDT
+ plugins: Compiler warnings have been fixed. Thanks to Ruben Kerkhof.
+ #3093, #3098, #3099, #3100, #3102, #3103, #3104
+ * virt plugin: Code "do {} while(0)" around macro has been removed.
+ Thanks to Florian Forster. #2579
+ * virt plugin: Compiler warnings, a segfault in libvirt, typo in error
+ messages have been fixed. Thanks to Antoine Naud, Ruben Kerkhof, sarah
+ niuxu18. #2808, #2919, #2957
+ * virt plugin: Optional "virDomainGetCPUStats()" has been removed from
+ main flow, cleanup. Thanks to Pavel Rochnyak. #2972, #2978
+ * virt plugin: Tracking of VM state changes has been fixed. Thanks to
+ Radoslaw Jablonski. #2701
+ * Write MongoDB plugin: Plugin dependencies have been fixed. Thanks to
+ Pavel Rochnyak. #3010
+ * Write Prometheus plugin: A compilation issue on Mac OS X has been
+ fixed. Thanks to Florian Forster. #3059
+ * Write Redis plugin: Bug ""max_set_duration" deletes unexpected data"
+ has been fixed. Thanks to takahashi-tsc. #2773
+ * Write Stackdriver plugin: Potential NULL dereference and error
+ reporting have been fixed. Thanks to Florian Forster. #2960
+ * collectd.conf(5): a typo has been fixed, the tail plugin's
+ documentation has been improved. Thanks to Ruben Kerkhof, Florian
+ Forster. #3087, #2994
+ * collectd.conf.pod: virt: "Instances" option has been documented, a
+ clarifying example has been added. Thanks to Pavel Rochnyak, Fabien
+ Wernli. #2990, #2903
+ * collectd-python: "Import" configuration option has been documented.
+ Thanks to Tyler Harper. #2985
+ * collectd-snmp.pod: Document thread usage correctly. Thanks to Nathan
+ Ward. #3078
+ * CONTRIBUTING.md: Improve wording around ChangeLog; fix example,
+ document the new change log requirement / behavior. Thanks to Florian
+ Forster. #3061, #3054
+ * docs/review_comments.md: document with frequent review comments has
+ been started. Thanks to Florian Forster. #2964
+ * README: Include compiler defenses suggestion, do not point users to
+ non-existing file. Thanks to Kevin Laatz, Ruben Kerkhof. #2721, #2045
+
2018-10-23, Version 5.8.1
* collectd: Fix "BaseDir" option. Thanks to Mariusz Białończyk and
Pavel Rochnyak. #2857
newer libmicrohttpd. Thanks to Pavel Rochnyak. #2849
* Write Prometheus plugin: set "SO_REUSEADDRESS" on listening socket.
Thanks to Pavel Rochnyak. #2570, #2673
+ * Write Syslog plugin: The new "write_syslog" plugin writes value
+ lists as syslog messages. Thanks to Shirly Radco. #3019
2017-11-17, Version 5.8.0
* collectd: The core daemon is now completely licensed under the MIT
libheap.la \
libignorelist.la \
liblatency.la \
+ libllist.la \
liblookup.la \
libmetadata.la \
libmount.la \
src/daemon/utils_cache.h \
src/daemon/utils_complain.c \
src/daemon/utils_complain.h \
- src/daemon/utils_llist.c \
- src/daemon/utils_llist.h \
src/daemon/utils_random.c \
src/daemon/utils_random.h \
src/daemon/utils_subst.c \
libavltree.la \
libcommon.la \
libheap.la \
+ libllist.la \
liboconfig.la \
-lm \
$(COMMON_LIBS) \
else
collectd_SOURCES += src/daemon/cmd.c
endif
-
+
if BUILD_FEATURE_DAEMON
collectd_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
endif
src/utils/ignorelist/ignorelist.c \
src/utils/ignorelist/ignorelist.h
+libllist_la_SOURCES = \
+ src/daemon/utils_llist.c \
+ src/daemon/utils_llist.h
+
libmetadata_la_SOURCES = \
src/utils/metadata/meta_data.c \
src/utils/metadata/meta_data.h
chrony_la_LIBADD = -lm
endif
+if BUILD_PLUGIN_CHECK_UPTIME
+pkglib_LTLIBRARIES += check_uptime.la
+check_uptime_la_SOURCES = src/check_uptime.c
+check_uptime_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_CONNECTIVITY
+pkglib_LTLIBRARIES += connectivity.la
+connectivity_la_SOURCES = src/connectivity.c
+connectivity_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMNL_CFLAGS)
+connectivity_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+connectivity_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+connectivity_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS) $(BUILD_WITH_LIBMNL_LIBS) libignorelist.la
+endif
+
if BUILD_PLUGIN_CONNTRACK
pkglib_LTLIBRARIES += conntrack.la
conntrack_la_SOURCES = src/conntrack.c
pkglib_LTLIBRARIES += intel_rdt.la
intel_rdt_la_SOURCES = \
src/intel_rdt.c \
+ src/utils/proc_pids/proc_pids.c \
+ src/utils/proc_pids/proc_pids.h \
src/utils/config_cores/config_cores.h \
src/utils/config_cores/config_cores.c
intel_rdt_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBPQOS_CPPFLAGS)
intel_rdt_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPQOS_LDFLAGS)
intel_rdt_la_LIBADD = $(BUILD_WITH_LIBPQOS_LIBS)
+
+test_plugin_intel_rdt_SOURCES = \
+ src/intel_rdt_test.c \
+ src/utils/config_cores/config_cores.c \
+ src/utils/proc_pids/proc_pids.c \
+ src/daemon/configfile.c \
+ src/daemon/types_list.c
+test_plugin_intel_rdt_CPPFLAGS = $(AM_CPPFLAGS)
+test_plugin_intel_rdt_LDFLAGS = $(PLUGIN_LDFLAGS)
+test_plugin_intel_rdt_LDADD = liboconfig.la libplugin_mock.la
+check_PROGRAMS += test_plugin_intel_rdt
+TESTS += test_plugin_intel_rdt
+
+test_utils_proc_pids_SOURCES = \
+ src/utils/proc_pids/proc_pids_test.c \
+ src/testing.h
+test_utils_proc_pids_LDADD = libplugin_mock.la
+check_PROGRAMS += test_utils_proc_pids
+TESTS += test_utils_proc_pids
endif
if BUILD_PLUGIN_INTERFACE
lua_la_LIBADD = $(BUILD_WITH_LIBLUA_LIBS)
endif
-if BUILD_PLUGIN_LVM
-pkglib_LTLIBRARIES += lvm.la
-lvm_la_SOURCES = src/lvm.c
-lvm_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBLVM2APP_CPPFLAGS)
-lvm_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBLVM2APP_LDFLAGS)
-lvm_la_LIBADD = $(BUILD_WITH_LIBLVM2APP_LIBS)
-endif
-
if BUILD_PLUGIN_MADWIFI
pkglib_LTLIBRARIES += madwifi.la
madwifi_la_SOURCES = \
network_la_LDFLAGS += $(GCRYPT_LDFLAGS)
network_la_LIBADD += $(GCRYPT_LIBS)
endif
+
+test_plugin_network_SOURCES = \
+ src/network_test.c \
+ src/utils_fbhash.c \
+ src/daemon/configfile.c \
+ src/daemon/types_list.c
+test_plugin_network_CPPFLAGS = $(AM_CPPFLAGS) $(GCRYPT_CPPFLAGS)
+test_plugin_network_LDFLAGS = $(PLUGIN_LDFLAGS) $(GCRYPT_LDFLAGS)
+test_plugin_network_LDADD = \
+ libavltree.la \
+ liboconfig.la \
+ libplugin_mock.la \
+ libmetadata.la \
+ $(GCRYPT_LIBS)
+if BUILD_WITH_LIBSOCKET
+test_plugin_network_LDADD += -lsocket
+endif
+if BUILD_WITH_LIBNSL
+test_plugin_network_LDADD += -lnsl
+endif
+check_PROGRAMS += test_plugin_network
endif
if BUILD_PLUGIN_NFS
endif
endif
+if BUILD_PLUGIN_PROCEVENT
+pkglib_LTLIBRARIES += procevent.la
+procevent_la_SOURCES = src/procevent.c
+procevent_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+procevent_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+procevent_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS) libignorelist.la
+endif
+
if BUILD_PLUGIN_PROTOCOLS
pkglib_LTLIBRARIES += protocols.la
protocols_la_SOURCES = src/protocols.c
synproxy_la_LDFLAGS = $(PLUGIN_LDFLAGS)
endif
+if BUILD_PLUGIN_SYSEVENT
+pkglib_LTLIBRARIES += sysevent.la
+sysevent_la_SOURCES = src/sysevent.c
+sysevent_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+sysevent_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+sysevent_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS) libignorelist.la
+endif
+
if BUILD_PLUGIN_SYSLOG
pkglib_LTLIBRARIES += syslog.la
syslog_la_SOURCES = src/syslog.c
virt_la_LDFLAGS = $(PLUGIN_LDFLAGS)
virt_la_LIBADD = libignorelist.la $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-test_plugin_virt_SOURCES = src/virt_test.c
+test_plugin_virt_SOURCES = src/virt_test.c src/daemon/configfile.c \
+ src/daemon/types_list.c
test_plugin_virt_CPPFLAGS = $(AM_CPPFLAGS) \
$(BUILD_WITH_LIBVIRT_CPPFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
test_plugin_virt_LDFLAGS = $(PLUGIN_LDFLAGS) \
$(BUILD_WITH_LIBVIRT_LDFLAGS) $(BUILD_WITH_LIBXML2_LDFLAGS)
-test_plugin_virt_LDADD = libplugin_mock.la \
+test_plugin_virt_LDADD = liboconfig.la libplugin_mock.la \
$(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
check_PROGRAMS += test_plugin_virt
TESTS += test_plugin_virt
$(BUILD_WITH_LIBCURL_LIBS)
endif
+if BUILD_PLUGIN_WRITE_SYSLOG
+pkglib_LTLIBRARIES += write_syslog.la
+write_syslog_la_SOURCES = src/write_syslog.c
+write_syslog_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
if BUILD_PLUGIN_WRITE_TSDB
pkglib_LTLIBRARIES += write_tsdb.la
write_tsdb_la_SOURCES = src/write_tsdb.c
am__v_POD2MAN_C_1 =
.pod.1:
- $(AM_V_POD2MAN_C)pod2man --release=$(VERSION) --center=$(PACKAGE) $< \
- >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
- @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
- then \
- echo "$@ has some POD errors!"; false; \
- fi
+ $(AM_V_POD2MAN_C)pod2man --release=$(VERSION) --center=$(PACKAGE) $< $@
.pod.5:
- $(AM_V_POD2MAN_C)pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< \
- >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
- @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
- then \
- echo "$@ has some POD errors!"; false; \
- fi
+ $(AM_V_POD2MAN_C)pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< $@
V_PROTOC = $(v_protoc_@AM_V@)
v_protoc_ = $(v_protoc_@AM_DEFAULT_V@)
- chrony
Chrony daemon statistics: Local clock drift, offset to peers, etc.
+ - connectivity
+ Event-based interface status.
+
- conntrack
Number of nf_conntrack entries.
collectd without the need to start a heavy interpreter every interval.
See collectd-lua(5) for details.
- - lvm
- Size of “Logical Volumes” (LV) and “Volume Groups” (VG) of Linux'
- “Logical Volume Manager” (LVM).
-
- madwifi
Queries very detailed usage statistics from wireless LAN adapters and
interfaces that use the Atheros chipset and the MadWifi driver.
- processes
Process counts: Number of running, sleeping, zombie, ... processes.
+ - procevent
+ Listens for process starts and exits via netlink.
+
- protocols
Counts various aspects of network protocols such as IP, TCP, UDP, etc.
Acts as a StatsD server, reading values sent over the network from StatsD
clients and calculating rates and other aggregates out of these values.
+ - sysevent
+ Listens to rsyslog events and submits matched values.
+
- swap
Pages swapped out onto hard disk or whatever is called `swap' by the OS..
Sends data to Sensu, a stream processing and monitoring system, via the
Sensu client local TCP socket.
+ - write_syslog
+ Sends data in syslog format, using TCP, where the message
+ contains the metric in human or JSON format.
+
- write_tsdb
Sends data OpenTSDB, a scalable no master, no shared state time series
database.
Used by the `lua' plugin. Currently, Lua 5.1 and later are supported.
<https://www.lua.org/>
- * liblvm2 (optional)
- Used by the `lvm' plugin.
- <ftp://sources.redhat.com/pub/lvm2/>
-
* libmemcached (optional)
Used by the `memcachec' plugin to connect to a memcache daemon.
<http://tangent.org/552/libmemcached.html>
$v{'type_instance'} = $cpu_instances[$key];
$v{'values'} = [ $counters[$key] ];
plugin_dispatch_values(\%v);
+ }
}
}
-}
sub df_read {
my $veid = shift;
$v{'type_instance'} = $val;
$v{'values'} = [ $parts[5] * ($parts[6] - $parts[7]), $parts[5] * $parts[7] ];
plugin_dispatch_values(\%v);
-}
+ }
}
sub load_read {
$v{'type_instance'} = $key;
$v{'values'} = [ $ps_states->{$key} ];
plugin_dispatch_values(\%v);
-}
+ }
}
sub users_read {
kstat.h \
kvm.h \
libgen.h \
+ locale.h \
mntent.h \
mnttab.h \
netdb.h \
# }}}
-# For the dns plugin
-AC_CHECK_HEADERS([arpa/nameser.h])
-AC_CHECK_HEADERS([arpa/nameser_compat.h], [], [],
- [[
- #if HAVE_ARPA_NAMESER_H
- # include <arpa/nameser.h>
- #endif
- ]]
-)
-
AC_CHECK_HEADERS([net/if_arp.h], [], [],
[[
#if HAVE_SYS_SOCKET_H
#
AC_CHECK_FUNCS_ONCE([ \
asprintf \
- closelog \
- getaddrinfo \
- getgrnam_r \
- getnameinfo \
+ execvpe \
getpwnam \
getpwnam_r \
- gettimeofday \
if_indextoname \
- openlog \
- regcomp \
- regerror \
- regexec \
- regfree \
- select \
- setenv \
setgroups \
- strcasecmp \
- strdup \
- strncasecmp \
- sysconf
+ setlocale
]
)
AC_FUNC_STRERROR_R
-SAVE_CFLAGS="$CFLAGS"
-CFLAGS="-Wall -Werror"
+if test "x$GCC" = "xyes"; then
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -Wall -Werror"
+fi
SAVE_LDFLAGS="$LDFLAGS"
LDFLAGS=""
if test "x$ac_system" = "xWindows"; then
AM_CONDITIONAL([BUILD_WITH_LIBSOCKET], [test "x$socket_needs_socket" = "xyes"])
AM_CONDITIONAL([BUILD_WITH_GNULIB], [test "x$socket_needs_gnulib" = "xyes"])
+AC_CHECK_FUNCS([inet_ntop],
+ [],
+ [
+ AC_CHECK_LIB([nsl], [inet_ntop],
+ [inet_ntop_needs_nsl="yes"],
+ [AC_MSG_ERROR([cannot find inet_ntop() in libnsl])]
+ )
+ ]
+)
+AM_CONDITIONAL([BUILD_WITH_LIBNSL], [test "x$inet_ntop_needs_nsl" = "xyes"])
+
clock_gettime_needs_posix4="no"
AC_CHECK_FUNCS([clock_gettime],
[have_clock_gettime="yes"],
AC_COMPILE_IFELSE(
[
AC_LANG_PROGRAM(
- [[#include "$srcdir/src/utils_mount.h"]],
+ [[#include "$srcdir/src/utils/mount/mount.h"]],
[[
FILE *fh;
struct mntent *me;
AC_COMPILE_IFELSE(
[
AC_LANG_PROGRAM(
- [[#include "$srcdir/src/utils_mount.h"]],
+ [[#include "$srcdir/src/utils/mount/mount.h"]],
[[
FILE *fh;
struct mnttab mt;
LDFLAGS="$LDFLAGS $LIBAQUAERO5_LDFLAGS"
if test "x$with_libaquaero5" = "xyes"; then
- if test "x$LIBAQUAERO5_CFLAGS" != "x"; then
- AC_MSG_NOTICE([libaquaero5 CPPFLAGS: $LIBAQUAERO5_CFLAGS])
- fi
AC_CHECK_HEADERS([libaquaero5.h],
[with_libaquaero5="yes"],
[with_libaquaero5="no (libaquaero5.h not found)"]
fi
if test "x$with_libaquaero5" = "xyes"; then
- if test "x$LIBAQUAERO5_LDFLAGS" != "x"; then
- AC_MSG_NOTICE([libaquaero5 LDFLAGS: $LIBAQUAERO5_LDFLAGS])
- fi
AC_CHECK_LIB([aquaero5], libaquaero5_poll,
[with_libaquaero5="yes"],
[with_libaquaero5="no (symbol 'libaquaero5_poll' not found)"]
LDFLAGS="$LDFLAGS $LIBHIREDIS_LDFLAGS"
if test "x$with_libhiredis" = "xyes"; then
- if test "x$LIBHIREDIS_CPPFLAGS" != "x"; then
- AC_MSG_NOTICE([libhiredis CPPFLAGS: $LIBHIREDIS_CPPFLAGS])
- fi
AC_CHECK_HEADERS([hiredis/hiredis.h],
[with_libhiredis="yes"],
[with_libhiredis="no (hiredis.h not found)"]
fi
if test "x$with_libhiredis" = "xyes"; then
- if test "x$LIBHIREDIS_LDFLAGS" != "x"; then
- AC_MSG_NOTICE([libhiredis LDFLAGS: $LIBHIREDIS_LDFLAGS])
- fi
AC_CHECK_LIB([hiredis], [redisCommand],
[with_libhiredis="yes"],
[with_libhiredis="no (symbol 'redisCommand' not found)"]
LIBS="$LIBS $GCRYPT_LIBS"
if test "x$with_libgcrypt" = "xyes"; then
- if test "x$GCRYPT_CPPFLAGS" != "x"; then
- AC_MSG_NOTICE([gcrypt CPPFLAGS: $GCRYPT_CPPFLAGS])
- fi
AC_CHECK_HEADERS([gcrypt.h],
[with_libgcrypt="yes"],
[with_libgcrypt="no (gcrypt.h not found)"]
else
AC_MSG_RESULT([no])
with_libgrpcpp="no (requires C++11 support)"
+ with_libprotobuf="no (<google/protobuf/util/time_util.h> requires C++11 support)"
fi
fi
fi; fi
fi
-if test "x$JAVA_CPPFLAGS" != "x"; then
- AC_MSG_NOTICE([Building with JAVA_CPPFLAGS set to: $JAVA_CPPFLAGS])
-fi
-if test "x$JAVA_CFLAGS" != "x"; then
- AC_MSG_NOTICE([Building with JAVA_CFLAGS set to: $JAVA_CFLAGS])
-fi
-if test "x$JAVA_LDFLAGS" != "x"; then
- AC_MSG_NOTICE([Building with JAVA_LDFLAGS set to: $JAVA_LDFLAGS])
-fi
-if test "x$JAVA_LIBS" != "x"; then
- AC_MSG_NOTICE([Building with JAVA_LIBS set to: $JAVA_LIBS])
-fi
if test "x$JAVAC" = "x"; then
with_javac_path="$PATH"
if test "x$with_java_home" != "x"; then
if test "x$with_java" = "xyes"; then
JAVA_LIBS="$JAVA_LIBS -ljvm"
- AC_MSG_NOTICE([Building with JAVA_LIBS set to: $JAVA_LIBS])
fi
CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$LDFLAGS $LIBLDAP_LDFLAGS"
if test "x$with_libldap" = "xyes"; then
- if test "x$LIBLDAP_CPPFLAGS" != "x"; then
- AC_MSG_NOTICE([libldap CPPFLAGS: $LIBLDAP_CPPFLAGS])
- fi
-
AC_CHECK_HEADERS([ldap.h],
[with_libldap="yes"],
[with_libldap="no ('ldap.h' not found)"]
fi
if test "x$with_libldap" = "xyes"; then
- if test "x$LIBLDAP_LDFLAGS" != "x"; then
- AC_MSG_NOTICE([libldap LDFLAGS: $LIBLDAP_LDFLAGS])
- fi
-
AC_CHECK_LIB([ldap], [ldap_initialize],
[with_libldap="yes"],
[with_libldap="no (symbol 'ldap_initialize' not found)"]
AC_SUBST(BUILD_WITH_LIBLUA_LIBS)
# }}}
-# --with-liblvm2app {{{
-AC_ARG_WITH([liblvm2app],
- [AS_HELP_STRING([--with-liblvm2app@<:@=PREFIX@:>@], [Path to liblvm2app.])],
- [
- if test "x$withval" = "xno"; then
- with_liblvm2app="no"
- else
- with_liblvm2app="yes"
- if test "x$withval" != "xyes"; then
- with_liblvm2app_cppflags="-I$withval/include"
- with_liblvm2app_ldflags="-L$withval/lib"
- fi
- fi
- ],
- [
- if test "x$ac_system" = "xLinux"; then
- with_liblvm2app="yes"
- else
- with_liblvm2app="no (Linux only library)"
- fi
- ]
-)
-
-if test "x$with_liblvm2app" = "xyes"; then
- SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
-
- AC_CHECK_HEADERS([lvm2app.h],
- [with_liblvm2app="yes"],
- [with_liblvm2app="no (lvm2app.h not found)"]
- )
-
- CPPFLAGS="$SAVE_CPPFLAGS"
-fi
-
-if test "x$with_liblvm2app" = "xyes"; then
- SAVE_CPPFLAGS="$CPPFLAGS"
- SAVE_LDFLAGS="$LDFLAGS"
- CPPFLAGS="$CPPFLAGS $with_liblvm2app_cppflags"
- LDFLAGS="$LDFLAGS $with_liblvm2app_ldflags"
-
- AC_CHECK_LIB([lvm2app], [lvm_lv_get_property],
- [with_liblvm2app="yes"],
- [with_liblvm2app="no (Symbol 'lvm_lv_get_property' not found)"]
- )
-
- CPPFLAGS="$SAVE_CPPFLAGS"
- LDFLAGS="$SAVE_LDFLAGS"
-fi
-
-if test "x$with_liblvm2app" = "xyes"; then
- BUILD_WITH_LIBLVM2APP_CPPFLAGS="$with_liblvm2app_cppflags"
- BUILD_WITH_LIBLVM2APP_LDFLAGS="$with_liblvm2app_ldflags"
- BUILD_WITH_LIBLVM2APP_LIBS="-llvm2app"
-fi
-
-AC_SUBST([BUILD_WITH_LIBLVM2APP_CPPFLAGS])
-AC_SUBST([BUILD_WITH_LIBLVM2APP_LDFLAGS])
-AC_SUBST([BUILD_WITH_LIBLVM2APP_LIBS])
-# }}}
-
# --with-libmemcached {{{
AC_ARG_WITH([libmemcached],
[AS_HELP_STRING([--with-libmemcached@<:@=PREFIX@:>@], [Path to libmemcached.])],
# configure using pkg-config
if test "x$with_libmodbus" = "xuse_pkgconfig"; then
- AC_MSG_NOTICE([Checking for libmodbus using $PKG_CONFIG])
$PKG_CONFIG --exists 'libmodbus' 2>/dev/null
if test $? -ne 0; then
with_libmodbus="no (pkg-config doesn't know libmodbus)"
CPPFLAGS="$CPPFLAGS $LIBMONGOC_CFLAGS"
- if test "x$CPPFLAGS" != "x"; then
- AC_MSG_NOTICE([libmongoc CPPFLAGS: $LIBMONGOC_CFLAGS])
- fi
-
AC_CHECK_HEADERS([mongoc.h],
[with_libmongoc="yes"],
[with_libmongoc="no ('mongoc.h' not found)"]
CPPFLAGS="$CPPFLAGS $LIBMONGOC_CFLAGS"
LDFLAGS="$LDFLAGS $LIBMONGOC_LDFLAGS"
- if test "x$LIBMONGOC_LDFLAGS" != "x"; then
- AC_MSG_NOTICE([libmongoc LDFLAGS: $LIBMONGOC_LDFLAGS])
- fi
-
AC_CHECK_LIB([mongoc-1.0], [mongoc_init],
[with_libmongoc="yes"],
[with_libmongoc="no (symbol 'mongoc_init' not found)"]
LDFLAGS="$LDFLAGS $LIBNETAPP_LDFLAGS"
if test "x$with_libnetapp" = "xyes"; then
- if test "x$LIBNETAPP_CPPFLAGS" != "x"; then
- AC_MSG_NOTICE([netapp CPPFLAGS: $LIBNETAPP_CPPFLAGS])
- fi
AC_CHECK_HEADERS([netapp_api.h],
[with_libnetapp="yes"],
[with_libnetapp="no (netapp_api.h not found)"]
fi
if test "x$with_libnetapp" = "xyes"; then
- if test "x$LIBNETAPP_LDFLAGS" != "x"; then
- AC_MSG_NOTICE([netapp LDFLAGS: $LIBNETAPP_LDFLAGS])
- fi
-
if test "x$LIBNETAPP_LIBS" = "x"; then
LIBNETAPP_LIBS="$PTHREAD_LIBS -lxml -ladt -lssl -lm -lcrypto -lz"
fi
- AC_MSG_NOTICE([netapp LIBS: $LIBNETAPP_LIBS])
-
AC_CHECK_LIB([netapp], [na_server_invoke_elem],
[with_libnetapp="yes"],
[with_libnetapp="no (symbol na_server_invoke_elem not found)"],
SAVE_CPPFLAGS="$CPPFLAGS"
SAVE_LDFLAGS="$LDFLAGS"
SAVE_LIBS="$LIBS"
- CPPFLAGS="$CPPFLAGS $with_libnetsnmp_cppflags -Wall -Werror"
+ CPPFLAGS="$CPPFLAGS $with_libnetsnmp_cppflags"
+ if test "x$GCC" = "xyes"; then
+ CPPFLAGS="$CPPFLAGS -Wall -Werror"
+ fi
LDFLAGS="$LDFLAGS $with_libnetsnmp_ldflags"
LIBS="$LIBS -lnetsnmp"
)
AC_CHECK_LIB([netsnmpagent], [init_agent],
- [with_libnetsnmpagent="yes"],
+ [
+ # libnetsnmp can be built without mib loading support
+ AC_CHECK_LIB([netsnmp], [get_tree],
+ [with_libnetsnmpagent="yes"],
+ [with_libnetsnmpagent="no (libnetsnmp doesn't support mib loading)"]
+ )
+ ],
[with_libnetsnmpagent="no (libnetsnmpagent not found)"],
[$libnetsnmphelpers]
)
fi
if test "x$with_libnetsnmpagent" = "xyes"; then
+ BUILD_WITH_LIBNETSNMPAGENT_CPPFLAGS="$with_libnetsnmpagent_cppflags"
+ BUILD_WITH_LIBNETSNMPAGENT_LDFLAGS="$with_libnetsnmpagent_ldflags"
BUILD_WITH_LIBNETSNMPAGENT_LIBS="-lnetsnmpagent $libnetsnmphelpers"
fi
# (see issues #41 and #42)
SAVE_CFLAGS="$CFLAGS"
SAVE_LIBS="$LIBS"
- CFLAGS="$CFLAGS $PERL_CFLAGS -Wall -Werror"
+ CFLAGS="$CFLAGS $PERL_CFLAGS"
+ if test "x$GCC" = "xyes"; then
+ CFLAGS="$CFLAGS -Wall -Werror"
+ fi
LIBS="$LIBS $PERL_LIBS"
AC_CACHE_CHECK([for broken Perl_load_module()],
AC_CHECK_LIB([protobuf], [main],
[
SAVE_CPPFLAGS="$CPPFLAGS"
- CPPFLAGS="$with_libprotobuf_cppflags $PROTOBUF_CFLAGS"
+ CPPFLAGS="-std=c++11 $with_libprotobuf_cppflags $PROTOBUF_CFLAGS"
if test "x$PROTOBUF_LIBS" = "x"
then
PROTOBUF_LIBS="-lprotobuf"
if test $? -ne 0; then
with_libpython="no"
fi
- LIBPYTHON_LDFLAGS="`${PYTHON_CONFIG} --ldflags`"
+ LIBPYTHON_LDFLAGS="`${PYTHON_CONFIG} --ldflags --embed`" || LIBPYTHON_LDFLAGS="`${PYTHON_CONFIG} --ldflags`"
if test $? -ne 0; then
with_libpython="no"
fi
- LIBPYTHON_LIBS="`${PYTHON_CONFIG} --libs`"
+ LIBPYTHON_LIBS="`${PYTHON_CONFIG} --libs --embed`" || LIBPYTHON_LIBS="`${PYTHON_CONFIG} --libs`"
if test $? -ne 0; then
with_libpython="no"
fi
with_libtokyotyrant="$withval"
else
with_libtokyotyrant_cppflags="-I$withval/include"
- with_libtokyotyrant_ldflags="-L$withval/include"
+ with_libtokyotyrant_ldflags="-L$withval/lib"
with_libtokyotyrant_libs="-ltokyotyrant"
with_libtokyotyrant="yes"
fi
else if test "x$withval" = "xyes"; then
with_libupsclient="use_pkgconfig"
else
- if test -x "$withval"; then
+ if test -f "$withval" && test -x "$withval"; then
with_libupsclient_config="$withval"
with_libupsclient="use_libupsclient_config"
else if test -x "$withval/bin/libupsclient-config"; then
# configure using pkg-config
if test "x$with_libupsclient" = "xuse_pkgconfig"; then
- AC_MSG_NOTICE([Checking for libupsclient using $PKG_CONFIG])
$PKG_CONFIG --exists 'libupsclient' 2>/dev/null
if test $? -ne 0; then
with_libupsclient="no (pkg-config doesn't know libupsclient)"
fi
if test "x$with_libxmms" = "xyes"; then
- SAVE_CPPFLAGS="$CFLAGS"
+ SAVE_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$with_xmms_cflags"
AC_CHECK_HEADER([xmmsctrl.h],
plugin_bind="no"
plugin_ceph="no"
plugin_cgroups="no"
+plugin_connectivity="no"
plugin_conntrack="no"
plugin_contextswitch="no"
plugin_cpu="no"
plugin_perl="no"
plugin_pinba="no"
plugin_processes="no"
+plugin_procevent="no"
plugin_protocols="no"
plugin_python="no"
plugin_serial="no"
plugin_smart="no"
plugin_swap="no"
plugin_synproxy="no"
+plugin_sysevent="no"
plugin_tape="no"
plugin_tcpconns="no"
plugin_ted="no"
plugin_ipc="yes"
plugin_irq="yes"
plugin_load="yes"
- plugin_lvm="yes"
plugin_mcelog="yes"
plugin_memory="yes"
plugin_nfs="yes"
if test "x$with_libyajl" = "xyes" && test "x$with_libyajl2" = "xyes"; then
plugin_ovs_events="yes"
plugin_ovs_stats="yes"
+ plugin_procevent="yes"
+
+ if test "x$with_libmnl" = "xyes"; then
+ plugin_connectivity="yes"
+ fi
fi
if test "x$have_pci_regs_h" = "xyes"; then
# FreeBSD
if test "x$ac_system" = "xFreeBSD"; then
+ plugin_cpufreq="yes"
plugin_disk="yes"
plugin_zfs_arc="yes"
fi
if test "x$with_libyajl" = "xyes"; then
plugin_ceph="yes"
+ plugin_sysevent="yes"
fi
if test "x$have_processor_info" = "xyes"; then
plugin_df="yes"
fi
-if test "x$c_cv_have_getmntent_r" = "xyes"; then
+if test "x$have_getmntent_r" = "xyes"; then
plugin_df="yes"
fi
AC_PLUGIN([ceph], [$plugin_ceph], [Ceph daemon statistics])
AC_PLUGIN([cgroups], [$plugin_cgroups], [CGroups CPU usage accounting])
AC_PLUGIN([chrony], [yes], [Chrony statistics])
+AC_PLUGIN([check_uptime], [yes], [Notify about uptime reset])
+AC_PLUGIN([connectivity], [$plugin_connectivity], [Network interface up/down events])
AC_PLUGIN([conntrack], [$plugin_conntrack], [nf_conntrack statistics])
AC_PLUGIN([contextswitch], [$plugin_contextswitch], [context switch statistics])
AC_PLUGIN([cpu], [$plugin_cpu], [CPU usage statistics])
AC_PLUGIN([logfile], [yes], [File logging plugin])
AC_PLUGIN([lpar], [$with_perfstat], [AIX logical partitions statistics])
AC_PLUGIN([lua], [$with_liblua], [Lua plugin])
-AC_PLUGIN([lvm], [$with_liblvm2app], [LVM statistics])
AC_PLUGIN([madwifi], [$have_linux_wireless_h], [Madwifi wireless statistics])
AC_PLUGIN([match_empty_counter], [yes], [The empty counter match])
AC_PLUGIN([match_hashed], [yes], [The hashed match])
AC_PLUGIN([postgresql], [$with_libpq], [PostgreSQL database statistics])
AC_PLUGIN([powerdns], [yes], [PowerDNS statistics])
AC_PLUGIN([processes], [$plugin_processes], [Process statistics])
+AC_PLUGIN([procevent], [$plugin_procevent], [Process event (start, stop) statistics])
AC_PLUGIN([protocols], [$plugin_protocols], [Protocol (IP, TCP, ...) statistics])
AC_PLUGIN([python], [$plugin_python], [Embed a Python interpreter])
AC_PLUGIN([redis], [$with_libhiredis], [Redis 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([sysevent], [$plugin_sysevent], [rsyslog events])
AC_PLUGIN([syslog], [$have_syslog], [Syslog logging plugin])
AC_PLUGIN([table], [yes], [Parsing of tabular data])
AC_PLUGIN([tail], [yes], [Parsing of logfiles])
AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics])
AC_PLUGIN([write_graphite], [yes], [Graphite / Carbon output plugin])
AC_PLUGIN([write_http], [$with_libcurl], [HTTP output plugin])
-AC_PLUGIN([write_stackdriver], [$plugin_write_stackdriver], [Google Stackdriver Monitoring output plugin])
AC_PLUGIN([write_kafka], [$with_librdkafka], [Kafka output plugin])
AC_PLUGIN([write_log], [yes], [Log output plugin])
AC_PLUGIN([write_mongodb], [$with_libmongoc], [MongoDB output plugin])
AC_PLUGIN([write_redis], [$with_libhiredis], [Redis output plugin])
AC_PLUGIN([write_riemann], [$with_libriemann_client], [Riemann output plugin])
AC_PLUGIN([write_sensu], [yes], [Sensu output plugin])
+AC_PLUGIN([write_stackdriver], [$plugin_write_stackdriver], [Google Stackdriver Monitoring output plugin])
+AC_PLUGIN([write_syslog], [yes], [Syslog output plugin])
AC_PLUGIN([write_tsdb], [yes], [TSDB output plugin])
AC_PLUGIN([xencpu], [$plugin_xencpu], [Xen Host CPU usage])
AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics])
AC_CONFIG_FILES([src/libcollectdclient/collectd/lcc_features.h])
-AM_CFLAGS="-Wall"
-AM_CXXFLAGS="-Wall"
-if test "x$enable_werror" != "xno"; then
- AM_CFLAGS="$AM_CFLAGS -Werror"
- AM_CXXFLAGS="$AM_CXXFLAGS -Werror"
+if test "x$GCC" = "xyes"; then
+ AM_CFLAGS="-Wall"
+ AM_CXXFLAGS="-Wall"
+ if test "x$enable_werror" != "xno"; then
+ AM_CFLAGS="$AM_CFLAGS -Werror"
+ AM_CXXFLAGS="$AM_CXXFLAGS -Werror"
+ fi
fi
AC_SUBST([AM_CFLAGS])
AC_MSG_RESULT([ libkvm . . . . . . . $with_libkvm])
AC_MSG_RESULT([ libldap . . . . . . . $with_libldap])
AC_MSG_RESULT([ liblua . . . . . . . $with_liblua])
-AC_MSG_RESULT([ liblvm2app . . . . . $with_liblvm2app])
AC_MSG_RESULT([ libmemcached . . . . $with_libmemcached])
AC_MSG_RESULT([ libmicrohttpd . . . . $with_libmicrohttpd])
AC_MSG_RESULT([ libmnl . . . . . . . $with_libmnl])
AC_MSG_RESULT([ ceph . . . . . . . . $enable_ceph])
AC_MSG_RESULT([ cgroups . . . . . . . $enable_cgroups])
AC_MSG_RESULT([ chrony. . . . . . . . $enable_chrony])
+AC_MSG_RESULT([ check_uptime. . . . . $enable_check_uptime])
+AC_MSG_RESULT([ connectivity. . . . . $enable_connectivity])
AC_MSG_RESULT([ conntrack . . . . . . $enable_conntrack])
AC_MSG_RESULT([ contextswitch . . . . $enable_contextswitch])
AC_MSG_RESULT([ cpu . . . . . . . . . $enable_cpu])
AC_MSG_RESULT([ log_logstash . . . . $enable_log_logstash])
AC_MSG_RESULT([ lpar . . . . . . . . $enable_lpar])
AC_MSG_RESULT([ lua . . . . . . . . . $enable_lua])
-AC_MSG_RESULT([ lvm . . . . . . . . . $enable_lvm])
AC_MSG_RESULT([ madwifi . . . . . . . $enable_madwifi])
AC_MSG_RESULT([ match_empty_counter . $enable_match_empty_counter])
AC_MSG_RESULT([ match_hashed . . . . $enable_match_hashed])
AC_MSG_RESULT([ postgresql . . . . . $enable_postgresql])
AC_MSG_RESULT([ powerdns . . . . . . $enable_powerdns])
AC_MSG_RESULT([ processes . . . . . . $enable_processes])
+AC_MSG_RESULT([ procevent . . . . . . $enable_procevent])
AC_MSG_RESULT([ protocols . . . . . . $enable_protocols])
AC_MSG_RESULT([ python . . . . . . . $enable_python])
AC_MSG_RESULT([ redis . . . . . . . . $enable_redis])
AC_MSG_RESULT([ statsd . . . . . . . $enable_statsd])
AC_MSG_RESULT([ swap . . . . . . . . $enable_swap])
AC_MSG_RESULT([ synproxy . . . . . . $enable_synproxy])
+AC_MSG_RESULT([ sysevent. . . . . . . $enable_sysevent])
AC_MSG_RESULT([ syslog . . . . . . . $enable_syslog])
AC_MSG_RESULT([ table . . . . . . . . $enable_table])
AC_MSG_RESULT([ tail_csv . . . . . . $enable_tail_csv])
AC_MSG_RESULT([ write_riemann . . . . $enable_write_riemann])
AC_MSG_RESULT([ write_sensu . . . . . $enable_write_sensu])
AC_MSG_RESULT([ write_stackdriver . . $enable_write_stackdriver])
+AC_MSG_RESULT([ write_syslog . . . . $enable_write_syslog])
AC_MSG_RESULT([ write_tsdb . . . . . $enable_write_tsdb])
AC_MSG_RESULT([ xencpu . . . . . . . $enable_xencpu])
AC_MSG_RESULT([ xmms . . . . . . . . $enable_xmms])
Collectd network protocol implementation.
"""
-import socket,struct,sys
+import socket,struct
import platform
if platform.python_version() < '2.8.0':
# Python 2.7 and below io.StringIO does not like unicode
function nav_calculate_event_x (e)
{
var pos = 0;
- var off = 0;
if (!e || !e.target)
return;
- off = nav_calculate_offset_x (e.target);
+ nav_calculate_offset_x (e.target);
if (e.pageX || e.pageY)
{
APT::Install-Recommends "1";
-APT::Install-Suggests "0";
+APT::Install-Suggests "1";
APT::Get::Assume-Yes "1";
APT::Get::AutomaticRemove "1";
-FROM debian:stable
+FROM debian:stable-slim
ENV DEBIAN_FRONTEND noninteractive
COPY 50docker-apt-conf /etc/apt/apt.conf.d/
ENV LD_PRELOAD /usr/src/rootfs_prefix/rootfs_prefix.so
-CMD [ "/usr/sbin/collectd", "-f"]
+ENTRYPOINT ["/usr/sbin/collectd"]
+CMD ["-f"]
newOption.setAttribute('style', 'font-style: italic');
newOption.appendChild(document.createTextNode('- please select -'));
select.appendChild(newOption);
- for (i = 0; i < optCnt; i++) {
- newOption = document.createElement("option");
+ for (var i = 0; i < optCnt; i++) {
+ var newOption = document.createElement("option");
newOption.value = options[i].firstChild ? options[i].firstChild.data : '';
if (keepSelection && newOption.value == oldValue)
newOption.setAttribute('selected', 'selected');
function ListOfGraph(response) {
var graphs = response ? response.getElementsByTagName('graph') : null;
if (graphs && graphs.length > 0) {
- for (i = 0; i < graphs.length; i++)
+ for (var i = 0; i < graphs.length; i++)
GraphDoAppend(graphs[i].getAttribute('host'), graphs[i].getAttribute('plugin'), graphs[i].getAttribute('plugin_instance'),
graphs[i].getAttribute('type'), graphs[i].getAttribute('type_instance'), graphs[i].getAttribute('timespan'),
graphs[i].getAttribute('tinyLegend') == '1', graphs[i].getAttribute('logarithmic') == '1');
var graph_id = 'graph_'+nextGraphId++;
var graph_src = graph_url+'?host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst)+'&type='+encodeURIComponent(type);
var graph_alt = '';
- var grap_title = '';
+ var graph_title = '';
if (tinst == '@') {
graph_alt = host+'/'+plugin+(pinst.length > 0 ? '-'+pinst : '')+'/'+type;
graph_title = type+' of '+plugin+(pinst.length > 0 ? '-'+pinst : '')+' plugin for '+host;
graphList.push(graph_id+' '+encodeURIComponent(graph_alt)+(logarithmic ? '&logarithmic=1' : '')+(tinyLegend ? '&tinylegend=1' : '')+'×pan='+encodeURIComponent(timespan));
// Graph container
- newGraph = document.createElement('div');
+ var newGraph = document.createElement('div');
newGraph.setAttribute('class', 'graph');
newGraph.setAttribute('id', graph_id);
// Graph cell + graph
- newImg = document.createElement('img');
+ var newImg = document.createElement('img');
newImg.setAttribute('src', graph_src);
newImg.setAttribute('alt', graph_alt);
newImg.setAttribute('title', graph_title);
document.getElementById('ge_graphid').value = graph;
document.getElementById('ge_tinylegend').checked = src_url.match(/&tinylegend=1/);
document.getElementById('ge_logarithmic').checked = src_url.match(/&logarithmic=1/);
- for (i = 0; i < ts_sel.options.length; i++)
+ for (var i = 0; i < ts_sel.options.length; i++)
if (ts_sel.options[i].value == ts) {
ts_sel.selectedIndex = i;
break;
imgs[imgCnt].setAttribute('src', newSrc);
var myList = Array();
- for (i = 0; i < graphList.length; i++)
+ for (var i = 0; i < graphList.length; i++)
if (graphList[i].substring(0, graphId.length) == graphId && graphList[i].charAt(graphId.length) == ' ') {
newSrc = graphList[i];
newSrc = newSrc.replace(/&logarithmic=[^&]*/, '');
document.getElementById('nograph').style.display = 'block';
var myList = Array();
- for (i = 0; i < graphList.length; i++)
+ for (var i = 0; i < graphList.length; i++)
if (graphList[i].substring(0, graphId.length) == graphId && graphList[i].charAt(graphId.length) == ' ')
continue;
else
var graphId = graph == null ? document.getElementById('ge_graphid').value : graph;
var childCnt = graphs.childNodes.length;
var prevGraph = null;
- for (i = 0; i < childCnt; i++)
+ for (var i = 0; i < childCnt; i++)
if (graphs.childNodes[i].nodeName == 'div' || graphs.childNodes[i].nodeName == 'DIV') {
if (graphs.childNodes[i].id == 'nograph') {
// Skip
var childCnt = graphs.childNodes.length;
var nextGraph = null;
var myGraph = null;
- for (i = 0; i < childCnt; i++)
+ for (var i = 0; i < childCnt; i++)
if (graphs.childNodes[i].nodeName == 'div' || graphs.childNodes[i].nodeName == 'DIV') {
if (graphs.childNodes[i].id == 'nograph') {
// Skip
break;
}
}
- for (i = 0; i < graphList.length; i++)
- if (graphList[i].substring(0, graphId.length) == graphId && graphList[i].charAt(graphId.length) == ' ') {
- if (i+1 < graphList.length) {
- var tmp = graphList[i+1];
- graphList[i+1] = graphList[i];
- graphList[i] = tmp;
+ for (var j = 0; j < graphList.length; j++)
+ if (graphList[j].substring(0, graphId.length) == graphId && graphList[j].charAt(graphId.length) == ' ') {
+ if (j+1 < graphList.length) {
+ var tmp = graphList[j+1];
+ graphList[j+1] = graphList[i];
+ graphList[j] = tmp;
}
break;
}
if (document.cookie.length > 0) {
var cname= 'graphLst'+lname+'=';
var cookies = document.cookie.split('; ');
- for (i = 0; i < cookies.length; i++)
+ for (var i = 0; i < cookies.length; i++)
if (cookies[i].substring(0, cname.length) == cname)
return cookies[i].substring(cname.length).split('/');
}
} else {
select.removeAttribute('disabled');
for (i = 0; i < optCnt; i++) {
- newOption = document.createElement("option");
+ var newOption = document.createElement("option");
newOption.value = options[i][0];
if (newOption.value == oldValue)
newOption.setAttribute('selected', 'selected');
if (graphList.length > 0) {
// Save graph list to cookie
var str = '';
- for (i = 0; i < graphList.length; i++) {
+ for (var i = 0; i < graphList.length; i++) {
var g = graphList[i].indexOf(' ');
if (i > 0)
str += '/';
// Load graph list from cookie
var grLst = GraphListFromCookie(cname);
var oldLength = graphList.length;
- for (i = 0; i < grLst.length; i++) {
+ for (var i = 0; i < grLst.length; i++) {
var host = '';
var plugin = '';
var pinst = '';
var logarithmic = false;
var tinyLegend = false;
var graph = grLst[i].split('&');
- for (j = 0; j < graph.length; j++)
+ for (var j = 0; j < graph.length; j++)
if (graph[j] == 'logarithmic=1')
logarithmic = true;
else if (graph[j] == 'tinylegend=1')
%define with_ceph 0%{!?_without_ceph:1}
%define with_cgroups 0%{!?_without_cgroups:1}
%define with_chrony 0%{!?_without_chrony:1}
+%define with_connectivity 0%{!?_without_connectivity:1}
%define with_conntrack 0%{!?_without_conntrack:1}
%define with_contextswitch 0%{!?_without_contextswitch:1}
%define with_cpu 0%{!?_without_cpu:1}
%define with_log_logstash 0%{!?_without_log_logstash:1}
%define with_logfile 0%{!?_without_logfile:1}
%define with_lua 0%{!?_without_lua:1}
-%define with_lvm 0%{!?_without_lvm:1}
%define with_madwifi 0%{!?_without_madwifi:1}
%define with_mbmon 0%{!?_without_mbmon:1}
%define with_mcelog 0%{!?_without_mcelog:1}
%define with_openvpn 0%{!?_without_openvpn:1}
%define with_ovs_events 0%{!?_without_ovs_events:1}
%define with_ovs_stats 0%{!?_without_ovs_stats:1}
+%define with_pcie_errors 0%{!?_without_pcie_errors:1}
%define with_perl 0%{!?_without_perl:1}
%define with_pinba 0%{!?_without_pinba:1}
%define with_ping 0%{!?_without_ping:1}
%define with_postgresql 0%{!?_without_postgresql:1}
%define with_powerdns 0%{!?_without_powerdns:1}
%define with_processes 0%{!?_without_processes:1}
+%define with_procevent 0%{!?_without_procevent:1}
%define with_protocols 0%{!?_without_protocols:1}
%define with_python 0%{!?_without_python:1}
%define with_redis 0%{!?_without_redis:1}
%define with_statsd 0%{!?_without_statsd:1}
%define with_swap 0%{!?_without_swap:1}
%define with_synproxy 0%{!?_without_synproxy:0}
+%define with_sysevent 0%{!?_without_sysevent:1}
%define with_syslog 0%{!?_without_syslog:1}
%define with_table 0%{!?_without_table:1}
%define with_tail 0%{!?_without_tail:1}
%define with_write_prometheus 0%{!?_without_write_prometheus:1}
%define with_write_redis 0%{!?_without_write_redis:1}
%define with_write_riemann 0%{!?_without_write_riemann:1}
+%define with_write_stackdriver 0%{!?_without_write_stackdriver:1}
%define with_write_sensu 0%{!?_without_write_sensu:1}
+%define with_write_syslog 0%{!?_without_write_syslog:1}
%define with_write_tsdb 0%{!?_without_write_tsdb:1}
%define with_xmms 0%{!?_without_xmms:0%{?_has_xmms}}
%define with_zfs_arc 0%{!?_without_zfs_arc:1}
%define with_xencpu 0%{!?_without_xencpu:0}
# plugin zone disabled, requires Solaris
%define with_zone 0%{!?_without_zone:0}
+# plugin gpu_nvidia requires cuda-nvml-dev
+# get it from https://developer.nvidia.com/cuda-downloads
+# then install cuda-nvml-dev-10-1 or other version
+%define with_gpu_nvidia 0%{!?_without_gpu_nvidia:0}
+# not sure why this one's failing
+%define with_write_stackdriver 0%{!?_without_write_stackdriver:0}
# Plugins not buildable on RHEL < 6
%if 0%{?rhel} && 0%{?rhel} < 6
%define with_gmond 0
%define with_iptables 0
%define with_ipvs 0
-%define with_lvm 0
%define with_modbus 0
%define with_netlink 0
%define with_redis 0
# Plugins not buildable on RHEL < 7
%if 0%{?rhel} && 0%{?rhel} < 7
+%define with_connectivity 0
%define with_cpusleep 0
%define with_gps 0
%define with_mqtt 0
%define with_ovs_events 0
%define with_ovs_stats 0
+%define with_procevent 0
%define with_redis 0
%define with_rrdcached 0
+%define with_sysevent 0
%define with_write_redis 0
%define with_write_riemann 0
%define with_xmms 0
Summary: Statistics collection and monitoring daemon
Name: collectd
-Version: 5.7.1
-Release: 9%{?dist}
+Version: 5.9.2
+Release: 2%{?dist}
URL: https://collectd.org
Source: https://collectd.org/files/%{name}-%{version}.tar.bz2
License: GPLv2
Chrony plugin for collectd
%endif
+%if %{with_connectivity}
+%package connectivity
+Summary: Connectivity plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: libmnl-devel, yajl-devel
+%description connectivity
+Monitors network interface up/down status via netlink library.
+%endif
+
%if %{with_curl}
%package curl
Summary: Curl plugin for collectd
application programming interface (API) to Lua scripts.
%endif
-%if %{with_lvm}
-%package lvm
-Summary: LVM plugin for collectd
-Group: System Environment/Daemons
-Requires: %{name}%{?_isa} = %{version}-%{release}
-BuildRequires: lvm2-devel
-%description lvm
-This plugin collects size of “Logical Volumes” (LV) and “Volume Groups” (VG)
-of Linux' “Logical Volume Manager” (LVM).
-%endif
-
%if %{with_mcelog}
%package mcelog
Summary: Mcelog plugin for collectd
application programming interface (API) to Perl-scripts.
%endif
+%if %{with_pcie_errors}
+%package pcie_errors
+Summary: PCI Express errors plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+%description pcie_errors
+The pcie_errors plugin collects PCI Express errors from Device Status in Capability
+structure and from Advanced Error Reporting Extended Capability.
+%endif
+
%if %{with_pinba}
%package pinba
Summary: Pinba plugin for collectd
database.
%endif
+%if %{with_procevent}
+%package procevent
+Summary: Processes event plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: yajl-devel
+%description procevent
+Monitors process starts/stops via netlink library.
+%endif
+
%if %{with_python}
%package python
Summary: Python plugin for collectd
This plugin for collectd to support AgentX integration.
%endif
+%if %{with_sysevent}
+%package sysevent
+Summary: Rsyslog event plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: yajl-devel
+%description sysevent
+Monitors rsyslog for system events.
+%endif
+
%if %{with_varnish}
%package varnish
Summary: Varnish plugin for collectd
The riemann plugin submits values to Riemann, an event stream processor.
%endif
+%if %{with_write_stackdriver}
+%package write_stackdriver
+Summary: stackdriver plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: curl-devel, yajl-devel, openssl-devel
+%description write_stackdriver
+The write_stackdriver collectd plugin writes metrics to the
+Google Stackdriver Monitoring service.
+%endif
+
+%if %{with_gpu_nvidia}
+%package gpu_nvidia
+Summary: stackdriver plugin for collectd
+Group: System Environment/Daemons
+Requires: %{name}%{?_isa} = %{version}-%{release}
+BuildRequires: cuda-nvml-dev-10-1
+%description gpu_nvidia
+The gpu_nvidia collectd plugin collects NVidia GPU metrics.
+%endif
+
%if %{with_xencpu}
%package xencpu
Summary: xencpu plugin for collectd
%define _with_chrony --disable-chrony
%endif
+%if %{with_connectivity}
+%define _with_connectivity --enable-connectivity
+%else
+%define _with_connectivity --disable-connectivity
+%endif
+
%if %{with_conntrack}
%define _with_conntrack --enable-conntrack
%else
%define _with_lua --disable-lua
%endif
-%if %{with_lvm}
-%define _with_lvm --enable-lvm
-%else
-%define _with_lvm --disable-lvm
-%endif
-
%if %{with_madwifi}
%define _with_madwifi --enable-madwifi
%else
%define _with_perl --disable-perl
%endif
+%if %{with_pcie_errors}
+%define _with_pcie_errors --enable-pcie_errors
+%else
+%define _with_pcie_errors --disable-pcie_errors
+%endif
+
%if %{with_pf}
%define _with_pf --enable-pf
%else
%define _with_processes --disable-processes
%endif
+%if %{with_procevent}
+%define _with_procevent --enable-procevent
+%else
+%define _with_procevent --disable-procevent
+%endif
+
%if %{with_protocols}
%define _with_protocols --enable-protocols
%else
%define _with_synproxy --disable-synproxy
%endif
+%if %{with_sysevent}
+%define _with_sysevent --enable-sysevent
+%else
+%define _with_sysevent --disable-sysevent
+%endif
+
%if %{with_syslog}
%define _with_syslog --enable-syslog
%else
%define _with_write_riemann --disable-write_riemann
%endif
+%if %{with_write_stackdriver}
+%define _with_write_stackdriver --enable-write_stackdriver
+%else
+%define _with_write_stackdriver --disable-write_stackdriver
+%endif
+
+%if %{with_gpu_nvidia}
+%define _with_gpu_nvidia --enable-gpu_nvidia
+%else
+%define _with_gpu_nvidia --disable-gpu_nvidia
+%endif
+
%if %{with_write_sensu}
%define _with_write_sensu --enable-write_sensu
%else
%define _with_write_sensu --disable-write_sensu
%endif
+%if %{with_write_syslog}
+%define _with_write_syslog --enable-write_syslog
+%else
+%define _with_write_syslog --disable-write_syslog
+%endif
+
%if %{with_write_tsdb}
%define _with_write_tsdb --enable-write_tsdb
%else
%{?_with_ceph} \
%{?_with_cgroups} \
%{?_with_chrony} \
+ %{?_with_connectivity} \
%{?_with_conntrack} \
%{?_with_contextswitch} \
%{?_with_cpufreq} \
%{?_with_logfile} \
%{?_with_lpar} \
%{?_with_lua} \
- %{?_with_lvm} \
%{?_with_madwifi} \
%{?_with_mbmon} \
%{?_with_mcelog} \
%{?_with_ovs_events} \
%{?_with_ovs_stats} \
%{?_with_perl} \
+ %{?_with_pcie_errors} \
%{?_with_pf} \
%{?_with_pinba} \
%{?_with_ping} \
%{?_with_postgresql} \
%{?_with_powerdns} \
%{?_with_processes} \
+ %{?_with_procevent} \
%{?_with_protocols} \
%{?_with_python} \
%{?_with_redis} \
%{?_with_statsd} \
%{?_with_swap} \
%{?_with_synproxy} \
+ %{?_with_sysevent} \
%{?_with_syslog} \
%{?_with_table} \
%{?_with_tail_csv} \
%{?_with_write_prometheus} \
%{?_with_write_redis} \
%{?_with_write_riemann} \
+ %{?_with_write_stackdriver} \
+ %{?_with_gpu_nvidia} \
%{?_with_write_sensu} \
+ %{?_with_write_syslog} \
%{?_with_write_tsdb} \
%{?_with_xencpu} \
%{?_with_xmms} \
%if %{with_write_log}
%{_libdir}/%{name}/write_log.so
%endif
+%if %{with_write_syslog}
+%{_libdir}/%{name}/write_syslog.so
+%endif
%if %{with_write_sensu}
%{_libdir}/%{name}/write_sensu.so
%endif
%{_libdir}/%{name}/chrony.so
%endif
+%if %{with_connectivity}
+%files connectivity
+%{_libdir}/%{name}/connectivity.so
+%endif
+
%if %{with_curl}
%files curl
%{_libdir}/%{name}/curl.so
%{_libdir}/%{name}/lua.so
%endif
-%if %{with_lvm}
-%files lvm
-%{_libdir}/%{name}/lvm.so
-%endif
-
%if %{with_memcachec}
%files memcachec
%{_libdir}/%{name}/memcachec.so
%{_libdir}/%{name}/perl.so
%endif
+%if %{with_pcie_errors}
+%files pcie_errors
+%{_libdir}/%{name}/pcie_errors.so
+%endif
+
%if %{with_pinba}
%files pinba
%{_libdir}/%{name}/pinba.so
%{_libdir}/%{name}/postgresql.so
%endif
+%if %{with_procevent}
+%files procevent
+%{_libdir}/%{name}/procevent.so
+%endif
+
%if %{with_python}
%files python
%{_mandir}/man5/collectd-python*
%{_libdir}/%{name}/snmp_agent.so
%endif
+%if %{with_sysevent}
+%files sysevent
+%{_libdir}/%{name}/sysevent.so
+%endif
+
%if %{with_varnish}
%files varnish
%{_libdir}/%{name}/varnish.so
%{_libdir}/%{name}/write_riemann.so
%endif
+%if %{with_write_stackdriver}
+%files write_stackdriver
+%{_libdir}/%{name}/write_stackdriver.so
+%endif
+
+%if %{with_gpu_nvidia}
+%files write_gpu_nvidia
+%{_libdir}/%{name}/write_gpu_nvidia.so
+%endif
+
%if %{with_xencpu}
%files xencpu
%{_libdir}/%{name}/xencpu.so
%doc contrib/
%changelog
+* Mon Oct 14 2019 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.9.2-2
+- Remove lvm plugin, liblvmapp has been deprecated upstream
+
+* Fri Jun 14 2019 Fabien Wernli <rpmbuild@faxmodem.org> - 5.9.0-1
+- add code for write_stackdriver (disabled for now)
+- add code for gpu_nvidia (disabled for now)
+- add pcie_errors
+
* Thu Sep 28 2017 Jakub Jankowski <shasta@toxcorp.com> - 5.7.1-9
- Fix mbmon/mcelog build options
ExecStart=/usr/sbin/collectd
EnvironmentFile=-/etc/sysconfig/collectd
EnvironmentFile=-/etc/default/collectd
-ProtectSystem=full
-ProtectHome=true
# A few plugins won't work without some privileges, which you'll have to
# specify using the CapabilityBoundingSet directive below.
--- /dev/null
+# Contribution guidelines
+
+Thanks for taking the time to contribute to the [collectd
+project](https://collectd.org/)! This document tries to give some guidance to
+make the process of contributing to *collectd* as pleasant as possible.
+
+## Bug reports
+
+Please report bugs as [GitHub
+Issues](https://github.com/collectd/collectd/issues). Try to answer the
+following questions:
+
+* Which version of *collectd* are you using?
+* Which operating system (distribution) are you using at which version?
+* What is the expected behavior / output?
+* What is the actual (observed) behavior / output?
+* How can we reproduce the problem you're having?
+* If *collectd* crashes, try to get a
+ [stack trace](https://collectd.org/wiki/index.php/Core_file).
+
+Please monitor your issue for a couple of days and reply to questions. To keep
+the project manageable, we have to do some housekeeping; meaning we will close
+issues that have become stale.
+
+## Code contributions
+
+Please open a [GitHub Pull Request](https://github.com/collectd/collectd/pulls)
+(PR) to contribute bug fixes, features, cleanups, new plugins, … Patches sent to
+the mailing list have a tendency to fall through the cracks.
+
+* *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` 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.
+* *Continuous integration:* Once your PR is created, our continuous
+ integration environment will try to build it on a number of platforms. If
+ this reports a failure, please investigate and fix the problem. We will at
+ best do a very casual review for failing PRs.
+* *Don't rebase:* Rebasing your branch destroys the review history. If a
+ review takes a long time, we may ask you to rebase on a more recent
+ *master*, but please don't do that without being asked.
+* *types.db:* One of the most common mistakes made by new contributors is the
+ addition of (many) new *types* in the file `src/types.db`. The majority of
+ usecases can be met with one of the existing entries. If you plan to add new
+ entries to `src/types.db`, you should talk to us early in the design
+ process.
+
+### ChangeLog
+
+PRs need to have a one-line summary in the *PR description*. This information
+is used to automatically generate release notes. If you got here after creating
+the PR, you need to go to the *PR description* (shown as the first "comment" on
+the PR, made by yourself) and *edit* that description. Editing a PR will
+trigger the "ChangeLog" status to be updated.
+
+For the summary itself, follow this style:
+
+```
+ChangeLog: Foo plugin: A specific issue people had has been fixed.
+```
+
+The summary must be on a line of its own, with a "ChangeLog:" prefix at the
+beginning of the line. The text should start with "Foo plugin" to give the
+reader context for the information. Other common contexts are "collectd" for
+the core daemon, "Build system", and "Documentation". Use past tense and
+passive voice the for remainder, e.g. "a bug has been fixed", "a feature has
+been added".
+
+Some PRs should be excluded from the release notes, e.g. changes to project
+internal documentation (such as this file). Those changes are not interesting
+for external users of the project and would reduce the value of the release
+notes. Maintainers may use the `Unlisted Change` label to mark those PRs.
+
+## Other resources
+
+* [Mailing list](http://mailman.verplant.org/listinfo/collectd)
+* [#collectd IRC channel](https://webchat.freenode.net/?channels=#collectd)
+ on *freenode*.
+* [Old patch submission guideline](https://collectd.org/wiki/index.php/Submitting_patches)
sstrncpy(tmp_plugin_instance, agg->ident.plugin_instance,
sizeof(tmp_plugin_instance));
+ // Both tmp_plugin and tmp_plugin_instance are empty.
if ((strcmp("", tmp_plugin) == 0) && (strcmp("", tmp_plugin_instance) == 0))
sstrncpy(inst->ident.plugin_instance, AGG_FUNC_PLACEHOLDER,
sizeof(inst->ident.plugin_instance));
- else if (strcmp("", tmp_plugin) != 0)
- snprintf(inst->ident.plugin_instance, sizeof(inst->ident.plugin_instance),
- "%s-%s", tmp_plugin, AGG_FUNC_PLACEHOLDER);
- else if (strcmp("", tmp_plugin_instance) != 0)
- snprintf(inst->ident.plugin_instance, sizeof(inst->ident.plugin_instance),
- "%s-%s", tmp_plugin_instance, AGG_FUNC_PLACEHOLDER);
+ // tmp_plugin is non-empty, and tmp_plugin_instance is empty.
+ else if (strcmp("", tmp_plugin_instance) == 0)
+ ssnprintf(inst->ident.plugin_instance,
+ sizeof(inst->ident.plugin_instance), "%s-%s", tmp_plugin,
+ AGG_FUNC_PLACEHOLDER);
+ // tmp_plugin is empty, and tmp_plugin_instance is non-empty.
+ else if (strcmp("", tmp_plugin) == 0)
+ ssnprintf(inst->ident.plugin_instance,
+ sizeof(inst->ident.plugin_instance), "%s-%s",
+ tmp_plugin_instance, AGG_FUNC_PLACEHOLDER);
+ // Both tmp_plugin and tmp_plugin_instance are non-empty.
else
- snprintf(inst->ident.plugin_instance, sizeof(inst->ident.plugin_instance),
- "%s-%s-%s", tmp_plugin, tmp_plugin_instance,
- AGG_FUNC_PLACEHOLDER);
+ ssnprintf(inst->ident.plugin_instance,
+ sizeof(inst->ident.plugin_instance), "%s-%s-%s", tmp_plugin,
+ tmp_plugin_instance, AGG_FUNC_PLACEHOLDER);
}
/* Type */
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. */
if (r.reply.id == AMQP_CONNECTION_CLOSE_METHOD) {
amqp_connection_close_t *m = r.reply.decoded;
char *tmp = camqp_bytes_cstring(&m->reply_text);
- snprintf(buffer, buffer_size, "Server connection error %d: %s",
- m->reply_code, tmp);
+ ssnprintf(buffer, buffer_size, "Server connection error %d: %s",
+ m->reply_code, tmp);
sfree(tmp);
} else if (r.reply.id == AMQP_CHANNEL_CLOSE_METHOD) {
amqp_channel_close_t *m = r.reply.decoded;
char *tmp = camqp_bytes_cstring(&m->reply_text);
- snprintf(buffer, buffer_size, "Server channel error %d: %s",
- m->reply_code, tmp);
+ ssnprintf(buffer, buffer_size, "Server channel error %d: %s",
+ m->reply_code, tmp);
sfree(tmp);
} else {
- snprintf(buffer, buffer_size, "Server error method %#" PRIx32,
- r.reply.id);
+ ssnprintf(buffer, buffer_size, "Server error method %#" PRIx32,
+ r.reply.id);
}
break;
default:
- snprintf(buffer, buffer_size, "Unknown reply type %i", (int)r.reply_type);
+ ssnprintf(buffer, buffer_size, "Unknown reply type %i", (int)r.reply_type);
}
return buffer;
amqp_queue_declare_ok_t *qd_ret;
amqp_basic_consume_ok_t *cm_ret;
- qd_ret = amqp_queue_declare(conf->connection,
- /* channel = */ CAMQP_CHANNEL,
- /* queue = */ (conf->queue != NULL)
- ? amqp_cstring_bytes(conf->queue)
- : AMQP_EMPTY_BYTES,
- /* passive = */ 0,
- /* durable = */ conf->queue_durable,
- /* exclusive = */ 0,
- /* auto_delete = */ conf->queue_auto_delete,
- /* arguments = */ AMQP_EMPTY_TABLE);
+ qd_ret =
+ amqp_queue_declare(conf->connection,
+ /* channel = */ CAMQP_CHANNEL,
+ /* queue = */
+ (conf->queue != NULL) ? amqp_cstring_bytes(conf->queue)
+ : AMQP_EMPTY_BYTES,
+ /* passive = */ 0,
+ /* durable = */ conf->queue_durable,
+ /* exclusive = */ 0,
+ /* auto_delete = */ conf->queue_auto_delete,
+ /* arguments = */ AMQP_EMPTY_TABLE);
if (qd_ret == NULL) {
ERROR("amqp plugin: amqp_queue_declare failed.");
camqp_close_connection(conf);
amqp_queue_bind_ok_t *qb_ret;
assert(conf->queue != NULL);
- qb_ret =
- amqp_queue_bind(conf->connection,
- /* channel = */ CAMQP_CHANNEL,
- /* queue = */ amqp_cstring_bytes(conf->queue),
- /* exchange = */ amqp_cstring_bytes(conf->exchange),
- /* routing_key = */ (conf->routing_key != NULL)
- ? amqp_cstring_bytes(conf->routing_key)
- : AMQP_EMPTY_BYTES,
- /* arguments = */ AMQP_EMPTY_TABLE);
+ qb_ret = amqp_queue_bind(
+ conf->connection,
+ /* channel = */ CAMQP_CHANNEL,
+ /* queue = */ amqp_cstring_bytes(conf->queue),
+ /* exchange = */ amqp_cstring_bytes(conf->exchange),
+ /* routing_key = */
+ (conf->routing_key != NULL) ? amqp_cstring_bytes(conf->routing_key)
+ : AMQP_EMPTY_BYTES,
+ /* arguments = */ AMQP_EMPTY_TABLE);
if ((qb_ret == NULL) && camqp_is_error(conf)) {
char errbuf[1024];
ERROR("amqp plugin: amqp_queue_bind failed: %s",
#ifdef HAVE_AMQP_TCP_SOCKET
#define CLOSE_SOCKET() /* amqp_destroy_connection() closes the socket for us \
- */
+ */
/* TODO: add support for SSL using amqp_ssl_socket_new
* and related functions */
socket = amqp_tcp_socket_new(conf->connection);
if (conf->routing_key != NULL) {
sstrncpy(routing_key, conf->routing_key, sizeof(routing_key));
} else {
- snprintf(routing_key, sizeof(routing_key), "collectd/%s/%s/%s/%s/%s",
- vl->host, vl->plugin, vl->plugin_instance, vl->type,
- vl->type_instance);
+ ssnprintf(routing_key, sizeof(routing_key), "collectd/%s/%s/%s/%s/%s",
+ vl->host, vl->plugin, vl->plugin_instance, vl->type,
+ vl->type_instance);
/* Switch slashes (the only character forbidden by collectd) and dots
* (the separation character used by AMQP). */
if (publish) {
char cbname[128];
- snprintf(cbname, sizeof(cbname), "amqp/%s", conf->name);
+ ssnprintf(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;
else if (strcasecmp("Format", child->key) == 0) {
char *key = NULL;
status = cf_util_get_string(child, &key);
- if (status != 0)
+ if (status != 0) {
+ amqp1_config_instance_free(instance);
return status;
+ }
assert(key != NULL);
if (strcasecmp(key, "Command") == 0) {
instance->format = AMQP1_FORMAT_COMMAND;
return status;
} else {
char tpname[DATA_MAX_NAME_LEN];
- status = snprintf(tpname, sizeof(tpname), "amqp1/%s", instance->name);
+ status = ssnprintf(tpname, sizeof(tpname), "amqp1/%s", instance->name);
if ((status < 0) || (size_t)status >= sizeof(tpname)) {
ERROR("amqp1 plugin: Instance name would have been truncated.");
+ amqp1_config_instance_free(instance);
return -1;
}
- status = snprintf(instance->send_to, sizeof(instance->send_to), "/%s/%s",
- transport->address, instance->name);
+ status = ssnprintf(instance->send_to, sizeof(instance->send_to), "/%s/%s",
+ transport->address, instance->name);
if ((status < 0) || (size_t)status >= sizeof(instance->send_to)) {
ERROR("amqp1 plugin: send_to address would have been truncated.");
+ amqp1_config_instance_free(instance);
return -1;
}
if (instance->notify) {
status = plugin_register_notification(
tpname, amqp1_notify,
&(user_data_t){
- .data = instance, .free_func = amqp1_config_instance_free,
+ .data = instance,
+ .free_func = amqp1_config_instance_free,
});
} else {
- status = plugin_register_write(
- tpname, amqp1_write,
- &(user_data_t){
- .data = instance, .free_func = amqp1_config_instance_free,
- });
+ status =
+ plugin_register_write(tpname, amqp1_write,
+ &(user_data_t){
+ .data = instance,
+ .free_func = amqp1_config_instance_free,
+ });
}
if (status != 0) {
/* callback = */ apache_read_host,
/* interval = */ 0,
&(user_data_t){
- .data = st, .free_func = apache_free,
+ .data = st,
+ .free_func = apache_free,
});
} /* int config_add */
if (value_array[i] == AQ5_FLOAT_UNDEF)
continue;
- snprintf(type_instance, sizeof(type_instance), "%s%d", type_instance_prefix,
- i + 1);
+ ssnprintf(type_instance, sizeof(type_instance), "%s%d",
+ type_instance_prefix, i + 1);
aquaero_submit(type, type_instance, value_array[i]);
}
}
(aq_data.fan_vrm_temp[i] != AQ5_FLOAT_UNDEF))
continue;
- snprintf(type_instance, sizeof(type_instance), "fan%d", i + 1);
+ ssnprintf(type_instance, sizeof(type_instance), "fan%d", i + 1);
aquaero_submit("fanspeed", type_instance, aq_data.fan_rpm[i]);
aquaero_submit("percent", type_instance, aq_data.fan_duty[i]);
/* Report the voltage reglator module (VRM) temperature with a
* different type instance. */
- snprintf(type_instance, sizeof(type_instance), "fan%d-vrm", i + 1);
+ ssnprintf(type_instance, sizeof(type_instance), "fan%d-vrm", i + 1);
aquaero_submit("temperature", type_instance, aq_data.fan_vrm_temp[i]);
}
static char credentials[1024];
int status;
- status = snprintf(credentials, sizeof(credentials), "%s:%s", user,
- (pass == NULL) ? "" : pass);
+ status = ssnprintf(credentials, sizeof(credentials), "%s:%s", user,
+ (pass == NULL) ? "" : pass);
if ((status < 0) || ((size_t)status >= sizeof(credentials))) {
ERROR("ascent plugin: ascent_init: Returning an error because the "
"credentials have been truncated.");
} else if (strcasecmp(key, "Normalization") == 0) {
int normalize_tmp = atoi(value);
if (normalize_tmp < 0 || normalize_tmp > 2) {
- WARNING("barometer: collectd_barometer_config: invalid normalization: %d",
- normalize_tmp);
+ ERROR("barometer: collectd_barometer_config: invalid normalization: %d",
+ normalize_tmp);
return 1;
}
config_normalize = normalize_tmp;
return 0;
} /* }}} int battery_read */
-/* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
+ /* #endif HAVE_IOKIT_IOKITLIB_H || HAVE_IOKIT_PS_IOPOWERSOURCES_H */
#elif KERNEL_LINUX
/* Reads a file which contains only a number (and optionally a trailing
snprintf(filename, sizeof(filename), "%s/%s/%s", dir, power_supply, basename);
- status = (int)read_file_contents(filename, buffer, buffer_size - 1);
+ status = (int)read_text_file_contents(filename, buffer, buffer_size);
if (status < 0)
return status;
- buffer[status] = '\0';
-
strstripnewline(buffer);
return 0;
} /* }}} int sysfs_file_to_buffer */
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
#ifdef HAVE_CURLOPT_TIMEOUT_MS
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS,
- (timeout >= 0) ? (long)timeout : (long)CDTIME_T_TO_MS(
- plugin_get_interval()));
+ (timeout >= 0)
+ ? (long)timeout
+ : (long)CDTIME_T_TO_MS(plugin_get_interval()));
#endif
return 0;
return err;
}
address.sun_family = AF_UNIX;
- snprintf(address.sun_path, sizeof(address.sun_path), "%s", io->d->asok_path);
+ ssnprintf(address.sun_path, sizeof(address.sun_path), "%s", io->d->asok_path);
RETRY_ON_EINTR(err, connect(fd, (struct sockaddr *)&address,
sizeof(struct sockaddr_un)));
if (err < 0) {
return -EDOM;
case CSTATE_WRITE_REQUEST: {
char cmd[32];
- snprintf(cmd, sizeof(cmd), "%s%d%s", "{ \"prefix\": \"", io->request_type,
- "\" }\n");
+ ssnprintf(cmd, sizeof(cmd), "%s%d%s", "{ \"prefix\": \"", io->request_type,
+ "\" }\n");
size_t cmd_len = strlen(cmd);
RETRY_ON_EINTR(
ret, write(io->asok, ((char *)&cmd) + io->amt, cmd_len - io->amt));
--- /dev/null
+/**
+ * collectd - src/check_uptime.c
+ * Copyright (C) 2007-2019 Florian Forster
+ * Copyright (C) 2019 Pavel V. Rochnyack
+ *
+ * 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
+ *
+ * Author:
+ * Florian octo Forster <octo at collectd.org>
+ * Pavel Rochnyak <pavel2000 ngs.ru>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "utils/avltree/avltree.h"
+#include "utils/common/common.h"
+#include "utils_cache.h"
+
+/* Types are registered only in `config` phase, so access is not protected by
+ * locks */
+c_avl_tree_t *types_tree = NULL;
+
+static int format_uptime(unsigned long uptime_sec, char *buf, size_t bufsize) {
+
+ unsigned int uptime_days = uptime_sec / 24 / 3600;
+ uptime_sec -= uptime_days * 24 * 3600;
+ unsigned int uptime_hours = uptime_sec / 3600;
+ uptime_sec -= uptime_hours * 3600;
+ unsigned int uptime_mins = uptime_sec / 60;
+ uptime_sec -= uptime_mins * 60;
+
+ int ret = 0;
+ if (uptime_days) {
+ ret += snprintf(buf + ret, bufsize - ret, " %u day(s)", uptime_days);
+ }
+ if (uptime_days || uptime_hours) {
+ ret += snprintf(buf + ret, bufsize - ret, " %u hour(s)", uptime_hours);
+ }
+ if (uptime_days || uptime_hours || uptime_mins) {
+ ret += snprintf(buf + ret, bufsize - ret, " %u min", uptime_mins);
+ }
+ ret += snprintf(buf + ret, bufsize - ret, " %lu sec.", uptime_sec);
+ return ret;
+}
+
+static int cu_notify(enum cache_event_type_e event_type, const value_list_t *vl,
+ gauge_t old_uptime, gauge_t new_uptime) {
+ notification_t n;
+ NOTIFICATION_INIT_VL(&n, vl);
+
+ int status;
+ char *buf = n.message;
+ size_t bufsize = sizeof(n.message);
+
+ n.time = vl->time;
+
+ const char *service = "Service";
+ if (strcmp(vl->plugin, "uptime") == 0)
+ service = "Host";
+
+ switch (event_type) {
+ case CE_VALUE_NEW:
+ n.severity = NOTIF_OKAY;
+ status = snprintf(buf, bufsize, "%s is running.", service);
+ buf += status;
+ bufsize -= status;
+ break;
+ case CE_VALUE_UPDATE:
+ n.severity = NOTIF_WARNING;
+ status = snprintf(buf, bufsize, "%s just restarted.", service);
+ buf += status;
+ bufsize -= status;
+ break;
+ case CE_VALUE_EXPIRED:
+ n.severity = NOTIF_FAILURE;
+ status = snprintf(buf, bufsize, "%s is unreachable.", service);
+ buf += status;
+ bufsize -= status;
+ break;
+ }
+
+ if (!isnan(old_uptime)) {
+ status = snprintf(buf, bufsize, " Uptime was:");
+ buf += status;
+ bufsize -= status;
+
+ status = format_uptime(old_uptime, buf, bufsize);
+ buf += status;
+ bufsize -= status;
+
+ plugin_notification_meta_add_double(&n, "LastValue", old_uptime);
+ }
+
+ if (!isnan(new_uptime)) {
+ status = snprintf(buf, bufsize, " Uptime now:");
+ buf += status;
+ bufsize -= status;
+
+ status = format_uptime(new_uptime, buf, bufsize);
+ buf += status;
+ bufsize -= status;
+
+ plugin_notification_meta_add_double(&n, "CurrentValue", new_uptime);
+ }
+
+ plugin_dispatch_notification(&n);
+
+ plugin_notification_meta_free(n.meta);
+ return 0;
+}
+
+static int cu_cache_event(cache_event_t *event,
+ __attribute__((unused)) user_data_t *ud) {
+ gauge_t values_history[2];
+
+ /* For CE_VALUE_EXPIRED */
+ int ret;
+ value_t *values;
+ size_t values_num;
+ gauge_t old_uptime = NAN;
+
+ switch (event->type) {
+ case CE_VALUE_NEW:
+ DEBUG("check_uptime: CE_VALUE_NEW, %s", event->value_list_name);
+ if (c_avl_get(types_tree, event->value_list->type, NULL) == 0) {
+ event->ret = 1;
+ assert(event->value_list->values_len > 0);
+ cu_notify(CE_VALUE_NEW, event->value_list, NAN /* old */,
+ event->value_list->values[0].gauge /* new */);
+ }
+ break;
+ case CE_VALUE_UPDATE:
+ DEBUG("check_uptime: CE_VALUE_UPDATE, %s", event->value_list_name);
+ if (uc_get_history_by_name(event->value_list_name, values_history, 2, 1)) {
+ ERROR("check_uptime plugin: Failed to get value history for %s.",
+ event->value_list_name);
+ } else {
+ if (!isnan(values_history[0]) && !isnan(values_history[1]) &&
+ values_history[0] < values_history[1]) {
+ cu_notify(CE_VALUE_UPDATE, event->value_list,
+ values_history[1] /* old */, values_history[0] /* new */);
+ }
+ }
+ break;
+ case CE_VALUE_EXPIRED:
+ DEBUG("check_uptime: CE_VALUE_EXPIRED, %s", event->value_list_name);
+ ret = uc_get_value_by_name(event->value_list_name, &values, &values_num);
+ if (ret == 0) {
+ old_uptime = values[0].gauge;
+ sfree(values);
+ }
+
+ cu_notify(CE_VALUE_EXPIRED, event->value_list, old_uptime, NAN /* new */);
+ break;
+ }
+ return 0;
+}
+
+static int cu_config(oconfig_item_t *ci) {
+ if (types_tree == NULL) {
+ types_tree = c_avl_create((int (*)(const void *, const void *))strcmp);
+ if (types_tree == NULL) {
+ ERROR("check_uptime plugin: c_avl_create failed.");
+ return -1;
+ }
+ }
+
+ for (int i = 0; i < ci->children_num; ++i) {
+ oconfig_item_t *child = ci->children + i;
+ if (strcasecmp("Type", child->key) == 0) {
+ if ((child->values_num != 1) ||
+ (child->values[0].type != OCONFIG_TYPE_STRING)) {
+ WARNING("check_uptime plugin: The `Type' option needs exactly one "
+ "string argument.");
+ return -1;
+ }
+ char *type = child->values[0].value.string;
+
+ if (c_avl_get(types_tree, type, NULL) == 0) {
+ ERROR("check_uptime plugin: Type `%s' already added.", type);
+ return -1;
+ }
+
+ char *type_copy = strdup(type);
+ if (type_copy == NULL) {
+ ERROR("check_uptime plugin: strdup failed.");
+ return -1;
+ }
+
+ int status = c_avl_insert(types_tree, type_copy, NULL);
+ if (status != 0) {
+ ERROR("check_uptime plugin: c_avl_insert failed.");
+ sfree(type_copy);
+ return -1;
+ }
+ } else
+ WARNING("check_uptime plugin: Ignore unknown config option `%s'.",
+ child->key);
+ }
+
+ return 0;
+}
+
+static int cu_init(void) {
+ if (types_tree == NULL) {
+ types_tree = c_avl_create((int (*)(const void *, const void *))strcmp);
+ if (types_tree == NULL) {
+ ERROR("check_uptime plugin: c_avl_create failed.");
+ return -1;
+ }
+ /* Default configuration */
+ char *type = strdup("uptime");
+ if (type == NULL) {
+ ERROR("check_uptime plugin: strdup failed.");
+ return -1;
+ }
+ int status = c_avl_insert(types_tree, type, NULL);
+ if (status != 0) {
+ ERROR("check_uptime plugin: c_avl_insert failed.");
+ sfree(type);
+ return -1;
+ }
+ }
+
+ int ret = 0;
+ char *type;
+ void *val;
+ c_avl_iterator_t *iter = c_avl_get_iterator(types_tree);
+ while (c_avl_iterator_next(iter, (void *)&type, (void *)&val) == 0) {
+ data_set_t const *ds = plugin_get_ds(type);
+ if (ds == NULL) {
+ ERROR("check_uptime plugin: Failed to look up type \"%s\".", type);
+ ret = -1;
+ continue;
+ }
+ if (ds->ds_num != 1) {
+ ERROR("check_uptime plugin: The type \"%s\" has %" PRIsz " data sources. "
+ "Only types with a single GAUGE data source are supported.",
+ ds->type, ds->ds_num);
+ ret = -1;
+ continue;
+ }
+ if (ds->ds[0].type != DS_TYPE_GAUGE) {
+ ERROR("check_uptime plugin: The type \"%s\" has wrong data source type. "
+ "Only types with a single GAUGE data source are supported.",
+ ds->type);
+ ret = -1;
+ continue;
+ }
+ }
+ c_avl_iterator_destroy(iter);
+
+ if (ret == 0)
+ plugin_register_cache_event("check_uptime", cu_cache_event, NULL);
+
+ return ret;
+}
+
+void module_register(void) {
+ plugin_register_complex_config("check_uptime", cu_config);
+ plugin_register_init("check_uptime", cu_init);
+}
#define ATTRIB_PACKED
#endif
-typedef struct ATTRIB_PACKED { int32_t value; } tFloat;
+typedef struct ATTRIB_PACKED {
+ int32_t value;
+} tFloat;
typedef struct ATTRIB_PACKED {
uint32_t tv_sec_high;
Amplification) */
} tChrony_Req_Tracking;
-typedef struct ATTRIB_PACKED { uint32_t f_n_sources; } tChrony_Req_N_Sources;
+typedef struct ATTRIB_PACKED {
+ uint32_t f_n_sources;
+} tChrony_Req_N_Sources;
typedef struct ATTRIB_PACKED {
int32_t f_index;
} tChrony_Request;
/* Chrony daemon response packets */
-typedef struct ATTRIB_PACKED { uint32_t f_n_sources; } tChrony_Resp_N_Sources;
+typedef struct ATTRIB_PACKED {
+ uint32_t f_n_sources;
+} tChrony_Resp_N_Sources;
typedef struct ATTRIB_PACKED {
union {
per interval (see the B<Interval> configuration option of collectd). Usually
it will call B<collectd.dispatch_values> to dispatch the values to collectd
which will pass them on to all registered B<write functions>. If this function
-does not return 0 the plugin will be skipped for an increasing
-amount of time until it returns normally again.
+does not return 0, interval between its calls will grow until function returns
+0 again. See the B<MaxReadInterval> configuration option of collectd.
=item write functions
=item register_read(callback)
+Function to register read callbacks.
The callback will be called without arguments.
If this callback function does not return 0 the next call will be delayed by
an increasing interval.
-=item register_write
+=item register_write(callback)
+Function to register write callbacks.
The callback function will be called with one argument passed, which will be a
table of values.
If this callback function does not return 0 next call will be delayed by
To register those functions with collectd:
- collectd.register_read(read)
- collectd.register_write(write)
+ collectd.register_read(read) -- pass function as variable
+ collectd.register_write("write") -- pass by global-scope function name
=back
=head1 AUTHOR
The C<Lua plugin> has been written by
-Julien Ammous E<lt>j.ammous<nbsp>atE<nbsp>gmail.comE<gt>,
+Julien Ammous E<lt>j.ammousE<nbsp>atE<nbsp>gmail.comE<gt>,
Florian Forster E<lt>octoE<nbsp>atE<nbsp>collectd.orgE<gt> and
-Ruben Kerkhof E<lt>ruben<nbsp>atE<nbsp>rubenkerkhof.com<gt> and
+Ruben Kerkhof E<lt>rubenE<nbsp>atE<nbsp>rubenkerkhof.comE<gt>.
This manpage has been written by Ruben Kerkhof
-E<lt>ruben<nbsp>atE<nbsp>rubenkerkhof.com<gt>.
+E<lt>rubenE<nbsp>atE<nbsp>rubenkerkhof.comE<gt>.
It is based on the L<collectd-perl(5)> manual page by
Florian Forster E<lt>octoE<nbsp>atE<nbsp>collectd.orgE<gt> and
Sebastian Harl E<lt>shE<nbsp>atE<nbsp>tokkee.orgE<gt>.
loaded they may be written to disk or submitted to another instance or
whatever you configured.
-Because querying a host via SNMP may produce a timeout multiple threads are
-used to query hosts in parallel. Depending on the number of hosts between one
-and ten threads are used.
+Because querying a host via SNMP may produce a timeout the "complex reads"
+polling method is used. The ReadThreads parameter in the main configuration
+influences the number of parallel polling jobs which can be undertaken. If
+you expect timeouts or some polling to take a long time, you should increase
+this parameter. Note that other plugins also use the same threads.
=head1 CONFIGURATION
=item B<AuthPassphrase> I<Passphrase>
-Sets the authentication passphrase for SNMPv3 security.
+Sets the authentication passphrase for SNMPv3 security.
=item B<PrivacyProtocol> I<AES>|I<DES>
=item B<PrivacyPassphrase> I<Passphrase>
-Sets the privacy (encryption) passphrase for SNMPv3 security.
+Sets the privacy (encryption) passphrase for SNMPv3 security.
=item B<Collect> I<Data> [I<Data> ...]
The number of times that a query should be retried after the Timeout expires.
The C<Net-SNMP> library default is 5.
+=item B<BulkSize> I<Integer>
+
+Configures the size of SNMP bulk transfers. The default is 0, which disables bulk transfers altogether.
+
=back
=head1 SEE ALSO
#@BUILD_PLUGIN_CEPH_TRUE@LoadPlugin ceph
#@BUILD_PLUGIN_CGROUPS_TRUE@LoadPlugin cgroups
#@BUILD_PLUGIN_CHRONY_TRUE@LoadPlugin chrony
+#@BUILD_PLUGIN_CHECK_UPTIME_TRUE@LoadPlugin check_uptime
+#@BUILD_PLUGIN_CONNECTIVITY_TRUE@LoadPlugin connectivity
#@BUILD_PLUGIN_CONNTRACK_TRUE@LoadPlugin conntrack
#@BUILD_PLUGIN_CONTEXTSWITCH_TRUE@LoadPlugin contextswitch
@BUILD_PLUGIN_CPU_TRUE@@BUILD_PLUGIN_CPU_TRUE@LoadPlugin cpu
@BUILD_PLUGIN_LOAD_TRUE@@BUILD_PLUGIN_LOAD_TRUE@LoadPlugin load
#@BUILD_PLUGIN_LPAR_TRUE@LoadPlugin lpar
#@BUILD_PLUGIN_LUA_TRUE@LoadPlugin lua
-#@BUILD_PLUGIN_LVM_TRUE@LoadPlugin lvm
#@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
#@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
#@BUILD_PLUGIN_MCELOG_TRUE@LoadPlugin mcelog
#@BUILD_PLUGIN_POSTGRESQL_TRUE@LoadPlugin postgresql
#@BUILD_PLUGIN_POWERDNS_TRUE@LoadPlugin powerdns
#@BUILD_PLUGIN_PROCESSES_TRUE@LoadPlugin processes
+#@BUILD_PLUGIN_PROCEVENT_TRUE@LoadPlugin procevent
#@BUILD_PLUGIN_PROTOCOLS_TRUE@LoadPlugin protocols
#@BUILD_PLUGIN_PYTHON_TRUE@LoadPlugin python
#@BUILD_PLUGIN_REDIS_TRUE@LoadPlugin redis
#@BUILD_PLUGIN_SNMP_AGENT_TRUE@LoadPlugin snmp_agent
#@BUILD_PLUGIN_STATSD_TRUE@LoadPlugin statsd
#@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap
+#@BUILD_PLUGIN_SYSEVENT_TRUE@LoadPlugin sysevent
#@BUILD_PLUGIN_TABLE_TRUE@LoadPlugin table
#@BUILD_PLUGIN_TAIL_TRUE@LoadPlugin tail
#@BUILD_PLUGIN_TAIL_CSV_TRUE@LoadPlugin tail_csv
#@BUILD_PLUGIN_WRITE_RIEMANN_TRUE@LoadPlugin write_riemann
#@BUILD_PLUGIN_WRITE_SENSU_TRUE@LoadPlugin write_sensu
#@BUILD_PLUGIN_WRITE_STACKDRIVER_TRUE@LoadPlugin write_stackdriver
+#@BUILD_PLUGIN_WRITE_SYSLOG_TRUE@LoadPlugin write_syslog
#@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb
#@BUILD_PLUGIN_XENCPU_TRUE@LoadPlugin xencpu
#@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms
# Timeout "2"
#</Plugin>
+#<Plugin connectivity>
+# Interface eth0
+#</Plugin>
+
#<Plugin cgroups>
# CGroup "libvirt"
# IgnoreSelected false
#<Plugin curl>
# <Page "stock_quotes">
# URL "http://finance.google.com/finance?q=NYSE%3AAMD"
+# AddressFamily "any"
# User "foo"
# Password "bar"
# Digest false
#<Plugin curl_json>
# <URL "http://localhost:80/test.json">
+# AddressFamily "any"
# Instance "test_http_json"
# <Key "testArray/0">
# Type "gauge"
# }
## See: http://wiki.apache.org/couchdb/Runtime_Statistics
# <URL "http://localhost:5984/_stats">
+# AddressFamily "ipv4"
# Instance "httpd"
# <Key "httpd/requests/count">
# Type "http_requests"
# </URL>
## Database status metrics:
# <URL "http://localhost:5984/_all_dbs">
+# AddressFamily "ipv6"
# Instance "dbs"
# <Key "*/doc_count">
# Type "gauge"
#<Plugin curl_xml>
# <URL "http://localhost/stats.xml">
+# AddressFamily "any"
# Host "my_host"
# #Plugin "stats"
# Instance "some_instance"
#<Plugin "intel_rdt">
# Cores "0-2"
+# Processes "sshd"
#</Plugin>
#<Plugin interface>
# </Process>
#</Plugin>
+#<Plugin "procevent">
+# BufferLength 10
+# ProcessRegex "/^ovs.*$/"
+# Process tuned
+#</Plugin>
+
#<Plugin protocols>
# Value "/^Tcp:/"
# IgnoreSelected false
# Version 2
# Community "another_string"
# Collect "std_traffic" "hr_users"
+# BulkSize 0
# </Host>
# <Host "some.ups.mydomain.org">
# Address "192.168.0.3"
# Timeout 5
# Retries 5
# </Host>
+# <Host "highend.switch.example.org">
+# Address "192.168.0.3"
+# Version 2
+# Community "another_string"
+# Collect "std_traffic"
+# Interval 10
+# Timeout 10
+# BulkSize 100
+# </Host>
#</Plugin>
#<Plugin snmp_agent>
# ReportIO true
#</Plugin>
+#<Plugin sysevent>
+# Listen "127.0.0.1" "6666"
+# BufferSize 1024
+# BufferLength 10
+# RegexFilter "regex"
+#</Plugin>
+
#<Plugin table>
# <Table "/proc/slabinfo">
# #Plugin "table"
# InterfaceFormat name
# PluginInstanceFormat name
# Instances 1
-# ExtraStats "cpu_util disk disk_err domain_state fs_info job_stats_background pcpu perf vcpupin"
+# ExtraStats "cpu_util disk disk_err domain_state fs_info job_stats_background pcpu perf vcpu vcpupin disk_physical disk_allocation disk_capacity memory"
# PersistentNotification false
#</Plugin>
# SeparateInstances false
# PreserveSeparator false
# DropDuplicateFields false
+# ReverseHost false
# </Node>
#</Plugin>
# Url "https://monitoring.googleapis.com/v3"
#</Plugin>
+#<Plugin write_syslog>
+# <Node>
+# Host "localhost"
+# Port "44514"
+# Prefix "collectd"
+# MessageFormat "human"
+# HostTags ""
+# StoreRates false
+# AlwaysAppendDS false
+# </Node>
+#</Plugin>
+
#<Plugin write_tsdb>
# <Node>
# Host "localhost"
=back
+=head2 Plugin C<check_uptime>
+
+The I<check_uptime plugin> designed to check and notify about host or service
+status based on I<uptime> metric.
+
+When new metric of I<uptime> type appears in cache, OK notification is sent.
+When new value for metric is less than previous value, WARNING notification is
+sent about host/service restart.
+When no new updates comes for metric and cache entry expires, then FAILURE
+notification is sent about unreachable host or service.
+
+By default (when no explicit configuration), plugin checks for I<uptime> metric.
+
+B<Synopsis:>
+
+ <Plugin "check_uptime">
+ Type "uptime"
+ Type "my_uptime_type"
+ </Plugin>
+
+=over 4
+
+=item B<Type> I<Type>
+
+Metric type to check for status/values. The type should consist single GAUGE
+data source.
+
+=back
+
=head2 Plugin C<chrony>
The C<chrony> plugin collects ntp data from a B<chronyd> server, such as clock
=back
+=head2 Plugin Connectivity
+
+connectivity - Documentation of collectd's C<connectivity plugin>
+
+
+ LoadPlugin connectivity
+ # ...
+ <Plugin connectivity>
+ Interface eth0
+ </Plugin>
+
+The C<connectivity plugin> queries interface status using netlink (man 7 netlink) which provides information about network interfaces via the NETLINK_ROUTE family (man 7 rtnetlink). The plugin translates the value it receives to collectd's internal format and, depending on the write plugins you have loaded, it may be written to disk or submitted to another instance.
+The plugin listens to interfaces enumerated within the plugin configuration (see below). If no interfaces are listed, then the default is for all interfaces to be monitored.
+
+This example shows C<connectivity plugin> monitoring all interfaces.
+LoadPlugin connectivity
+<Plugin connectivity>
+</Plugin>
+
+This example shows C<connectivity plugin> monitoring 2 interfaces, "eth0" and "eth1".
+LoadPlugin connectivity
+<Plugin connectivity>
+ Interface eth0
+ Interface eth1
+</Plugin>
+
+This example shows C<connectivity plugin> monitoring all interfaces except "eth1".
+LoadPlugin connectivity
+<Plugin connectivity>
+ Interface eth1
+ IgnoreSelected true
+</Plugin>
+
+=over 4
+
+=item B<Interface> I<interface_name>
+
+interface(s) to monitor connect to.
+
+=back
+
=head2 Plugin C<conntrack>
This plugin collects IP conntrack statistics.
=head2 Plugin C<cpufreq>
-This plugin doesn't have any options. It reads
+This plugin is available on Linux and FreeBSD only. It doesn't have any
+options. On Linux it reads
F</sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq> (for the first CPU
installed) to get the current CPU frequency. If this file does not exist make
sure B<cpufreqd> (L<http://cpufreqd.sourceforge.net/>) or a similar tool is
installed and an "cpu governor" (that's a kernel module) is loaded.
-If the system has the I<cpufreq-stats> kernel module loaded, this plugin reports
-the rate of p-state (cpu frequency) transitions and the percentage of time spent
-in each p-state.
+On Linux, if the system has the I<cpufreq-stats> kernel module loaded, this
+plugin reports the rate of p-state (cpu frequency) transitions and the
+percentage of time spent in each p-state.
+
+On FreeBSD it does a sysctl dev.cpu.0.freq and submits this as instance 0.
+At this time FreeBSD only has one frequency setting for all cores.
+See the BUGS section in the FreeBSD man page for cpufreq(4) for more details.
+
+On FreeBSD the plugin checks the success of sysctl dev.cpu.0.freq and
+unregisters the plugin when this fails. A message will be logged to indicate
+this.
=head2 Plugin C<cpusleep>
<Page "stock_quotes">
Plugin "quotes"
URL "http://finance.google.com/finance?q=NYSE%3AAMD"
+ AddressFamily "any"
User "foo"
Password "bar"
Digest false
URL of the web site to retrieve. Since a regular expression will be used to
extract information from this data, non-binary data is a big plus here ;)
+=item B<AddressFamily> I<Type>
+
+IP version to resolve URL to. Useful in cases when hostname in URL resolves
+to both IPv4 and IPv6 addresses, and you are interested in using one of them
+specifically.
+Use C<ipv4> to enforce IPv4, C<ipv6> to enforce IPv6, or C<any> to keep the
+default behavior of resolving addresses to all IP versions your system allows.
+If C<libcurl> is compiled without IPv6 support, using C<ipv6> will result in
+a warning and fallback to C<any>.
+If C<Type> cannot be parsed, a warning will be printed and the whole B<Page>
+block will be ignored.
+
=item B<User> I<Name>
Username to use if authorization is required to read the page.
<Plugin curl_json>
<URL "http://localhost:5984/_stats">
+ AddressFamily "any"
Instance "httpd"
<Key "httpd/requests/count">
Type "http_requests"
=over 4
+=item B<AddressFamily> I<Type>
+
+IP version to resolve URL to. Useful in cases when hostname in URL resolves
+to both IPv4 and IPv6 addresses, and you are interested in using one of them
+specifically.
+Use C<ipv4> to enforce IPv4, C<ipv6> to enforce IPv6, or C<any> to keep the
+default behavior of resolving addresses to all IP versions your system allows.
+If C<libcurl> is compiled without IPv6 support, using C<ipv6> will result in
+a warning and fallback to C<any>.
+If C<Type> cannot be parsed, a warning will be printed and the whole B<URL>
+block will be ignored.
+
=item B<Host> I<Name>
Use I<Name> as the host name when submitting values. Defaults to the global
<Plugin "curl_xml">
<URL "http://localhost/stats.xml">
+ AddressFamily "any"
Host "my_host"
#Plugin "curl_xml"
Instance "some_instance"
=over 4
+=item B<AddressFamily> I<Type>
+
+IP version to resolve URL to. Useful in cases when hostname in URL resolves
+to both IPv4 and IPv6 addresses, and you are interested in using one of them
+specifically.
+Use C<ipv4> to enforce IPv4, C<ipv6> to enforce IPv6, or C<any> to keep the
+default behavior of resolving addresses to all IP versions your system allows.
+If C<libcurl> is compiled without IPv6 support, using C<ipv6> will result in
+a warning and fallback to C<any>.
+If C<Type> cannot be parsed, a warning will be printed and the whole B<URL>
+block will be ignored.
+
=item B<Host> I<Name>
Use I<Name> as the host name when submitting values. Defaults to the global
<Plugin "intel_rdt">
Cores "0-2" "3,4,6" "8-10,15"
+ Processes "sshd,qemu-system-x86" "bash"
</Plugin>
B<Options:>
=item B<Cores> I<cores groups>
-All events are reported on a per core basis. Monitoring of the events can be
-configured for group of cores (aggregated statistics). This field defines groups
-of cores on which to monitor supported events. The field is represented as list
-of strings with core group values. Each string represents a list of cores in a
-group. Allowed formats are:
+Monitoring of the events can be configured for group of cores
+(aggregated statistics). This field defines groups of cores on which to monitor
+supported events. The field is represented as list of strings with core group
+values. Each string represents a list of cores in a group. Allowed formats are:
0,1,2,3
0-10,20-18
1,3,5-8,10,0x10-12
If an empty string is provided as value for this field default cores
configuration is applied - a separate group is created for each core.
+=item B<Processes> I<process names groups>
+
+Monitoring of the events can be configured for group of processes
+(aggregated statistics). This field defines groups of processes on which to
+monitor supported events. The field is represented as list of strings with
+process names group values. Each string represents a list of processes in a
+group. Allowed format is:
+ sshd,bash,qemu
+
=back
B<Note:> By default global interval is used to retrieve statistics on monitored
For Modbus/RTU, specifies the baud rate of the serial device.
Note, connections currently support only 8/N/1.
+=item B<UARTType> I<UARTType>
+
+For Modbus/RTU, specifies the type of the serial device.
+RS232, RS422 and RS485 are supported. Defaults to RS232.
+Available only on Linux systems with libmodbus>=2.9.4.
+
=item B<Interval> I<Interval>
Sets the interval (in seconds) in which the values will be collected from this
Username to use when connecting to the database. The user does not have to be
granted any privileges (which is synonym to granting the C<USAGE> privilege),
-unless you want to collectd replication statistics (see B<MasterStats> and
+unless you want to collect replication statistics (see B<MasterStats> and
B<SlaveStats> below). In this case, the user needs the C<REPLICATION CLIENT>
(or C<SUPER>) privileges. Else, any existing MySQL user will do.
=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'
+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'.
+Defaults to B<false>.
=item B<ConnectTimeout> I<Seconds>
B<ProcessMatch> blocks these options set the default value for subsequent
matches.
+=head2 Plugin C<procevent>
+
+The I<procevent> plugin monitors when processes start (EXEC) and stop (EXIT).
+
+B<Synopsis:>
+
+ <Plugin procevent>
+ BufferLength 10
+ Process "name"
+ ProcessRegex "regex"
+ </Plugin>
+
+B<Options:>
+
+=over 4
+
+=item B<BufferLength> I<length>
+
+Maximum number of process events that can be stored in plugin's ring buffer.
+By default, this is set to 10. Once an event has been read, its location
+becomes available for storing a new event.
+
+=item B<Process> I<name>
+
+Enumerate a process name to monitor. All processes that match this exact
+name will be monitored for EXECs and EXITs.
+
+=item B<ProcessRegex> I<regex>
+
+Enumerate a process pattern to monitor. All processes that match this
+regular expression will be monitored for EXECs and EXITs.
+
+=back
+
=head2 Plugin C<protocols>
Collects a lot of information about various network protocols, such as I<IP>,
=back
+=head2 Plugin C<sysevent>
+
+The I<sysevent> plugin monitors rsyslog messages.
+
+B<Synopsis:>
+
+ <Plugin sysevent>
+ Listen "192.168.0.2" "6666"
+ BufferSize 1024
+ BufferLength 10
+ RegexFilter "regex"
+ </Plugin>
+
+ rsyslog should be configured such that it sends data to the IP and port you
+ include in the plugin configuration. For example, given the configuration
+ above, something like this would be set in /etc/rsyslog.conf:
+
+ if $programname != 'collectd' then
+ *.* @192.168.0.2:6666
+
+ This plugin is designed to consume JSON rsyslog data, so a more complete
+ rsyslog configuration would look like so (where we define a JSON template
+ and use it when sending data to our IP and port):
+
+ $template ls_json,"{%timestamp:::date-rfc3339,jsonf:@timestamp%, \
+ %source:::jsonf:@source_host%,\"@source\":\"syslog://%fromhost-ip:::json%\", \
+ \"@message\":\"%timestamp% %app-name%:%msg:::json%\",\"@fields\": \
+ {%syslogfacility-text:::jsonf:facility%,%syslogseverity:::jsonf:severity-num%, \
+ %syslogseverity-text:::jsonf:severity%,%programname:::jsonf:program%, \
+ %procid:::jsonf:processid%}}"
+
+ if $programname != 'collectd' then
+ *.* @192.168.0.2:6666;ls_json
+
+ Please note that these rsyslog.conf examples are *not* complete, as rsyslog
+ requires more than these options in the configuration file. These examples
+ are meant to demonstration the proper remote logging and JSON format syntax.
+
+B<Options:>
+
+=over 4
+
+=item B<Listen> I<host> I<port>
+
+Listen on this IP on this port for incoming rsyslog messages.
+
+=item B<BufferSize> I<length>
+
+Maximum allowed size for incoming rsyslog messages. Messages that exceed
+this number will be truncated to this size. Default is 4096 bytes.
+
+=item B<BufferLength> I<length>
+
+Maximum number of rsyslog events that can be stored in plugin's ring buffer.
+By default, this is set to 10. Once an event has been read, its location
+becomes available for storing a new event.
+
+=item B<RegexFilter> I<regex>
+
+Enumerate a regex filter to apply to all incoming rsyslog messages. If a
+message matches this filter, it will be published.
+
+=back
+
=head2 Plugin C<syslog>
=over 4
The default is to collect statistics for all domains and all their devices.
-Example:
+B<Note:> B<BlockDevice> and B<InterfaceDevice> options are related to
+corresponding B<*Format> options. Specifically, B<BlockDevice> filtering depends
+on B<BlockDeviceFormat> setting - if user wants to filter block devices by
+'target' name then B<BlockDeviceFormat> option has to be set to 'target' and
+B<BlockDevice> option must be set to a valid block device target
+name("/:hdb/"). Mixing formats and filter values from different worlds (i.e.,
+using 'target' name as B<BlockDevice> value with B<BlockDeviceFormat> set to
+'source') may lead to unexpected results (all devices filtered out or all
+visible, depending on the value of B<IgnoreSelected> option).
+Similarly, option B<InterfaceDevice> is related to B<InterfaceFormat> setting
+(i.e., when user wants to use MAC address as a filter then B<InterfaceFormat>
+has to be set to 'address' - using wrong type here may filter out all of the
+interfaces).
+
+B<Example 1:>
+
+Ignore all I<hdb> devices on any domain, but other block devices (eg. I<hda>)
+will be collected:
BlockDevice "/:hdb/"
IgnoreSelected "true"
+ BlockDeviceFormat "target"
-Ignore all I<hdb> devices on any domain, but other block devices (eg. I<hda>)
-will be collected.
+B<Example 2:>
+
+Collect metrics only for block device on 'baremetal0' domain when its
+'source' matches given path:
+
+ BlockDevice "baremetal0:/var/lib/libvirt/images/baremetal0.qcow2"
+ BlockDeviceFormat source
+
+As you can see it is possible to filter devices/interfaces using
+various formats - for block devices 'target' or 'source' name can be
+used. Interfaces can be filtered using 'name', 'address' or 'number'.
+
+B<Example 3:>
+
+Collect metrics only for domains 'baremetal0' and 'baremetal1' and
+ignore any other domain:
+
+ Domain "baremetal0"
+ Domain "baremetal1"
+
+It is possible to filter multiple block devices/domains/interfaces by
+adding multiple filtering entries in separate lines.
=item B<BlockDeviceFormat> B<target>|B<source>
Setting C<BlockDeviceFormat source> will cause the I<type instance> to be set
to C<var_lib_libvirt_images_image1.qcow2>.
+B<Note:> this option determines also what field will be used for
+filtering over block devices (filter value in B<BlockDevice>
+will be applied to target or source). More info about filtering
+block devices can be found in the description of B<BlockDevice>.
+
=item B<BlockDeviceFormatBasename> B<false>|B<true>
The B<BlockDeviceFormatBasename> controls whether the full path or the
B<number> means use the interface's number in guest.
+B<Note:> this option determines also what field will be used for
+filtering over interface device (filter value in B<InterfaceDevice>
+will be applied to name, address or number). More info about filtering
+interfaces can be found in the description of B<InterfaceDevice>.
+
=item B<PluginInstanceFormat> B<name|uuid|metadata|none>
When the virt plugin logs data, it sets the plugin_instance of the collected
=item B<disk_err>: report disk errors if any occured. Requires libvirt API version
I<0.9.10> or later.
-=item B<domain_state>: report domain state and reason in human-readable format as
-a notification. If libvirt API version I<0.9.2> or later is available, domain
-reason will be included in notification.
+=item B<domain_state>: report domain state and reason as 'domain_state' metric.
=item B<fs_info>: report file system information as a notification. Requires
libvirt API version I<1.2.11> or later. Can be collected only if I<Guest Agent>
a domain. Only one type of job statistics can be collected at the same time.
Requires libvirt API version I<1.2.9> or later.
+=item B<memory>: report statistics about memory usage details, provided
+by libvirt virDomainMemoryStats() function.
+
=item B<pcpu>: report the physical user/system cpu time consumed by the hypervisor, per-vm.
Requires libvirt API version I<0.9.11> or later.
libvirt API version I<1.3.3> or later.
B<Note>: I<perf> metrics can't be collected if I<intel_rdt> plugin is enabled.
+=item B<vcpu>: report domain virtual CPUs utilisation.
+
=item B<vcpupin>: report pinning of domain VCPUs to host physical CPUs.
+=item B<disk_physical>: report 'disk_physical' statistic for disk device.
+B<Note>: This statistic is only reported for disk devices with 'source'
+property available.
+
+=item B<disk_allocation>: report 'disk_allocation' statistic for disk device.
+B<Note>: This statistic is only reported for disk devices with 'source'
+property available.
+
+=item B<disk_capacity>: report 'disk_capacity' statistic for disk device.
+B<Note>: This statistic is only reported for disk devices with 'source'
+property available.
+
=back
=item B<PersistentNotification> B<true>|B<false>
LogSendErrors true
Prefix "collectd"
UseTags false
+ ReverseHost false
</Node>
</Plugin>
Default value: B<false>.
+=item B<ReverseHost> B<false>|B<true>
+
+If set to B<true>, the (dot separated) parts of the B<host> field of the
+I<value list> will be rewritten in reverse order. The rewrite happens I<before>
+special characters are replaced with the B<EscapeCharacter>.
+
+This option might be convenient if the metrics are presented with Graphite in a
+DNS like tree structure (probably without replacing dots in hostnames).
+
+Example:
+ Hostname "node3.cluster1.example.com"
+ LoadPlugin "cpu"
+ LoadPlugin "write_graphite"
+ <Plugin "write_graphite">
+ <Node "graphite.example.com">
+ EscapeCharacter "."
+ ReverseHost true
+ </Node>
+ </Plugin>
+
+ result on the wire: com.example.cluster1.node3.cpu-0.cpu-idle 99.900993 1543010932
+
+Default value: B<false>.
+
=back
=head2 Plugin C<write_log>
=back
+=head2 Plugin C<write_syslog>
+
+The C<write_syslog> plugin writes data in I<syslog> format log messages.
+It implements the basic syslog protocol, RFC 5424, extends it with
+content-based filtering, rich filtering capabilities,
+flexible configuration options and adds features such as using TCP for transport.
+The plugin can connect to a I<Syslog> daemon, like syslog-ng and rsyslog, that will
+ingest metrics, transform and ship them to the specified output.
+The plugin uses I<TCP> over the "line based" protocol with a default port 44514.
+The data will be sent in blocks of at most 1428 bytes to minimize the number of
+network packets.
+
+Synopsis:
+
+ <Plugin write_syslog>
+ ResolveInterval 60
+ ResolveJitter 60
+ <Node "example">
+ Host "syslog-1.my.domain"
+ Port "44514"
+ Prefix "collectd"
+ MessageFormat "human"
+ HostTags ""
+ </Node>
+ </Plugin>
+
+The configuration consists of one or more E<lt>B<Node>E<nbsp>I<Name>E<gt>
+blocks and global directives.
+
+Global directives are:
+
+=over 4
+
+=item B<ResolveInterval> I<seconds>
+
+=item B<ResolveJitter> I<seconds>
+
+When I<collectd> connects to a syslog node, it will request the hostname from
+DNS. This can become a problem if the syslog node is unavailable or badly
+configured because collectd will request DNS in order to reconnect for every
+metric, which can flood your DNS. So you can cache the last value for
+I<ResolveInterval> seconds.
+Defaults to the I<Interval> of the I<write_syslog plugin>, e.g. 10E<nbsp>seconds.
+
+You can also define a jitter, a random interval to wait in addition to
+I<ResolveInterval>. This prevents all your collectd servers to resolve the
+hostname at the same time when the connection fails.
+Defaults to the I<Interval> of the I<write_syslog plugin>, e.g. 10E<nbsp>seconds.
+
+B<Note:> If the DNS resolution has already been successful when the socket
+closes, the plugin will try to reconnect immediately with the cached
+information. DNS is queried only when the socket is closed for a longer than
+I<ResolveInterval> + I<ResolveJitter> seconds.
+
+=back
+
+Inside the B<Node> blocks, the following options are recognized:
+
+=over 4
+
+=item B<Host> I<Address>
+
+Hostname or address to connect to. Defaults to C<localhost>.
+
+=item B<Port> I<Service>
+
+Service name or port number to connect to. Defaults to C<44514>.
+
+
+=item B<HostTags> I<String>
+
+When set, I<HostTags> is added to the end of the metric.
+It is intended to be used for adding additional metadata to tag the metric with.
+Dots and whitespace are I<not> escaped in this string.
+
+Examples:
+
+When MessageFormat is set to "human".
+
+ ["prefix1" "example1"="example1_v"]["prefix2" "example2"="example2_v"]"
+
+When MessageFormat is set to "JSON", text should be in JSON format.
+Escaping the quotation marks is required.
+
+ HostTags "\"prefix1\": {\"example1\":\"example1_v\",\"example2\":\"example2_v\"}"
+
+=item B<MessageFormat> I<String>
+
+I<MessageFormat> selects the format in which messages are sent to the
+syslog deamon, human or JSON. Defaults to human.
+
+Syslog message format:
+
+<priority>VERSION ISOTIMESTAMP HOSTNAME APPLICATION PID MESSAGEID STRUCTURED-DATA MSG
+
+The difference between the message formats are in the STRUCTURED-DATA and MSG parts.
+
+Human format:
+
+ <166>1 ISOTIMESTAMP HOSTNAME collectd PID MESSAGEID
+ ["collectd" "value": "v1" "plugin"="plugin_v" "plugin_instance"="plugin_instance_v"
+ "type_instance"="type_instance_v" "type"="type_v" "ds_name"="ds_name_v" "interval"="interval_v" ]
+ "host_tag_example"="host_tag_example_v" plugin_v.type_v.ds_name_v="v1"
+
+JSON format:
+
+ <166>1 ISOTIMESTAMP HOSTNAME collectd PID MESSAGEID STRUCTURED-DATA
+ {
+ "collectd": {
+ "time": time_as_epoch, "interval": interval_v, "plugin": "plugin_v",
+ "plugin_instance": "plugin_instance_v", "type":"type_v",
+ "type_instance": "type_instance_v", "plugin_v": {"type_v": v1}
+ } , "host":"host_v", "host_tag_example": "host_tag_example_v"
+ }
+
+=item B<StoreRates> B<false>|B<true>
+
+If set to B<true>, convert counter values to rates. If set to B<false>
+(the default) counter values are stored as is, as an increasing
+integer number.
+
+=item B<AlwaysAppendDS> B<false>|B<true>
+
+If set to B<true>, append the name of the I<Data Source> (DS) to the "metric"
+identifier. If set to B<false> (the default), this is only done when there is
+more than one DS.
+
+=item B<Prefix> I<String>
+
+When set, I<Prefix> is added to all metrics names as a prefix. It is intended in
+case you want to be able to define the source of the specific metric. Dots and
+whitespace are I<not> escaped in this string.
+
+=back
+
=head2 Plugin C<xencpu>
This plugin collects metrics of hardware CPU load for machine running Xen
=head1 IGNORELISTS
B<Ignorelists> are a generic framework to either ignore some metrics or report
-specific metircs only. Plugins usually provide one or more options to specify
+specific metrics only. Plugins usually provide one or more options to specify
the items (mounts points, devices, ...) and the boolean option
C<IgnoreSelected>.
#include "config.h"
#endif
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *optarg;
extern int optind;
+/* _ssnprintf returns result from vsnprintf (consistent with snprintf) */
+static int _ssnprintf(char *str, size_t sz, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+
+ int ret = vsnprintf(str, sz, format, ap);
+
+ va_end(ap);
+
+ return ret;
+} /* int _ssnprintf */
+
__attribute__((noreturn)) static void exit_usage(const char *name, int status) {
fprintf(
(status == 0) ? stdout : stderr,
}
hostname[sizeof(hostname) - 1] = '\0';
- snprintf(ident_str, sizeof(ident_str), "%s/%s", hostname, value);
+ _ssnprintf(ident_str, sizeof(ident_str), "%s/%s", hostname, value);
ident_str[sizeof(ident_str) - 1] = '\0';
} else {
strncpy(ident_str, value, sizeof(ident_str));
value);
BAIL_OUT(-1);
} else if ((endptr != NULL) && (*endptr != '\0')) {
- fprintf(stderr, "WARNING: Ignoring trailing garbage after timeout: "
- "%s.\n",
+ fprintf(stderr,
+ "WARNING: Ignoring trailing garbage after timeout: "
+ "%s.\n",
endptr);
}
} else if (strcasecmp(key, "plugin") == 0) {
char id[1024];
lcc_identifier_to_string(c, id, sizeof(id), identifiers + j);
- fprintf(stderr, "ERROR: Failed to flush plugin `%s', "
- "identifier `%s': %s.\n",
+ fprintf(stderr,
+ "ERROR: Failed to flush plugin `%s', "
+ "identifier `%s': %s.\n",
(plugins[i] == NULL) ? "(all)" : plugins[i], id,
lcc_strerror(c));
}
status = lcc_identifier_to_string(c, id, sizeof(id), ret_ident + i);
if (status != 0) {
- fprintf(stderr, "ERROR: listval: Failed to convert returned "
- "identifier to a string: %s\n",
+ fprintf(stderr,
+ "ERROR: listval: Failed to convert returned "
+ "identifier to a string: %s\n",
lcc_strerror(c));
continue;
}
value);
return -1;
} else if ((endptr != NULL) && (*endptr != '\0')) {
- fprintf(stderr, "WARNING: Ignoring trailing garbage after "
- "interval: %s.\n",
+ fprintf(stderr,
+ "WARNING: Ignoring trailing garbage after "
+ "interval: %s.\n",
endptr);
}
} else {
switch (opt) {
case 's':
- snprintf(address, sizeof(address), "unix:%s", optarg);
+ _ssnprintf(address, sizeof(address), "unix:%s", optarg);
address[sizeof(address) - 1] = '\0';
break;
case 'h':
if (counter >= 10) {
unsigned int time_left = 300;
- syslog(LOG_ERR, "Error: collectd is respawning too fast - "
- "disabled for %i seconds",
+ syslog(LOG_ERR,
+ "Error: collectd is respawning too fast - "
+ "disabled for %i seconds",
time_left);
while (((time_left = sleep(time_left)) > 0) && loop == 0)
}
struct sigaction sa = {
- .sa_handler = sig_int_term_handler, .sa_flags = 0,
+ .sa_handler = sig_int_term_handler,
+ .sa_flags = 0,
};
sigemptyset(&sa.sa_mask);
--- /dev/null
+/**
+ * collectd - src/connectivity.c
+ *
+ * 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:
+ * Red Hat NFVPE
+ * Andrew Bays <abays at redhat.com>
+ * Aneesh Puttur <aputtur at redhat.com>
+ **/
+
+#include "collectd.h"
+
+#include "plugin.h"
+#include "utils/common/common.h"
+#include "utils/ignorelist/ignorelist.h"
+#include "utils_complain.h"
+
+#include <asm/types.h>
+#include <errno.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <yajl/yajl_common.h>
+#include <yajl/yajl_gen.h>
+#if HAVE_YAJL_YAJL_VERSION_H
+#include <yajl/yajl_version.h>
+#endif
+#if defined(YAJL_MAJOR) && (YAJL_MAJOR > 1)
+#define HAVE_YAJL_V2 1
+#endif
+
+#define MYPROTO NETLINK_ROUTE
+
+#define LINK_STATE_DOWN 0
+#define LINK_STATE_UP 1
+#define LINK_STATE_UNKNOWN 2
+
+#define CONNECTIVITY_DOMAIN_FIELD "domain"
+#define CONNECTIVITY_DOMAIN_VALUE "stateChange"
+#define CONNECTIVITY_EVENT_ID_FIELD "eventId"
+#define CONNECTIVITY_EVENT_NAME_FIELD "eventName"
+#define CONNECTIVITY_EVENT_NAME_DOWN_VALUE "down"
+#define CONNECTIVITY_EVENT_NAME_UP_VALUE "up"
+#define CONNECTIVITY_LAST_EPOCH_MICROSEC_FIELD "lastEpochMicrosec"
+#define CONNECTIVITY_PRIORITY_FIELD "priority"
+#define CONNECTIVITY_PRIORITY_VALUE "high"
+#define CONNECTIVITY_REPORTING_ENTITY_NAME_FIELD "reportingEntityName"
+#define CONNECTIVITY_REPORTING_ENTITY_NAME_VALUE "collectd connectivity plugin"
+#define CONNECTIVITY_SEQUENCE_FIELD "sequence"
+#define CONNECTIVITY_SEQUENCE_VALUE "0"
+#define CONNECTIVITY_SOURCE_NAME_FIELD "sourceName"
+#define CONNECTIVITY_START_EPOCH_MICROSEC_FIELD "startEpochMicrosec"
+#define CONNECTIVITY_VERSION_FIELD "version"
+#define CONNECTIVITY_VERSION_VALUE "1.0"
+
+#define CONNECTIVITY_NEW_STATE_FIELD "newState"
+#define CONNECTIVITY_NEW_STATE_FIELD_DOWN_VALUE "outOfService"
+#define CONNECTIVITY_NEW_STATE_FIELD_UP_VALUE "inService"
+#define CONNECTIVITY_OLD_STATE_FIELD "oldState"
+#define CONNECTIVITY_OLD_STATE_FIELD_DOWN_VALUE "outOfService"
+#define CONNECTIVITY_OLD_STATE_FIELD_UP_VALUE "inService"
+#define CONNECTIVITY_STATE_CHANGE_FIELDS_FIELD "stateChangeFields"
+#define CONNECTIVITY_STATE_CHANGE_FIELDS_VERSION_FIELD \
+ "stateChangeFieldsVersion"
+#define CONNECTIVITY_STATE_CHANGE_FIELDS_VERSION_VALUE "1.0"
+#define CONNECTIVITY_STATE_INTERFACE_FIELD "stateInterface"
+
+/*
+ * Private data types
+ */
+
+struct interface_list_s {
+ char *interface;
+
+ uint32_t status;
+ uint32_t prev_status;
+ uint32_t sent;
+ cdtime_t timestamp;
+
+ struct interface_list_s *next;
+};
+typedef struct interface_list_s interface_list_t;
+
+/*
+ * Private variables
+ */
+
+static ignorelist_t *ignorelist = NULL;
+
+static interface_list_t *interface_list_head = NULL;
+static int monitor_all_interfaces = 1;
+
+static int connectivity_netlink_thread_loop = 0;
+static int connectivity_netlink_thread_error = 0;
+static pthread_t connectivity_netlink_thread_id;
+static int connectivity_dequeue_thread_loop = 0;
+static pthread_t connectivity_dequeue_thread_id;
+static pthread_mutex_t connectivity_threads_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t connectivity_data_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t connectivity_cond = PTHREAD_COND_INITIALIZER;
+static int nl_sock = -1;
+static int event_id = 0;
+static int statuses_to_send = 0;
+
+static const char *config_keys[] = {"Interface", "IgnoreSelected"};
+static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
+
+/*
+ * Private functions
+ */
+
+static int gen_message_payload(int state, int old_state, const char *interface,
+ cdtime_t timestamp, char **buf) {
+ const unsigned char *buf2;
+ yajl_gen g;
+ char json_str[DATA_MAX_NAME_LEN];
+
+#if !defined(HAVE_YAJL_V2)
+ yajl_gen_config conf = {0};
+#endif
+
+#if HAVE_YAJL_V2
+ size_t len;
+ g = yajl_gen_alloc(NULL);
+ yajl_gen_config(g, yajl_gen_beautify, 0);
+#else
+ unsigned int len;
+ g = yajl_gen_alloc(&conf, NULL);
+#endif
+
+ yajl_gen_clear(g);
+
+ // *** BEGIN common event header ***
+
+ if (yajl_gen_map_open(g) != yajl_gen_status_ok)
+ goto err;
+
+ // domain
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_DOMAIN_FIELD,
+ strlen(CONNECTIVITY_DOMAIN_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_DOMAIN_VALUE,
+ strlen(CONNECTIVITY_DOMAIN_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // eventId
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_EVENT_ID_FIELD,
+ strlen(CONNECTIVITY_EVENT_ID_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ event_id = event_id + 1;
+ if (snprintf(json_str, sizeof(json_str), "%d", event_id) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // eventName
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_EVENT_NAME_FIELD,
+ strlen(CONNECTIVITY_EVENT_NAME_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "interface %s %s", interface,
+ (state == 0 ? CONNECTIVITY_EVENT_NAME_DOWN_VALUE
+ : CONNECTIVITY_EVENT_NAME_UP_VALUE)) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
+ yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // lastEpochMicrosec
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_LAST_EPOCH_MICROSEC_FIELD,
+ strlen(CONNECTIVITY_LAST_EPOCH_MICROSEC_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "%" PRIu64,
+ CDTIME_T_TO_US(cdtime())) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // priority
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_PRIORITY_FIELD,
+ strlen(CONNECTIVITY_PRIORITY_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_PRIORITY_VALUE,
+ strlen(CONNECTIVITY_PRIORITY_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // reportingEntityName
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_REPORTING_ENTITY_NAME_FIELD,
+ strlen(CONNECTIVITY_REPORTING_ENTITY_NAME_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_REPORTING_ENTITY_NAME_VALUE,
+ strlen(CONNECTIVITY_REPORTING_ENTITY_NAME_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // sequence
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_SEQUENCE_FIELD,
+ strlen(CONNECTIVITY_SEQUENCE_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, CONNECTIVITY_SEQUENCE_VALUE,
+ strlen(CONNECTIVITY_SEQUENCE_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // sourceName
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_SOURCE_NAME_FIELD,
+ strlen(CONNECTIVITY_SOURCE_NAME_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)interface, strlen(interface)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // startEpochMicrosec
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_START_EPOCH_MICROSEC_FIELD,
+ strlen(CONNECTIVITY_START_EPOCH_MICROSEC_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "%" PRIu64,
+ CDTIME_T_TO_US(timestamp)) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // version
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_VERSION_FIELD,
+ strlen(CONNECTIVITY_VERSION_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, CONNECTIVITY_VERSION_VALUE,
+ strlen(CONNECTIVITY_VERSION_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // *** END common event header ***
+
+ // *** BEGIN state change fields ***
+
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_STATE_CHANGE_FIELDS_FIELD,
+ strlen(CONNECTIVITY_STATE_CHANGE_FIELDS_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_map_open(g) != yajl_gen_status_ok)
+ goto err;
+
+ // newState
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_NEW_STATE_FIELD,
+ strlen(CONNECTIVITY_NEW_STATE_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ int new_state_len =
+ (state == 0 ? strlen(CONNECTIVITY_NEW_STATE_FIELD_DOWN_VALUE)
+ : strlen(CONNECTIVITY_NEW_STATE_FIELD_UP_VALUE));
+
+ if (yajl_gen_string(g,
+ (u_char *)(state == 0
+ ? CONNECTIVITY_NEW_STATE_FIELD_DOWN_VALUE
+ : CONNECTIVITY_NEW_STATE_FIELD_UP_VALUE),
+ new_state_len) != yajl_gen_status_ok)
+ goto err;
+
+ // oldState
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_OLD_STATE_FIELD,
+ strlen(CONNECTIVITY_OLD_STATE_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ int old_state_len =
+ (old_state == 0 ? strlen(CONNECTIVITY_OLD_STATE_FIELD_DOWN_VALUE)
+ : strlen(CONNECTIVITY_OLD_STATE_FIELD_UP_VALUE));
+
+ if (yajl_gen_string(g,
+ (u_char *)(old_state == 0
+ ? CONNECTIVITY_OLD_STATE_FIELD_DOWN_VALUE
+ : CONNECTIVITY_OLD_STATE_FIELD_UP_VALUE),
+ old_state_len) != yajl_gen_status_ok)
+ goto err;
+
+ // stateChangeFieldsVersion
+ if (yajl_gen_string(g,
+ (u_char *)CONNECTIVITY_STATE_CHANGE_FIELDS_VERSION_FIELD,
+ strlen(CONNECTIVITY_STATE_CHANGE_FIELDS_VERSION_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, CONNECTIVITY_STATE_CHANGE_FIELDS_VERSION_VALUE,
+ strlen(CONNECTIVITY_STATE_CHANGE_FIELDS_VERSION_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // stateInterface
+ if (yajl_gen_string(g, (u_char *)CONNECTIVITY_STATE_INTERFACE_FIELD,
+ strlen(CONNECTIVITY_STATE_INTERFACE_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)interface, strlen(interface)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // close state change and header fields
+ if (yajl_gen_map_close(g) != yajl_gen_status_ok ||
+ yajl_gen_map_close(g) != yajl_gen_status_ok)
+ goto err;
+
+ // *** END state change fields ***
+
+ if (yajl_gen_get_buf(g, &buf2, &len) != yajl_gen_status_ok)
+ goto err;
+
+ *buf = strdup((char *)buf2);
+
+ if (*buf == NULL) {
+ ERROR("connectivity plugin: strdup failed during gen_message_payload: %s",
+ STRERRNO);
+ goto err;
+ }
+
+ yajl_gen_free(g);
+
+ return 0;
+
+err:
+ yajl_gen_free(g);
+ ERROR("connectivity plugin: gen_message_payload failed to generate JSON");
+ return -1;
+}
+
+static interface_list_t *add_interface(const char *interface, int status,
+ int prev_status) {
+ interface_list_t *il = calloc(1, sizeof(*il));
+
+ if (il == NULL) {
+ ERROR("connectivity plugin: calloc failed during add_interface: %s",
+ STRERRNO);
+ return NULL;
+ }
+
+ char *interface2 = strdup(interface);
+ if (interface2 == NULL) {
+ sfree(il);
+ ERROR("connectivity plugin: strdup failed during add_interface: %s",
+ STRERRNO);
+ return NULL;
+ }
+
+ il->interface = interface2;
+ il->status = status;
+ il->prev_status = prev_status;
+ il->timestamp = cdtime();
+ il->sent = 0;
+ il->next = interface_list_head;
+ interface_list_head = il;
+
+ DEBUG("connectivity plugin: added interface %s", interface2);
+
+ return il;
+}
+
+static int connectivity_link_state(struct nlmsghdr *msg) {
+ pthread_mutex_lock(&connectivity_data_lock);
+
+ struct nlattr *attr;
+ struct ifinfomsg *ifi = mnl_nlmsg_get_payload(msg);
+
+ /* Scan attribute list for device name. */
+ mnl_attr_for_each(attr, msg, sizeof(*ifi)) {
+ if (mnl_attr_get_type(attr) != IFLA_IFNAME)
+ continue;
+
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
+ ERROR("connectivity plugin: connectivity_link_state: IFLA_IFNAME "
+ "mnl_attr_validate "
+ "failed.");
+ pthread_mutex_unlock(&connectivity_data_lock);
+ return MNL_CB_ERROR;
+ }
+
+ const char *dev = mnl_attr_get_str(attr);
+
+ // Check the list of interfaces we should monitor, if we've chosen
+ // a subset. If we don't care about this one, abort.
+ if (ignorelist_match(ignorelist, dev) != 0) {
+ DEBUG("connectivity plugin: Ignoring link state change for unmonitored "
+ "interface: %s",
+ dev);
+ break;
+ }
+
+ interface_list_t *il = NULL;
+
+ for (il = interface_list_head; il != NULL; il = il->next)
+ if (strcmp(dev, il->interface) == 0)
+ break;
+
+ if (il == NULL) {
+ // We haven't encountered this interface yet, so add it to the linked list
+ il = add_interface(dev, LINK_STATE_UNKNOWN, LINK_STATE_UNKNOWN);
+
+ if (il == NULL) {
+ ERROR("connectivity plugin: unable to add interface %s during "
+ "connectivity_link_state",
+ dev);
+ return MNL_CB_ERROR;
+ }
+ }
+
+ uint32_t prev_status = il->status;
+ il->status =
+ ((ifi->ifi_flags & IFF_RUNNING) ? LINK_STATE_UP : LINK_STATE_DOWN);
+ il->timestamp = cdtime();
+
+ // If the new status is different than the previous status,
+ // store the previous status and set sent to zero, and set the
+ // global flag to indicate there are statuses to dispatch
+ if (il->status != prev_status) {
+ il->prev_status = prev_status;
+ il->sent = 0;
+ statuses_to_send = 1;
+ }
+
+ DEBUG("connectivity plugin (%llu): Interface %s status is now %s",
+ (unsigned long long)il->timestamp, dev,
+ ((ifi->ifi_flags & IFF_RUNNING) ? "UP" : "DOWN"));
+
+ // no need to loop again, we found the interface name attr
+ // (otherwise the first if-statement in the loop would
+ // have moved us on with 'continue')
+ break;
+ }
+
+ pthread_mutex_unlock(&connectivity_data_lock);
+
+ return 0;
+}
+
+static int msg_handler(struct nlmsghdr *msg) {
+ // We are only interested in RTM_NEWLINK messages
+ if (msg->nlmsg_type != RTM_NEWLINK) {
+ return 0;
+ }
+ return connectivity_link_state(msg);
+}
+
+static int read_event(int (*msg_handler)(struct nlmsghdr *)) {
+ int ret = 0;
+ int recv_flags = MSG_DONTWAIT;
+
+ if (nl_sock == -1 || msg_handler == NULL)
+ return EINVAL;
+
+ while (42) {
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ if (connectivity_netlink_thread_loop <= 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+ return ret;
+ }
+
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ char buf[4096];
+ int status = recv(nl_sock, buf, sizeof(buf), recv_flags);
+
+ if (status < 0) {
+
+ // If there were no more messages to drain from the socket,
+ // then signal the dequeue thread and allow it to dispatch
+ // any saved interface status changes. Then continue, but
+ // block and wait for new messages
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ pthread_cond_signal(&connectivity_cond);
+
+ recv_flags = 0;
+ continue;
+ }
+
+ if (errno == EINTR) {
+ // Interrupt, so just continue and try again
+ continue;
+ }
+
+ /* Anything else is an error */
+ ERROR("connectivity plugin: read_event: Error recv: %d", status);
+ return status;
+ }
+
+ // Message received successfully, so we'll stop blocking on the
+ // receive call for now (until we get a "would block" error, which
+ // will be handled above)
+ recv_flags = MSG_DONTWAIT;
+
+ if (status == 0) {
+ DEBUG("connectivity plugin: read_event: EOF");
+ }
+
+ /* We need to handle more than one message per 'recvmsg' */
+ for (struct nlmsghdr *h = (struct nlmsghdr *)buf;
+ NLMSG_OK(h, (unsigned int)status); h = NLMSG_NEXT(h, status)) {
+ /* Finish reading */
+ if (h->nlmsg_type == NLMSG_DONE)
+ return ret;
+
+ /* Message is some kind of error */
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *l_err = (struct nlmsgerr *)NLMSG_DATA(h);
+ ERROR("connectivity plugin: read_event: Message is an error: %d",
+ l_err->error);
+ return -1; // Error
+ }
+
+ /* Call message handler */
+ if (msg_handler) {
+ ret = (*msg_handler)(h);
+ if (ret < 0) {
+ ERROR("connectivity plugin: read_event: Message handler error %d",
+ ret);
+ return ret;
+ }
+ } else {
+ ERROR("connectivity plugin: read_event: Error NULL message handler");
+ return -1;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void connectivity_dispatch_notification(const char *interface,
+ gauge_t value, gauge_t old_value,
+ cdtime_t timestamp) {
+
+ notification_t n = {
+ .severity = (value == LINK_STATE_UP ? NOTIF_OKAY : NOTIF_FAILURE),
+ .time = cdtime(),
+ .plugin = "connectivity",
+ .type = "gauge",
+ .type_instance = "interface_status",
+ };
+
+ sstrncpy(n.host, hostname_g, sizeof(n.host));
+ sstrncpy(n.plugin_instance, interface, sizeof(n.plugin_instance));
+
+ char *buf = NULL;
+
+ gen_message_payload(value, old_value, interface, timestamp, &buf);
+
+ int status = plugin_notification_meta_add_string(&n, "ves", buf);
+
+ if (status < 0) {
+ sfree(buf);
+ ERROR("connectivity plugin: unable to set notification VES metadata: %s",
+ STRERRNO);
+ return;
+ }
+
+ DEBUG("connectivity plugin: notification VES metadata: %s",
+ n.meta->nm_value.nm_string);
+
+ DEBUG("connectivity plugin: dispatching state %d for interface %s",
+ (int)value, interface);
+
+ plugin_dispatch_notification(&n);
+ plugin_notification_meta_free(n.meta);
+
+ // strdup'd in gen_message_payload
+ if (buf != NULL)
+ sfree(buf);
+}
+
+// NOTE: Caller MUST hold connectivity_data_lock when calling this function
+static void send_interface_status() {
+ for (interface_list_t *il = interface_list_head; il != NULL;
+ il = il->next) /* {{{ */
+ {
+ uint32_t status = il->status;
+ uint32_t prev_status = il->prev_status;
+ uint32_t sent = il->sent;
+
+ if (status != prev_status && sent == 0) {
+ connectivity_dispatch_notification(il->interface, status, prev_status,
+ il->timestamp);
+ il->sent = 1;
+ }
+ } /* }}} for (il = interface_list_head; il != NULL; il = il->next) */
+
+ statuses_to_send = 0;
+}
+
+static void read_interface_status() /* {{{ */
+{
+ pthread_mutex_lock(&connectivity_data_lock);
+
+ // If we don't have any interface statuses to dispatch,
+ // then we wait until signalled
+ if (!statuses_to_send)
+ pthread_cond_wait(&connectivity_cond, &connectivity_data_lock);
+
+ send_interface_status();
+
+ pthread_mutex_unlock(&connectivity_data_lock);
+} /* }}} int *read_interface_status */
+
+static void *connectivity_netlink_thread(void *arg) /* {{{ */
+{
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ while (connectivity_netlink_thread_loop > 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ int status = read_event(msg_handler);
+
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ if (status < 0) {
+ connectivity_netlink_thread_error = 1;
+ break;
+ }
+ } /* while (connectivity_netlink_thread_loop > 0) */
+
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ return (void *)0;
+} /* }}} void *connectivity_netlink_thread */
+
+static void *connectivity_dequeue_thread(void *arg) /* {{{ */
+{
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ while (connectivity_dequeue_thread_loop > 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ read_interface_status();
+
+ pthread_mutex_lock(&connectivity_threads_lock);
+ } /* while (connectivity_dequeue_thread_loop > 0) */
+
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ return ((void *)0);
+} /* }}} void *connectivity_dequeue_thread */
+
+static int nl_connect() {
+ struct sockaddr_nl sa_nl = {
+ .nl_family = AF_NETLINK,
+ .nl_groups = RTMGRP_LINK,
+ .nl_pid = getpid(),
+ };
+
+ nl_sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
+ if (nl_sock == -1) {
+ ERROR("connectivity plugin: socket open failed: %s", STRERRNO);
+ return -1;
+ }
+
+ int rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
+ if (rc == -1) {
+ ERROR("connectivity plugin: socket bind failed: %s", STRERRNO);
+ close(nl_sock);
+ nl_sock = -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int start_netlink_thread(void) /* {{{ */
+{
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ if (connectivity_netlink_thread_loop != 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+ return 0;
+ }
+
+ connectivity_netlink_thread_loop = 1;
+ connectivity_netlink_thread_error = 0;
+
+ int status;
+
+ if (nl_sock == -1) {
+ status = nl_connect();
+
+ if (status != 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+ return status;
+ }
+ }
+
+ status = plugin_thread_create(&connectivity_netlink_thread_id,
+ /* attr = */ NULL, connectivity_netlink_thread,
+ /* arg = */ (void *)0, "connectivity");
+ if (status != 0) {
+ connectivity_netlink_thread_loop = 0;
+ ERROR("connectivity plugin: Starting thread failed.");
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ int status2 = close(nl_sock);
+
+ if (status2 != 0) {
+ ERROR("connectivity plugin: failed to close socket %d: %d (%s)", nl_sock,
+ status2, STRERRNO);
+ }
+
+ nl_sock = -1;
+
+ return -1;
+ }
+
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ return status;
+}
+
+static int start_dequeue_thread(void) /* {{{ */
+{
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ if (connectivity_dequeue_thread_loop != 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+ return 0;
+ }
+
+ connectivity_dequeue_thread_loop = 1;
+
+ int status =
+ plugin_thread_create(&connectivity_dequeue_thread_id,
+ /* attr = */ NULL, connectivity_dequeue_thread,
+ /* arg = */ (void *)0, "connectivity");
+ if (status != 0) {
+ connectivity_dequeue_thread_loop = 0;
+ ERROR("connectivity plugin: Starting dequeue thread failed.");
+ pthread_mutex_unlock(&connectivity_threads_lock);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ return status;
+} /* }}} int start_dequeue_thread */
+
+static int start_threads(void) /* {{{ */
+{
+ int status = start_netlink_thread();
+ int status2 = start_dequeue_thread();
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int start_threads */
+
+static int stop_netlink_thread(int shutdown) /* {{{ */
+{
+ int socket_status;
+
+ if (nl_sock != -1) {
+ socket_status = close(nl_sock);
+ if (socket_status != 0) {
+ ERROR("connectivity plugin: failed to close socket %d: %d (%s)", nl_sock,
+ socket_status, STRERRNO);
+ }
+
+ nl_sock = -1;
+ } else
+ socket_status = 0;
+
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ if (connectivity_netlink_thread_loop == 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+ // Thread has already been terminated, nothing more to attempt
+ return socket_status;
+ }
+
+ // Set thread termination status
+ connectivity_netlink_thread_loop = 0;
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ // Let threads waiting on access to the interface list know to move
+ // on such that they'll see the thread's termination status
+ pthread_cond_broadcast(&connectivity_cond);
+
+ int thread_status;
+
+ if (shutdown == 1) {
+ // Since the thread is blocking, calling pthread_join
+ // doesn't actually succeed in stopping it. It will stick around
+ // until a NETLINK message is received on the socket (at which
+ // it will realize that "connectivity_netlink_thread_loop" is 0 and will
+ // break out of the read loop and be allowed to die). This is
+ // fine when the process isn't supposed to be exiting, but in
+ // the case of a process shutdown, we don't want to have an
+ // idle thread hanging around. Calling pthread_cancel here in
+ // the case of a shutdown is just assures that the thread is
+ // gone and that the process has been fully terminated.
+
+ DEBUG("connectivity plugin: Canceling netlink thread for process shutdown");
+
+ thread_status = pthread_cancel(connectivity_netlink_thread_id);
+
+ if (thread_status != 0 && thread_status != ESRCH) {
+ ERROR("connectivity plugin: Unable to cancel netlink thread: %d",
+ thread_status);
+ thread_status = -1;
+ } else
+ thread_status = 0;
+ } else {
+ thread_status =
+ pthread_join(connectivity_netlink_thread_id, /* return = */ NULL);
+ if (thread_status != 0 && thread_status != ESRCH) {
+ ERROR("connectivity plugin: Stopping netlink thread failed: %d",
+ thread_status);
+ thread_status = -1;
+ } else
+ thread_status = 0;
+ }
+
+ pthread_mutex_lock(&connectivity_threads_lock);
+ memset(&connectivity_netlink_thread_id, 0,
+ sizeof(connectivity_netlink_thread_id));
+ connectivity_netlink_thread_error = 0;
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ DEBUG("connectivity plugin: Finished requesting stop of netlink thread");
+
+ if (socket_status != 0)
+ return socket_status;
+ else
+ return thread_status;
+}
+
+static int stop_dequeue_thread() /* {{{ */
+{
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ if (connectivity_dequeue_thread_loop == 0) {
+ pthread_mutex_unlock(&connectivity_threads_lock);
+ return -1;
+ }
+
+ // Set thread termination status
+ connectivity_dequeue_thread_loop = 0;
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ // Let threads waiting on access to the interface list know to move
+ // on such that they'll see the threads termination status
+ pthread_cond_broadcast(&connectivity_cond);
+
+ // Calling pthread_cancel here just assures that the thread is
+ // gone and that the process has been fully terminated.
+
+ DEBUG("connectivity plugin: Canceling dequeue thread for process shutdown");
+
+ int status = pthread_cancel(connectivity_dequeue_thread_id);
+
+ if (status != 0 && status != ESRCH) {
+ ERROR("connectivity plugin: Unable to cancel dequeue thread: %d", status);
+ status = -1;
+ } else
+ status = 0;
+
+ pthread_mutex_lock(&connectivity_threads_lock);
+ memset(&connectivity_dequeue_thread_id, 0,
+ sizeof(connectivity_dequeue_thread_id));
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ DEBUG("connectivity plugin: Finished requesting stop of dequeue thread");
+
+ return status;
+} /* }}} int stop_dequeue_thread */
+
+static int stop_threads() /* {{{ */
+{
+ int status = stop_netlink_thread(1);
+ int status2 = stop_dequeue_thread();
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int stop_threads */
+
+static int connectivity_init(void) /* {{{ */
+{
+ if (monitor_all_interfaces) {
+ NOTICE("connectivity plugin: No interfaces have been selected, so all will "
+ "be monitored");
+ }
+
+ return start_threads();
+} /* }}} int connectivity_init */
+
+static int connectivity_config(const char *key, const char *value) /* {{{ */
+{
+ if (ignorelist == NULL) {
+ ignorelist = ignorelist_create(/* invert = */ 1);
+
+ if (ignorelist == NULL)
+ return -1;
+ }
+
+ if (strcasecmp(key, "Interface") == 0) {
+ ignorelist_add(ignorelist, value);
+ monitor_all_interfaces = 0;
+ } else if (strcasecmp(key, "IgnoreSelected") == 0) {
+ int invert = 1;
+ if (IS_TRUE(value))
+ invert = 0;
+ ignorelist_set_invert(ignorelist, invert);
+ } else {
+ return -1;
+ }
+
+ return 0;
+} /* }}} int connectivity_config */
+
+static int connectivity_read(void) /* {{{ */
+{
+ pthread_mutex_lock(&connectivity_threads_lock);
+
+ if (connectivity_netlink_thread_error != 0) {
+
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ ERROR("connectivity plugin: The netlink thread had a problem. Restarting "
+ "it.");
+
+ stop_netlink_thread(0);
+
+ for (interface_list_t *il = interface_list_head; il != NULL;
+ il = il->next) {
+ il->status = LINK_STATE_UNKNOWN;
+ il->prev_status = LINK_STATE_UNKNOWN;
+ il->sent = 0;
+ }
+
+ start_netlink_thread();
+
+ return -1;
+ } /* if (connectivity_netlink_thread_error != 0) */
+
+ pthread_mutex_unlock(&connectivity_threads_lock);
+
+ return 0;
+} /* }}} int connectivity_read */
+
+static int connectivity_shutdown(void) /* {{{ */
+{
+ DEBUG("connectivity plugin: Shutting down thread.");
+
+ int status = stop_threads();
+
+ interface_list_t *il = interface_list_head;
+ while (il != NULL) {
+ interface_list_t *il_next;
+
+ il_next = il->next;
+
+ sfree(il->interface);
+ sfree(il);
+
+ il = il_next;
+ }
+
+ ignorelist_free(ignorelist);
+
+ return status;
+} /* }}} int connectivity_shutdown */
+
+void module_register(void) {
+ plugin_register_config("connectivity", connectivity_config, config_keys,
+ config_keys_num);
+ plugin_register_init("connectivity", connectivity_init);
+ plugin_register_read("connectivity", connectivity_read);
+ plugin_register_shutdown("connectivity", connectivity_shutdown);
+} /* void module_register */
#include "plugin.h"
#include "utils/common/common.h"
-#ifdef HAVE_SYS_SYSCTL_H
+#if defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYS_SYSCTL_H)
#include <sys/sysctl.h>
-#endif
-
-#if HAVE_SYSCTLBYNAME
/* no global variables */
/* #endif HAVE_SYSCTLBYNAME */
}
cs_submit(value);
-/* #endif HAVE_SYSCTLBYNAME */
+ /* #endif HAVE_SYSCTLBYNAME */
#elif KERNEL_LINUX
FILE *fh;
if (status == -2)
ERROR("contextswitch plugin: Unable to find context switch value.");
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_PERFSTAT
int status = 0;
#include <sys/sysinfo.h>
#endif /* HAVE_LIBKSTAT */
-#if (defined(HAVE_SYSCTL) && HAVE_SYSCTL) || \
- (defined(HAVE_SYSCTLBYNAME) && HAVE_SYSCTLBYNAME)
-#ifdef HAVE_SYS_SYSCTL_H
+#if (defined(HAVE_SYSCTL) && defined(HAVE_SYSCTLBYNAME)) || defined(__OpenBSD__)
+/* Implies BSD variant */
#include <sys/sysctl.h>
#endif
#ifdef HAVE_SYS_DKSTAT_H
+/* implies BSD variant */
#include <sys/dkstat.h>
-#endif
#if !defined(CP_USER) || !defined(CP_NICE) || !defined(CP_SYS) || \
!defined(CP_INTR) || !defined(CP_IDLE) || !defined(CPUSTATES)
#define CP_IDLE 4
#define CPUSTATES 5
#endif
-#endif /* HAVE_SYSCTL || HAVE_SYSCTLBYNAME */
+#endif /* HAVE_SYS_DKSTAT_H */
-#if HAVE_SYSCTL
+#define CAN_USE_SYSCTL 0
+#if (defined(HAVE_SYSCTL) && defined(HAVE_SYSCTLBYNAME)) || defined(__OpenBSD__)
+/* Implies BSD variant */
#if defined(CTL_HW) && defined(HW_NCPU) && defined(CTL_KERN) && \
defined(KERN_CPTIME) && defined(CPUSTATES)
#define CAN_USE_SYSCTL 1
-#else
-#define CAN_USE_SYSCTL 0
-#endif
-#else
-#define CAN_USE_SYSCTL 0
#endif
+#endif /* HAVE_SYSCTL_H && HAVE_SYSCTLBYNAME || __OpenBSD__ */
#define COLLECTD_CPU_STATE_USER 0
#define COLLECTD_CPU_STATE_SYSTEM 1
/* #endif HAVE_LIBKSTAT */
#elif CAN_USE_SYSCTL
+/* Only possible for (Open) BSD variant */
static int numcpu;
/* #endif CAN_USE_SYSCTL */
#elif defined(HAVE_SYSCTLBYNAME)
+/* Implies BSD variant */
static int numcpu;
#ifdef HAVE_SYSCTL_KERN_CP_TIMES
static int maxcpu;
INFO("cpu plugin: Found %i processor%s.", (int)cpu_list_len,
cpu_list_len == 1 ? "" : "s");
-/* #endif PROCESSOR_CPU_LOAD_INFO */
+ /* #endif PROCESSOR_CPU_LOAD_INFO */
#elif defined(HAVE_LIBKSTAT)
kstat_t *ksp_chain;
ksp_chain = ksp_chain->ks_next)
if (strncmp(ksp_chain->ks_module, "cpu_stat", 8) == 0)
ksp[numcpu++] = ksp_chain;
-/* #endif HAVE_LIBKSTAT */
+ /* #endif HAVE_LIBKSTAT */
#elif CAN_USE_SYSCTL
+ /* Only on (Open) BSD variant */
size_t numcpu_size;
int mib[2] = {CTL_HW, HW_NCPU};
int status;
WARNING("cpu plugin: sysctl: %s", STRERRNO);
return -1;
}
-/* #endif CAN_USE_SYSCTL */
+ /* #endif CAN_USE_SYSCTL */
#elif defined(HAVE_SYSCTLBYNAME)
+ /* Only on BSD varient */
size_t numcpu_size;
numcpu_size = sizeof(numcpu);
"%i)",
numcpu);
#endif
-/* #endif HAVE_SYSCTLBYNAME */
+ /* #endif HAVE_SYSCTLBYNAME */
#elif defined(HAVE_LIBSTATGRAB)
/* nothing to initialize */
cpu_stage(cpu, COLLECTD_CPU_STATE_IDLE,
(derive_t)cpu_info.cpu_ticks[CPU_STATE_IDLE], now);
}
-/* }}} #endif PROCESSOR_CPU_LOAD_INFO */
+ /* }}} #endif PROCESSOR_CPU_LOAD_INFO */
#elif defined(KERNEL_LINUX) /* {{{ */
int cpu;
cpu_stage(cpu, COLLECTD_CPU_STATE_NICE, (derive_t)nice_value, now);
}
fclose(fh);
-/* }}} #endif defined(KERNEL_LINUX) */
+ /* }}} #endif defined(KERNEL_LINUX) */
#elif defined(HAVE_LIBKSTAT) /* {{{ */
static cpu_stat_t cs;
cpu_stage(ksp[cpu]->ks_instance, COLLECTD_CPU_STATE_WAIT,
(derive_t)cs.cpu_sysinfo.cpu[CPU_WAIT], now);
}
-/* }}} #endif defined(HAVE_LIBKSTAT) */
+ /* }}} #endif defined(HAVE_LIBKSTAT) */
#elif CAN_USE_SYSCTL /* {{{ */
+ /* Only on (Open) BSD variant */
uint64_t cpuinfo[numcpu][CPUSTATES];
size_t cpuinfo_size;
int status;
cpu_stage(i, COLLECTD_CPU_STATE_INTERRUPT, (derive_t)cpuinfo[i][CP_INTR],
now);
}
-/* }}} #endif CAN_USE_SYSCTL */
+ /* }}} #endif CAN_USE_SYSCTL */
#elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES) /* {{{ \
- */
+ */
+ /* Only on BSD variant */
long cpuinfo[maxcpu][CPUSTATES];
size_t cpuinfo_size;
cpu_stage(i, COLLECTD_CPU_STATE_INTERRUPT, (derive_t)cpuinfo[i][CP_INTR],
now);
}
-/* }}} #endif HAVE_SYSCTL_KERN_CP_TIMES */
+ /* }}} #endif HAVE_SYSCTL_KERN_CP_TIMES */
#elif defined(HAVE_SYSCTLBYNAME) /* {{{ */
+ /* Only on BSD variant */
long cpuinfo[CPUSTATES];
size_t cpuinfo_size;
cpu_stage(0, COLLECTD_CPU_STATE_SYSTEM, (derive_t)cpuinfo[CP_SYS], now);
cpu_stage(0, COLLECTD_CPU_STATE_IDLE, (derive_t)cpuinfo[CP_IDLE], now);
cpu_stage(0, COLLECTD_CPU_STATE_INTERRUPT, (derive_t)cpuinfo[CP_INTR], now);
-/* }}} #endif HAVE_SYSCTLBYNAME */
+ /* }}} #endif HAVE_SYSCTLBYNAME */
#elif defined(HAVE_LIBSTATGRAB) /* {{{ */
sg_cpu_stats *cs;
cpu_state(0, COLLECTD_CPU_STATE_SYSTEM, (derive_t)cs->kernel);
cpu_state(0, COLLECTD_CPU_STATE_USER, (derive_t)cs->user);
cpu_state(0, COLLECTD_CPU_STATE_WAIT, (derive_t)cs->iowait);
-/* }}} #endif HAVE_LIBSTATGRAB */
+ /* }}} #endif HAVE_LIBSTATGRAB */
#elif defined(HAVE_PERFSTAT) /* {{{ */
perfstat_id_t id;
#include "plugin.h"
#include "utils/common/common.h"
+#if KERNEL_FREEBSD
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#endif
+
+#if KERNEL_LINUX
#define MAX_AVAIL_FREQS 20
static int num_cpu;
}
return;
}
+#endif /* KERNEL_LINUX */
static int cpufreq_init(void) {
+#if KERNEL_LINUX
char filename[PATH_MAX];
num_cpu = 0;
if (num_cpu == 0)
plugin_unregister_read("cpufreq");
+#elif KERNEL_FREEBSD
+ char mib[] = "dev.cpu.0.freq";
+ int cpufreq;
+ size_t cf_len = sizeof(cpufreq);
+
+ if (sysctlbyname(mib, &cpufreq, &cf_len, NULL, 0) != 0) {
+ WARNING("cpufreq plugin: sysctl \"%s\" failed.", mib);
+ plugin_unregister_read("cpufreq");
+ }
+#endif
return 0;
} /* int cpufreq_init */
plugin_dispatch_values(&vl);
}
+#if KERNEL_LINUX
static void cpufreq_read_stats(int cpu) {
char filename[PATH_MAX];
/* Read total transitions for cpu frequency */
}
fclose(fh);
}
+#endif /* KERNEL_LINUX */
static int cpufreq_read(void) {
+#if KERNEL_LINUX
for (int cpu = 0; cpu < num_cpu; cpu++) {
char filename[PATH_MAX];
/* Read cpu frequency */
if (report_p_stats)
cpufreq_read_stats(cpu);
}
+#elif KERNEL_FREEBSD
+ /* FreeBSD currently only has 1 freq setting. See BUGS in cpufreq(4) */
+ char mib[] = "dev.cpu.0.freq";
+ int cpufreq;
+ size_t cf_len = sizeof(cpufreq);
+
+ if (sysctlbyname(mib, &cpufreq, &cf_len, NULL, 0) != 0) {
+ WARNING("cpufreq plugin: sysctl \"%s\" failed.", mib);
+ return 0;
+ }
+
+ value_t v;
+ /* convert Mhz to Hz */
+ v.gauge = cpufreq * 1000000.0;
+
+ cpufreq_submit(0, "cpufreq", NULL, &v);
+#endif
return 0;
} /* int cpufreq_read */
* CPU sleep is reported in milliseconds of sleep per second of wall
* time. For that, the time difference between BOOT and MONOTONIC clocks
* is reported using derive type.
-**/
+ **/
#include "collectd.h"
typedef struct {
PluginData data;
- PyObject *meta; /* dict */
+ PyObject *meta; /* dict */
int severity;
char message[NOTIF_MAX_MSG_LEN];
} Notification;
char *instance;
char *url;
+ int address_family;
char *user;
char *pass;
char *credentials;
curl_easy_setopt(wp->curl, CURLOPT_ERRORBUFFER, wp->curl_errbuf);
curl_easy_setopt(wp->curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(wp->curl, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(wp->curl, CURLOPT_IPRESOLVE, wp->address_family);
if (wp->user != NULL) {
#ifdef HAVE_CURLOPT_USERNAME
}
page->plugin_name = NULL;
page->url = NULL;
+ page->address_family = CURL_IPRESOLVE_WHATEVER;
page->user = NULL;
page->pass = NULL;
page->digest = false;
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)
+ else if (strcasecmp("AddressFamily", child->key) == 0) {
+ char *af = NULL;
+ status = cf_util_get_string(child, &af);
+ if (status != 0 || af == NULL) {
+ WARNING("curl plugin: Cannot parse value of `%s' "
+ "for instance `%s'.",
+ child->key, page->instance);
+ } else if (strcasecmp("any", af) == 0) {
+ page->address_family = CURL_IPRESOLVE_WHATEVER;
+ } else if (strcasecmp("ipv4", af) == 0) {
+ page->address_family = CURL_IPRESOLVE_V4;
+ } else if (strcasecmp("ipv6", af) == 0) {
+ /* If curl supports ipv6, use it. If not, log a warning and
+ * fall back to default - don't set status to non-zero.
+ */
+ curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
+ if (curl_info->features & CURL_VERSION_IPV6)
+ page->address_family = CURL_IPRESOLVE_V6;
+ else
+ WARNING("curl plugin: IPv6 not supported by this libCURL. "
+ "Using fallback `any'.");
+ } else {
+ WARNING("curl plugin: Unsupported value of `%s' "
+ "for instance `%s'.",
+ child->key, page->instance);
+ status = -1;
+ }
+ } else if (strcasecmp("User", child->key) == 0)
status = cf_util_get_string(child, &page->user);
else if (strcasecmp("Password", child->key) == 0)
status = cf_util_get_string(child, &page->pass);
plugin_register_complex_read(/* group = */ NULL, cb_name, cc_read_page,
interval,
&(user_data_t){
- .data = page, .free_func = cc_web_page_free,
+ .data = page,
+ .free_func = cc_web_page_free,
});
sfree(cb_name);
char *sock;
char *url;
+ int address_family;
char *user;
char *pass;
char *credentials;
curl_easy_setopt(db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf);
curl_easy_setopt(db->curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(db->curl, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(db->curl, CURLOPT_IPRESOLVE, db->address_family);
if (db->user != NULL) {
#ifdef HAVE_CURLOPT_USERNAME
}
db->timeout = -1;
+ db->address_family = CURL_IPRESOLVE_WHATEVER;
if (strcasecmp("URL", ci->key) == 0)
status = cf_util_get_string(ci, &db->url);
db->stats = curl_stats_from_config(child);
if (db->stats == NULL)
status = -1;
+ } else if (db->url && strcasecmp("AddressFamily", child->key) == 0) {
+ char *af = NULL;
+ status = cf_util_get_string(child, &af);
+ if (status != 0 || af == NULL) {
+ WARNING("curl_json plugin: Cannot parse value of `%s' for URL `%s'.",
+ child->key, db->url);
+ } else if (strcasecmp("any", af) == 0) {
+ db->address_family = CURL_IPRESOLVE_WHATEVER;
+ } else if (strcasecmp("ipv4", af) == 0) {
+ db->address_family = CURL_IPRESOLVE_V4;
+ } else if (strcasecmp("ipv6", af) == 0) {
+ /* If curl supports ipv6, use it. If not, log a warning and
+ * fall back to default - don't set status to non-zero.
+ */
+ curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
+ if (curl_info->features & CURL_VERSION_IPV6)
+ db->address_family = CURL_IPRESOLVE_V6;
+ else
+ WARNING("curl_json plugin: IPv6 not supported by this libCURL. "
+ "Using fallback `any'.");
+ } else {
+ WARNING("curl_json plugin: Unsupported value of `%s' for URL `%s'.",
+ child->key, db->url);
+ status = -1;
+ }
} else {
WARNING("curl_json plugin: Option `%s' not allowed here.", child->key);
status = -1;
plugin_register_complex_read(/* group = */ NULL, cb_name, cj_read, interval,
&(user_data_t){
- .data = db, .free_func = cj_free,
+ .data = db,
+ .free_func = cj_free,
});
sfree(cb_name);
} else {
char *host;
char *url;
+ int address_family;
char *user;
char *pass;
char *credentials;
return EINVAL;
}
- cx_namespace_t *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;
curl_easy_setopt(db->curl, CURLOPT_ERRORBUFFER, db->curl_errbuf);
curl_easy_setopt(db->curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(db->curl, CURLOPT_MAXREDIRS, 50L);
+ curl_easy_setopt(db->curl, CURLOPT_IPRESOLVE, db->address_family);
if (db->user != NULL) {
#ifdef HAVE_CURLOPT_USERNAME
}
db->timeout = -1;
+ db->address_family = CURL_IPRESOLVE_WHATEVER;
int status = cf_util_get_string(ci, &db->url);
if (status != 0) {
db->stats = curl_stats_from_config(child);
if (db->stats == NULL)
status = -1;
+ } else if (strcasecmp("AddressFamily", child->key) == 0) {
+ char *af = NULL;
+ status = cf_util_get_string(child, &af);
+ if (status != 0 || af == NULL) {
+ WARNING("curl_xml plugin: Cannot parse value of `%s' for URL `%s'.",
+ child->key, db->url);
+ } else if (strcasecmp("any", af) == 0) {
+ db->address_family = CURL_IPRESOLVE_WHATEVER;
+ } else if (strcasecmp("ipv4", af) == 0) {
+ db->address_family = CURL_IPRESOLVE_V4;
+ } else if (strcasecmp("ipv6", af) == 0) {
+ /* If curl supports ipv6, use it. If not, log a warning and
+ * fall back to default - don't set status to non-zero.
+ */
+ curl_version_info_data *curl_info = curl_version_info(CURLVERSION_NOW);
+ if (curl_info->features & CURL_VERSION_IPV6)
+ db->address_family = CURL_IPRESOLVE_V6;
+ else
+ WARNING("curl_xml plugin: IPv6 not supported by this libCURL. "
+ "Using fallback `any'.");
+ } else {
+ WARNING("curl_xml plugin: Unsupported value of `%s' for URL `%s'.",
+ child->key, db->url);
+ status = -1;
+ }
} else {
WARNING("curl_xml plugin: Option `%s' not allowed here.", child->key);
status = -1;
plugin_register_complex_read(/* group = */ "curl_xml", cb_name, cx_read,
/* interval = */ interval,
&(user_data_t){
- .data = db, .free_func = cx_free,
+ .data = db,
+ .free_func = cx_free,
});
sfree(cb_name);
return 0;
#ifdef KERNEL_LINUX
&& notify_upstart() == 0 && notify_systemd() == 0
#endif
- ) {
+ ) {
pid_t pid;
if ((pid = fork()) == -1) {
/* error */
static void read_cmdline(int argc, char **argv, struct cmdline_config *config) {
/* read options */
while (1) {
- int c = getopt(argc, argv, "BhtTC:"
+ int c = getopt(argc, argv,
+ "BhtTC:"
#if COLLECT_DAEMON
- "fP:"
+ "fP:"
#endif
- );
+ );
if (c == -1)
break;
* Also, this will automatically load modules.
*/
if (cf_read(config->configfile)) {
- fprintf(stderr, "Error: Reading the config file failed!\n"
- "Read the logs for details.\n");
+ fprintf(stderr, "Error: Parsing the config file failed!\n");
return 1;
}
struct cmdline_config init_config(int argc, char **argv) {
struct cmdline_config config = {
- .daemonize = true, .create_basedir = true, .configfile = CONFIGFILE,
+ .daemonize = true,
+ .create_basedir = true,
+ .configfile = CONFIGFILE,
};
read_cmdline(argc, argv, &config);
return cf_cb;
}
-static int cf_dispatch(const char *type, const char *orig_key,
- const char *orig_value) {
- cf_callback_t *cf_cb;
- plugin_ctx_t old_ctx;
- char *key;
- char *value;
- int ret;
- int i = 0;
+static int cf_dispatch_option(const cf_callback_t *cf_cb, oconfig_item_t *ci) {
+ const char *plugin = cf_cb->type;
+ const char *orig_key = ci->key;
if (orig_key == NULL)
return EINVAL;
- DEBUG("type = %s, key = %s, value = %s", ESCAPE_NULL(type), orig_key,
- ESCAPE_NULL(orig_value));
+ /* (Re)construct string value for option */
+ char buffer[4096];
+ int buffer_free = sizeof(buffer);
+ char *buffer_ptr = buffer;
- if ((cf_cb = cf_search(type)) == NULL) {
- WARNING("Found a configuration for the `%s' plugin, but "
- "the plugin isn't loaded or didn't register "
- "a configuration callback.",
- type);
- return -1;
+ for (int i = 0; i < ci->values_num; i++) {
+ int status = -1;
+
+ if (ci->values[i].type == OCONFIG_TYPE_STRING)
+ status =
+ ssnprintf(buffer_ptr, buffer_free, " %s", ci->values[i].value.string);
+ else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
+ status = ssnprintf(buffer_ptr, buffer_free, " %lf",
+ ci->values[i].value.number);
+ else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
+ status = ssnprintf(buffer_ptr, buffer_free, " %s",
+ ci->values[i].value.boolean ? "true" : "false");
+
+ if ((status < 0) || (status >= buffer_free))
+ return -1;
+ buffer_free -= status;
+ buffer_ptr += status;
}
- if ((key = strdup(orig_key)) == NULL)
+ /* skip the initial space */
+ const char *orig_value = buffer + 1;
+
+ DEBUG("plugin = %s, key = %s, value = %s", ESCAPE_NULL(plugin), orig_key,
+ ESCAPE_NULL(orig_value));
+
+ char *key = strdup(orig_key);
+ if (key == NULL)
return 1;
- if ((value = strdup(orig_value)) == NULL) {
+
+ char *value = strdup(orig_value);
+ if (value == NULL) {
free(key);
return 2;
}
- ret = -1;
+ int ret = -1;
- old_ctx = plugin_set_ctx(cf_cb->ctx);
+ plugin_ctx_t old_ctx = plugin_set_ctx(cf_cb->ctx);
+ int i;
for (i = 0; i < cf_cb->keys_num; i++) {
if ((cf_cb->keys[i] != NULL) && (strcasecmp(cf_cb->keys[i], key) == 0)) {
ret = (*cf_cb->callback)(key, value);
plugin_set_ctx(old_ctx);
if (i >= cf_cb->keys_num)
- WARNING("Plugin `%s' did not register for value `%s'.", type, key);
+ WARNING("Plugin `%s' did not register for value `%s'.", plugin, key);
free(key);
free(value);
return ret;
-} /* int cf_dispatch */
+} /* int cf_dispatch_option */
static int dispatch_global_option(const oconfig_item_t *ci) {
if (ci->values_num != 1) {
return global_option_set(ci->key, ci->values[0].value.string, 0);
else if (ci->values[0].type == OCONFIG_TYPE_NUMBER) {
char tmp[128];
- snprintf(tmp, sizeof(tmp), "%lf", ci->values[0].value.number);
+ ssnprintf(tmp, sizeof(tmp), "%lf", ci->values[0].value.number);
return global_option_set(ci->key, tmp, 0);
} else if (ci->values[0].type == OCONFIG_TYPE_BOOLEAN) {
if (ci->values[0].value.boolean)
/* default to the global interval set before loading this plugin */
plugin_ctx_t ctx = {
- .interval = cf_get_default_interval(), .name = strdup(name),
+ .interval = cf_get_default_interval(),
+ .name = strdup(name),
};
if (ctx.name == NULL)
return ENOMEM;
return ret_val;
} /* int dispatch_value_loadplugin */
-static int dispatch_value_plugin(const char *plugin, oconfig_item_t *ci) {
- char buffer[4096];
- char *buffer_ptr;
- int buffer_free;
-
- buffer_ptr = buffer;
- buffer_free = sizeof(buffer);
-
- for (int i = 0; i < ci->values_num; i++) {
- int status = -1;
-
- if (ci->values[i].type == OCONFIG_TYPE_STRING)
- status =
- snprintf(buffer_ptr, buffer_free, " %s", ci->values[i].value.string);
- else if (ci->values[i].type == OCONFIG_TYPE_NUMBER)
- status =
- snprintf(buffer_ptr, buffer_free, " %lf", ci->values[i].value.number);
- else if (ci->values[i].type == OCONFIG_TYPE_BOOLEAN)
- status = snprintf(buffer_ptr, buffer_free, " %s",
- ci->values[i].value.boolean ? "true" : "false");
-
- if ((status < 0) || (status >= buffer_free))
- return -1;
- buffer_free -= status;
- buffer_ptr += status;
- }
- /* skip the initial space */
- buffer_ptr = buffer + 1;
-
- return cf_dispatch(plugin, ci->key, buffer_ptr);
-} /* int dispatch_value_plugin */
-
static int dispatch_value(oconfig_item_t *ci) {
int ret = 0;
return -1;
}
- const char *name = ci->values[0].value.string;
- if (strcmp("libvirt", name) == 0) {
+ const char *plugin_name = ci->values[0].value.string;
+ if (strcmp("libvirt", plugin_name) == 0) {
/* TODO(octo): Remove this legacy. */
WARNING("The \"libvirt\" plugin has been renamed to \"virt\" to avoid "
"problems with the build system. "
"Your configuration is still using the old name. "
"Please change it to use \"virt\" as soon as possible. "
"This compatibility code will go away eventually.");
- name = "virt";
+ plugin_name = "virt";
}
- if (IS_TRUE(global_option_get("AutoLoadPlugin"))) {
+ bool plugin_loaded = plugin_is_loaded(plugin_name);
+
+ if (!plugin_loaded && IS_TRUE(global_option_get("AutoLoadPlugin"))) {
plugin_ctx_t ctx = {0};
- plugin_ctx_t old_ctx;
- int status;
/* default to the global interval set before loading this plugin */
ctx.interval = cf_get_default_interval();
- ctx.name = strdup(name);
+ ctx.name = strdup(plugin_name);
- old_ctx = plugin_set_ctx(ctx);
- status = plugin_load(name, /* flags = */ false);
+ plugin_ctx_t old_ctx = plugin_set_ctx(ctx);
+ int status = plugin_load(plugin_name, /* flags = */ false);
/* reset to the "global" context */
plugin_set_ctx(old_ctx);
if (status != 0) {
- ERROR("Automatically loading plugin \"%s\" failed "
+ ERROR("Automatically loading plugin `%s' failed "
"with status %i.",
- name, status);
+ plugin_name, status);
return status;
}
+ plugin_loaded = true;
+ }
+
+ if (!plugin_loaded) {
+ WARNING("There is configuration for the `%s' plugin, but the plugin isn't "
+ "loaded. Please check your configuration.",
+ plugin_name);
+
+ /* Try to be backward-compatible with previous versions */
+ return 0;
}
/* Check for a complex callback first */
for (cf_complex_callback_t *cb = complex_callback_head; cb != NULL;
cb = cb->next) {
- if (strcasecmp(name, cb->type) == 0) {
- plugin_ctx_t old_ctx;
- int ret_val;
-
- old_ctx = plugin_set_ctx(cb->ctx);
- ret_val = (cb->callback(ci));
+ if (strcasecmp(plugin_name, cb->type) == 0) {
+ plugin_ctx_t old_ctx = plugin_set_ctx(cb->ctx);
+ int ret_val = (cb->callback(ci));
plugin_set_ctx(old_ctx);
return ret_val;
}
}
+ /* Try to be backward-compatible with previous versions */
+ if (ci->children_num == 0)
+ return 0;
+
/* Hm, no complex plugin found. Dispatch the values one by one */
+ cf_callback_t *cf_cb = cf_search(plugin_name);
+ if (cf_cb == NULL) {
+ WARNING("Found a configuration for the `%s' plugin, but "
+ "the plugin didn't register a configuration callback.",
+ plugin_name);
+ return -1;
+ }
+
for (int i = 0; i < ci->children_num; i++) {
- if (ci->children[i].children == NULL)
- dispatch_value_plugin(name, ci->children + i);
- else {
+ if (ci->children[i].children == NULL) {
+ oconfig_item_t *child = ci->children + i;
+ int ret = cf_dispatch_option(cf_cb, child);
+ if (ret != 0) {
+ ERROR("Plugin `%s' failed to handle option `%s', return code: %i",
+ plugin_name, child->key, ret);
+ return ret;
+ }
+ } else {
WARNING("There is a `%s' block within the "
- "configuration for the %s plugin. "
- "The plugin either only expects "
- "\"simple\" configuration statements "
- "or wasn't loaded using `LoadPlugin'."
- " Please check your configuration.",
- ci->children[i].key, name);
+ "configuration for the `%s' plugin. "
+ "The plugin only expects \"simple\" configuration options. "
+ "Blocks are not supported. Please check your configuration.",
+ ci->children[i].key, plugin_name);
}
}
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;
if ((de->d_name[0] == '.') || (de->d_name[0] == 0))
continue;
- status = snprintf(name, sizeof(name), "%s/%s", dir, de->d_name);
+ status = ssnprintf(name, sizeof(name), "%s/%s", dir, de->d_name);
if ((status < 0) || ((size_t)status >= sizeof(name))) {
ERROR("configfile: Not including `%s/%s' because its"
" name is too long.",
return root;
} /* oconfig_item_t *cf_read_generic */
-/* #endif HAVE_WORDEXP_H */
+ /* #endif HAVE_WORDEXP_H */
#else /* if !HAVE_WORDEXP_H */
static oconfig_item_t *cf_read_generic(const char *path, const char *pattern,
P_ERROR("cf_util_get_service: Out of memory.");
return -1;
}
- snprintf(service, 6, "%i", port);
+ ssnprintf(service, 6, "%i", port);
sfree(*ret_string);
*ret_string = service;
* DEALINGS IN THE SOFTWARE.
**/
-#include "globals.h"
+// clang-format off
+/*
+ * Explicit order is required or _FILE_OFFSET_BITS will have definition mismatches on Solaris
+ * See Github Issue #3193 for details
+ */
#include "utils/common/common.h"
+#include "globals.h"
+// clang-format on
#if HAVE_KSTAT_H
#include <kstat.h>
};
typedef struct read_func_s read_func_t;
+struct cache_event_func_s {
+ plugin_cache_event_cb callback;
+ char *name;
+ user_data_t user_data;
+ plugin_ctx_t plugin_ctx;
+};
+typedef struct cache_event_func_s cache_event_func_t;
+
struct write_queue_s;
typedef struct write_queue_s write_queue_t;
struct write_queue_s {
static llist_t *list_log;
static llist_t *list_notification;
+static size_t list_cache_event_num;
+static cache_event_func_t list_cache_event[32];
+
static fc_chain_t *pre_cache_chain;
static fc_chain_t *post_cache_chain;
static int register_callback(llist_t **list, /* {{{ */
const char *name, callback_func_t *cf) {
- llentry_t *le;
- char *key;
if (*list == NULL) {
*list = llist_create();
}
}
- key = strdup(name);
+ char *key = strdup(name);
if (key == NULL) {
ERROR("plugin: register_callback: strdup failed.");
destroy_callback(cf);
return -1;
}
- le = llist_search(*list, name);
+ llentry_t *le = llist_search(*list, name);
if (le == NULL) {
le = llentry_create(key, cf);
if (le == NULL) {
llist_append(*list, le);
} else {
- callback_func_t *old_cf;
-
- old_cf = le->value;
+ callback_func_t *old_cf = le->value;
le->value = cf;
P_WARNING("register_callback: "
cf->cf_callback = callback;
if (ud == NULL) {
cf->cf_udata = (user_data_t){
- .data = NULL, .free_func = NULL,
+ .data = NULL,
+ .free_func = NULL,
};
} else {
cf->cf_udata = *ud;
}
char name[THREAD_NAME_MAX];
- snprintf(name, sizeof(name), "reader#%" PRIu64, (uint64_t)read_threads_num);
+ ssnprintf(name, sizeof(name), "reader#%" PRIu64,
+ (uint64_t)read_threads_num);
set_thread_name(read_threads[read_threads_num], name);
read_threads_num++;
}
char name[THREAD_NAME_MAX];
- snprintf(name, sizeof(name), "writer#%" PRIu64,
- (uint64_t)write_threads_num);
+ ssnprintf(name, sizeof(name), "writer#%" PRIu64,
+ (uint64_t)write_threads_num);
set_thread_name(write_threads[write_threads_num], name);
write_threads_num++;
ERROR("plugin_set_dir: strdup(\"%s\") failed", dir);
}
-static bool plugin_is_loaded(char const *name) {
- int status;
-
+bool plugin_is_loaded(char const *name) {
if (plugins_loaded == NULL)
plugins_loaded =
c_avl_create((int (*)(const void *, const void *))strcasecmp);
assert(plugins_loaded != NULL);
- status = c_avl_get(plugins_loaded, name, /* ret_value = */ NULL);
+ int status = c_avl_get(plugins_loaded, name, /* ret_value = */ NULL);
return status == 0;
}
/* name = */ flush_name,
/* callback = */ plugin_flush_timeout_callback,
/* interval = */ ctx.flush_interval,
- /* user data = */ &(user_data_t){
- .data = cb, .free_func = plugin_flush_timeout_callback_free,
+ /* user data = */
+ &(user_data_t){
+ .data = cb,
+ .free_func = plugin_flush_timeout_callback_free,
});
sfree(flush_name);
return create_register_callback(&list_missing, name, (void *)callback, ud);
} /* int plugin_register_missing */
+EXPORT int plugin_register_cache_event(const char *name,
+ plugin_cache_event_cb callback,
+ user_data_t const *ud) {
+
+ if (name == NULL || callback == NULL)
+ return EINVAL;
+
+ char *name_copy = strdup(name);
+ if (name_copy == NULL) {
+ P_ERROR("plugin_register_cache_event: strdup failed.");
+ free_userdata(ud);
+ return ENOMEM;
+ }
+
+ if (list_cache_event_num >= 32) {
+ P_ERROR("plugin_register_cache_event: Too much cache event callbacks tried "
+ "to be registered.");
+ free_userdata(ud);
+ return ENOMEM;
+ }
+
+ for (size_t i = 0; i < list_cache_event_num; i++) {
+ cache_event_func_t *cef = &list_cache_event[i];
+ if (!cef->callback)
+ continue;
+
+ if (strcmp(name, cef->name) == 0) {
+ P_ERROR("plugin_register_cache_event: a callback named `%s' already "
+ "registered!",
+ name);
+ free_userdata(ud);
+ return -1;
+ }
+ }
+
+ user_data_t user_data;
+ if (ud == NULL) {
+ user_data = (user_data_t){
+ .data = NULL, .free_func = NULL,
+ };
+ } else {
+ user_data = *ud;
+ }
+
+ list_cache_event[list_cache_event_num] =
+ (cache_event_func_t){.callback = callback,
+ .name = name_copy,
+ .user_data = user_data,
+ .plugin_ctx = plugin_get_ctx()};
+ list_cache_event_num++;
+
+ return 0;
+} /* int plugin_register_cache_event */
+
EXPORT int plugin_register_shutdown(const char *name, int (*callback)(void)) {
return create_register_callback(&list_shutdown, name, (void *)callback, NULL);
} /* int plugin_register_shutdown */
return plugin_unregister(list_missing, name);
}
+EXPORT int plugin_unregister_cache_event(const char *name) {
+ for (size_t i = 0; i < list_cache_event_num; i++) {
+ cache_event_func_t *cef = &list_cache_event[i];
+ if (!cef->callback)
+ continue;
+ if (strcmp(name, cef->name) == 0) {
+ /* Mark callback as inactive, so mask in cache entries remains actual */
+ cef->callback = NULL;
+ sfree(cef->name);
+ free_userdata(&cef->user_data);
+ }
+ }
+ return 0;
+}
+
+static void destroy_cache_event_callbacks() {
+ for (size_t i = 0; i < list_cache_event_num; i++) {
+ cache_event_func_t *cef = &list_cache_event[i];
+ if (!cef->callback)
+ continue;
+ cef->callback = NULL;
+ sfree(cef->name);
+ free_userdata(&cef->user_data);
+ }
+}
+
EXPORT int plugin_unregister_shutdown(const char *name) {
return plugin_unregister(list_shutdown, name);
}
* the data isn't freed twice. */
destroy_all_callbacks(&list_flush);
destroy_all_callbacks(&list_missing);
+ destroy_cache_event_callbacks();
destroy_all_callbacks(&list_write);
destroy_all_callbacks(&list_notification);
return 0;
} /* int }}} plugin_dispatch_missing */
+void plugin_dispatch_cache_event(enum cache_event_type_e event_type,
+ unsigned long callbacks_mask, const char *name,
+ const value_list_t *vl) {
+ switch (event_type) {
+ case CE_VALUE_NEW:
+ callbacks_mask = 0;
+ for (size_t i = 0; i < list_cache_event_num; i++) {
+ cache_event_func_t *cef = &list_cache_event[i];
+ plugin_cache_event_cb callback = cef->callback;
+
+ if (!callback)
+ continue;
+
+ cache_event_t event = (cache_event_t){.type = event_type,
+ .value_list = vl,
+ .value_list_name = name,
+ .ret = 0};
+
+ plugin_ctx_t old_ctx = plugin_set_ctx(cef->plugin_ctx);
+ int status = (*callback)(&event, &cef->user_data);
+ plugin_set_ctx(old_ctx);
+
+ if (status != 0) {
+ ERROR("plugin_dispatch_cache_event: Callback \"%s\" failed with status "
+ "%i for event NEW.",
+ cef->name, status);
+ } else {
+ if (event.ret) {
+ DEBUG(
+ "plugin_dispatch_cache_event: Callback \"%s\" subscribed to %s.",
+ cef->name, name);
+ callbacks_mask |= (1 << (i));
+ } else {
+ DEBUG("plugin_dispatch_cache_event: Callback \"%s\" ignores %s.",
+ cef->name, name);
+ }
+ }
+ }
+
+ if (callbacks_mask)
+ uc_set_callbacks_mask(name, callbacks_mask);
+
+ break;
+ case CE_VALUE_UPDATE:
+ case CE_VALUE_EXPIRED:
+ for (size_t i = 0; i < list_cache_event_num; i++) {
+ cache_event_func_t *cef = &list_cache_event[i];
+ plugin_cache_event_cb callback = cef->callback;
+
+ if (!callback)
+ continue;
+
+ if (callbacks_mask && (1 << (i)) == 0)
+ continue;
+
+ cache_event_t event = (cache_event_t){.type = event_type,
+ .value_list = vl,
+ .value_list_name = name,
+ .ret = 0};
+
+ plugin_ctx_t old_ctx = plugin_set_ctx(cef->plugin_ctx);
+ int status = (*callback)(&event, &cef->user_data);
+ plugin_set_ctx(old_ctx);
+
+ if (status != 0) {
+ ERROR("plugin_dispatch_cache_event: Callback \"%s\" failed with status "
+ "%i for event %s.",
+ cef->name, status,
+ ((event_type == CE_VALUE_UPDATE) ? "UPDATE" : "EXPIRED"));
+ }
+ }
+ break;
+ }
+ return;
+}
+
static int plugin_dispatch_values_internal(value_list_t *vl) {
int status;
static c_complain_t no_write_complaint = C_COMPLAIN_INIT_STATIC;
};
typedef struct user_data_s user_data_t;
+enum cache_event_type_e { CE_VALUE_NEW, CE_VALUE_UPDATE, CE_VALUE_EXPIRED };
+
+typedef struct cache_event_s {
+ enum cache_event_type_e type;
+ const value_list_t *value_list;
+ const char *value_list_name;
+ int ret;
+} cache_event_t;
+
struct plugin_ctx_s {
char *name;
cdtime_t interval;
* callbacks should be called, greater than zero if no more callbacks should be
* called. */
typedef int (*plugin_missing_cb)(const value_list_t *, user_data_t *);
+/* "cache event" callback. CE_VALUE_NEW events are sent to all registered
+ * callbacks. Callback should check if it interested in further CE_VALUE_UPDATE
+ * and CE_VALUE_EXPIRED events for metric and set event->ret = 1 if so.
+ */
+typedef int (*plugin_cache_event_cb)(cache_event_t *, user_data_t *);
typedef void (*plugin_log_cb)(int severity, const char *message, user_data_t *);
typedef int (*plugin_shutdown_cb)(void);
typedef int (*plugin_notification_cb)(const notification_t *, user_data_t *);
* this case.
*/
int plugin_load(const char *name, bool global);
+bool plugin_is_loaded(char const *name);
int plugin_init_all(void);
void plugin_read_all(void);
user_data_t const *user_data);
int plugin_register_missing(const char *name, plugin_missing_cb callback,
user_data_t const *user_data);
+int plugin_register_cache_event(const char *name,
+ plugin_cache_event_cb callback,
+ user_data_t const *ud);
int plugin_register_shutdown(const char *name, plugin_shutdown_cb callback);
int plugin_register_data_set(const data_set_t *ds);
int plugin_register_log(const char *name, plugin_log_cb callback,
int plugin_unregister_write(const char *name);
int plugin_unregister_flush(const char *name);
int plugin_unregister_missing(const char *name);
+int plugin_unregister_cache_event(const char *name);
int plugin_unregister_shutdown(const char *name);
int plugin_unregister_data_set(const char *name);
int plugin_unregister_log(const char *name);
int store_type, ...);
int plugin_dispatch_missing(const value_list_t *vl);
+void plugin_dispatch_cache_event(enum cache_event_type_e event_type,
+ unsigned long callbacks_mask, const char *name,
+ const value_list_t *vl);
int plugin_dispatch_notification(const notification_t *notif);
int plugin_load(const char *name, bool global) { return ENOTSUP; }
+bool plugin_is_loaded(const char *name) { return false; }
+
int plugin_register_config(const char *name,
int (*callback)(const char *key, const char *val),
const char **keys, int keys_num) {
return ENOTSUP;
}
+int plugin_register_flush(__attribute__((unused)) const char *name,
+ __attribute__((unused)) plugin_flush_cb callback,
+ __attribute__((unused))
+ user_data_t const *user_data) {
+ return ENOTSUP;
+}
+
int plugin_register_missing(const char *name, plugin_missing_cb callback,
user_data_t const *ud) {
return ENOTSUP;
int plugin_register_data_set(const data_set_t *ds) { return ENOTSUP; }
+int plugin_register_notification(__attribute__((unused)) const char *name,
+ __attribute__((unused))
+ plugin_notification_cb callback,
+ __attribute__((unused))
+ user_data_t const *user_data) {
+ return ENOTSUP;
+}
+
+#define DECLARE_UNREGISTER(t) \
+ int plugin_unregister_##t(__attribute__((unused)) char const *name) { \
+ return ENOTSUP; \
+ }
+DECLARE_UNREGISTER(config)
+DECLARE_UNREGISTER(complex_config)
+DECLARE_UNREGISTER(init)
+DECLARE_UNREGISTER(read)
+DECLARE_UNREGISTER(read_group)
+DECLARE_UNREGISTER(write)
+DECLARE_UNREGISTER(flush)
+DECLARE_UNREGISTER(missing)
+DECLARE_UNREGISTER(shutdown)
+DECLARE_UNREGISTER(data_set)
+DECLARE_UNREGISTER(log)
+DECLARE_UNREGISTER(notification)
+
int plugin_dispatch_values(value_list_t const *vl) { return ENOTSUP; }
int plugin_dispatch_notification(__attribute__((unused))
cdtime_t plugin_get_interval(void) { return mock_context.interval; }
+int plugin_thread_create(__attribute__((unused)) pthread_t *thread,
+ __attribute__((unused)) const pthread_attr_t *attr,
+ __attribute__((unused)) void *(*start_routine)(void *),
+ __attribute__((unused)) void *arg,
+ __attribute__((unused)) char const *name) {
+ return ENOTSUP;
+}
+
/* TODO(octo): this function is actually from filter_chain.h, but in order not
* to tumble down that rabbit hole, we're declaring it here. A better solution
* would be to hard-code the top-level config keys in daemon/collectd.c to avoid
static void parse_line(char *buf) {
char *fields[64];
size_t fields_num;
- data_set_t *ds;
-
fields_num = strsplit(buf, fields, 64);
if (fields_num < 2)
return;
if (fields[0][0] == '#')
return;
- ds = calloc(1, sizeof(*ds));
- if (ds == NULL)
- return;
+ data_set_t ds = {{0}};
- sstrncpy(ds->type, fields[0], sizeof(ds->type));
+ sstrncpy(ds.type, fields[0], sizeof(ds.type));
- ds->ds_num = fields_num - 1;
- ds->ds = calloc(ds->ds_num, sizeof(*ds->ds));
- if (ds->ds == NULL) {
- sfree(ds);
+ ds.ds_num = fields_num - 1;
+ ds.ds = calloc(ds.ds_num, sizeof(*ds.ds));
+ if (ds.ds == NULL)
return;
- }
- for (size_t i = 0; i < ds->ds_num; i++)
- if (parse_ds(ds->ds + i, fields[i + 1], strlen(fields[i + 1])) != 0) {
+ 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 #%" PRIsz
" of data set %s",
- i, ds->type);
- sfree(ds->ds);
- sfree(ds);
+ i, ds.type);
+ sfree(ds.ds);
return;
}
- plugin_register_data_set(ds);
+ plugin_register_data_set(&ds);
- sfree(ds->ds);
- sfree(ds);
+ sfree(ds.ds);
} /* void parse_line */
static void parse_file(FILE *fh) {
size_t history_length;
meta_data_t *meta;
+ unsigned long callbacks_mask;
} cache_entry_t;
struct uc_iter_s {
static int uc_insert(const data_set_t *ds, const value_list_t *vl,
const char *key) {
- char *key_copy;
- cache_entry_t *ce;
-
/* `cache_lock' has been locked by `uc_update' */
- key_copy = strdup(key);
+ char *key_copy = strdup(key);
if (key_copy == NULL) {
ERROR("uc_insert: strdup failed.");
return -1;
}
- ce = cache_alloc(ds->ds_num);
+ cache_entry_t *ce = cache_alloc(ds->ds_num);
if (ce == NULL) {
sfree(key_copy);
ERROR("uc_insert: cache_alloc (%" PRIsz ") failed.", ds->ds_num);
ce->interval = vl->interval;
ce->state = STATE_UNKNOWN;
+ if (vl->meta != NULL) {
+ ce->meta = meta_data_clone(vl->meta);
+ }
+
if (c_avl_insert(cache_tree, key_copy, ce) != 0) {
sfree(key_copy);
ERROR("uc_insert: c_avl_insert failed.");
char *key;
cdtime_t time;
cdtime_t interval;
+ unsigned long callbacks_mask;
} *expired = NULL;
size_t expired_num = 0;
expired[expired_num].key = strdup(key);
expired[expired_num].time = ce->last_time;
expired[expired_num].interval = ce->interval;
+ expired[expired_num].callbacks_mask = ce->callbacks_mask;
if (expired[expired_num].key == NULL) {
ERROR("uc_check_timeout: strdup failed.");
* plugin calls the cache interface. */
for (size_t i = 0; i < expired_num; i++) {
value_list_t vl = {
- .time = expired[i].time, .interval = expired[i].interval,
+ .time = expired[i].time,
+ .interval = expired[i].interval,
};
if (parse_identifier_vl(expired[i].key, &vl) != 0) {
}
plugin_dispatch_missing(&vl);
+
+ if (expired[i].callbacks_mask)
+ plugin_dispatch_cache_event(CE_VALUE_EXPIRED, expired[i].callbacks_mask,
+ expired[i].key, &vl);
} /* for (i = 0; i < expired_num; i++) */
/* Now actually remove all the values from the cache. We don't re-evaluate
int uc_update(const data_set_t *ds, const value_list_t *vl) {
char name[6 * DATA_MAX_NAME_LEN];
- cache_entry_t *ce = NULL;
- int status;
if (FORMAT_VL(name, sizeof(name), vl) != 0) {
ERROR("uc_update: FORMAT_VL failed.");
pthread_mutex_lock(&cache_lock);
- status = c_avl_get(cache_tree, name, (void *)&ce);
+ cache_entry_t *ce = NULL;
+ int status = c_avl_get(cache_tree, name, (void *)&ce);
if (status != 0) /* entry does not yet exist */
{
status = uc_insert(ds, vl, name);
pthread_mutex_unlock(&cache_lock);
+
+ if (status == 0)
+ plugin_dispatch_cache_event(CE_VALUE_NEW, 0 /* mask */, name, vl);
+
return status;
}
ce->last_update = cdtime();
ce->interval = vl->interval;
+ /* Check if cache entry has registered callbacks */
+ unsigned long callbacks_mask = ce->callbacks_mask;
+
pthread_mutex_unlock(&cache_lock);
+ if (callbacks_mask)
+ plugin_dispatch_cache_event(CE_VALUE_UPDATE, callbacks_mask, name, vl);
+
return 0;
} /* int uc_update */
+int uc_set_callbacks_mask(const char *name, unsigned long mask) {
+ pthread_mutex_lock(&cache_lock);
+ cache_entry_t *ce = NULL;
+ int status = c_avl_get(cache_tree, name, (void *)&ce);
+ if (status != 0) { /* Ouch, just created entry disappeared ?! */
+ ERROR("uc_set_callbacks_mask: Couldn't find %s entry!", name);
+ pthread_mutex_unlock(&cache_lock);
+ return -1;
+ }
+ DEBUG("uc_set_callbacks_mask: set mask for \"%s\" to %lu.", name, mask);
+ ce->callbacks_mask = mask;
+ pthread_mutex_unlock(&cache_lock);
+ return 0;
+}
+
int uc_get_rate_by_name(const char *name, gauge_t **ret_values,
size_t *ret_values_num) {
gauge_t *ret = NULL;
if ((iter == NULL) || (iter->entry == NULL) || (ret_values == NULL) ||
(ret_num == NULL))
return -1;
-
*ret_values =
calloc(iter->entry->values_num, sizeof(*iter->entry->values_raw));
if (*ret_values == NULL)
return -1;
for (size_t i = 0; i < iter->entry->values_num; ++i)
- *ret_values[i] = iter->entry->values_raw[i];
+ (*ret_values)[i] = iter->entry->values_raw[i];
*ret_num = iter->entry->values_num;
pthread_mutex_unlock(&cache_lock); \
return status; \
}
-int uc_meta_data_exists(const value_list_t *vl,
- const char *key) UC_WRAP(meta_data_exists)
+int uc_meta_data_exists(const value_list_t *vl, const char *key)
+ UC_WRAP(meta_data_exists)
+
+ int uc_meta_data_delete(const value_list_t *vl, const char *key)
+ UC_WRAP(meta_data_delete)
+
+ /* The second argument is called `toc` in the API, but the macro expects
+ * `key`. */
+ int uc_meta_data_toc(const value_list_t *vl,
+ char ***key) UC_WRAP(meta_data_toc)
- int uc_meta_data_delete(const value_list_t *vl,
- const char *key) UC_WRAP(meta_data_delete)
#undef UC_WRAP
/* We need a new version of this macro because the following functions take
int uc_set_hits(const data_set_t *ds, const value_list_t *vl, int hits);
int uc_inc_hits(const data_set_t *ds, const value_list_t *vl, int step);
+int uc_set_callbacks_mask(const char *name, unsigned long callbacks_mask);
+
int uc_get_history(const data_set_t *ds, const value_list_t *vl,
gauge_t *ret_history, size_t num_steps, size_t num_ds);
int uc_get_history_by_name(const char *name, gauge_t *ret_history,
*/
int uc_meta_data_exists(const value_list_t *vl, const char *key);
int uc_meta_data_delete(const value_list_t *vl, const char *key);
+/* Same API as meta_data_toc. */
+int uc_meta_data_toc(const value_list_t *vl, char ***toc);
int uc_meta_data_add_string(const value_list_t *vl, const char *key,
const char *value);
* Florian Forster <octo at collectd.org>
**/
+#ifndef UTILS_RANDOM_H
+#define UTILS_RANDOM_H 1
+
/**
* Returns a random double value in the range [0..1), i.e. excluding 1.
*
* outside the intended range. This function is thread- and reentrant-safe.
*/
long cdrand_range(long min, long max);
+
+#endif /* !UTILS_RANDOM_H */
#include <libgeom.h>
#endif
-#if HAVE_LIMITS_H
-#include <limits.h>
-#endif
#ifndef UINT_MAX
#define UINT_MAX 4294967295U
#endif
io_master_port = MACH_PORT_NULL;
return -1;
}
-/* #endif HAVE_IOKIT_IOKITLIB_H */
+ /* #endif HAVE_IOKIT_IOKITLIB_H */
#elif KERNEL_LINUX
#if HAVE_LIBUDEV_H
}
}
#endif /* HAVE_LIBUDEV_H */
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif KERNEL_FREEBSD
int rv;
ERROR("geom_stats_open() failed, returned %d", rv);
return -1;
}
-/* #endif KERNEL_FREEBSD */
+ /* #endif KERNEL_FREEBSD */
#elif HAVE_LIBKSTAT
kstat_t *ksp_chain;
derive_t read, derive_t write) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = read}, {.derive = write},
+ {.derive = read},
+ {.derive = write},
};
vl.values = values;
derive_t weighted_time) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = io_time}, {.derive = weighted_time},
+ {.derive = io_time},
+ {.derive = weighted_time},
};
vl.values = values;
sstrncpy(disk_name, props_disk_name_bsd, sizeof(disk_name));
else {
ERROR("disk plugin: can't find bsd disk name.");
- snprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major, disk_minor);
+ ssnprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major,
+ disk_minor);
}
} else
- snprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major, disk_minor);
+ ssnprintf(disk_name, sizeof(disk_name), "%i-%i", disk_major, disk_minor);
DEBUG("disk plugin: disk_name = \"%s\"", disk_name);
disk_submit(disk_name, "disk_time", read_tme / 1000, write_tme / 1000);
}
IOObjectRelease(disk_list);
-/* #endif HAVE_IOKIT_IOKITLIB_H */
+ /* #endif HAVE_IOKIT_IOKITLIB_H */
#elif KERNEL_FREEBSD
int retry, dirty;
free(missing_ds);
}
fclose(fh);
-/* #endif defined(KERNEL_LINUX) */
+ /* #endif defined(KERNEL_LINUX) */
#elif HAVE_LIBKSTAT
#if HAVE_KSTAT_IO_T_WRITES && HAVE_KSTAT_IO_T_NWRITES && HAVE_KSTAT_IO_T_WTIME
disk_submit(ksp[i]->ks_name, "disk_ops", kio.KIO_ROPS, kio.KIO_WOPS);
}
}
-/* #endif defined(HAVE_LIBKSTAT) */
+ /* #endif defined(HAVE_LIBKSTAT) */
#elif defined(HAVE_LIBSTATGRAB)
sg_disk_io_stats *ds;
disk_submit(name, "disk_octets", ds->read_bytes, ds->write_bytes);
ds++;
}
-/* #endif defined(HAVE_LIBSTATGRAB) */
+ /* #endif defined(HAVE_LIBSTATGRAB) */
#elif defined(HAVE_PERFSTAT)
derive_t read_sectors;
static void submit_octets(derive_t queries, derive_t responses) {
value_t values[] = {
- {.derive = queries}, {.derive = responses},
+ {.derive = queries},
+ {.derive = responses},
};
value_list_t vl = VALUE_LIST_INIT;
char dev_name[DATA_MAX_NAME_LEN];
if (ec->config.link_status.port_name[i][0] != 0) {
- snprintf(dev_name, sizeof(dev_name), "%s",
- ec->config.link_status.port_name[i]);
+ ssnprintf(dev_name, sizeof(dev_name), "%s",
+ ec->config.link_status.port_name[i]);
} else {
- snprintf(dev_name, sizeof(dev_name), "port.%d", i);
+ ssnprintf(dev_name, sizeof(dev_name), "port.%d", i);
}
if (ec->config.link_status.notify) {
int sev = ec->link_info[i].link_status ? NOTIF_OKAY : NOTIF_WARNING;
char msg[DATA_MAX_NAME_LEN];
- snprintf(msg, sizeof(msg), "Link Status: %s",
- ec->link_info[i].link_status ? "UP" : "DOWN");
+ ssnprintf(msg, sizeof(msg), "Link Status: %s",
+ ec->link_info[i].link_status ? "UP" : "DOWN");
dpdk_events_notification_dispatch(sev, dev_name,
ec->link_info[i].read_time, msg);
} else {
}
char core_name[DATA_MAX_NAME_LEN];
- snprintf(core_name, sizeof(core_name), "lcore%u", i);
+ ssnprintf(core_name, sizeof(core_name), "lcore%u", i);
if (!ec->config.keep_alive.send_updated ||
(ec->core_info[i].lcore_state !=
switch (ec->config.keep_alive.shm->core_state[i]) {
case RTE_KA_STATE_ALIVE:
sev = NOTIF_OKAY;
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: ALIVE", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: ALIVE", i);
break;
case RTE_KA_STATE_MISSING:
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: MISSING", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: MISSING", i);
sev = NOTIF_WARNING;
break;
case RTE_KA_STATE_DEAD:
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DEAD", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DEAD", i);
sev = NOTIF_FAILURE;
break;
case RTE_KA_STATE_UNUSED:
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNUSED", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNUSED", i);
sev = NOTIF_OKAY;
break;
case RTE_KA_STATE_GONE:
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: GONE", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: GONE", i);
sev = NOTIF_FAILURE;
break;
case RTE_KA_STATE_DOZING:
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DOZING", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DOZING", i);
sev = NOTIF_OKAY;
break;
case RTE_KA_STATE_SLEEP:
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: SLEEP", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: SLEEP", i);
sev = NOTIF_OKAY;
break;
default:
- snprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNKNOWN", i);
+ ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNKNOWN", i);
sev = NOTIF_FAILURE;
}
char dev_name[64];
if (ctx->config.port_name[i][0] != 0) {
- snprintf(dev_name, sizeof(dev_name), "%s", ctx->config.port_name[i]);
+ ssnprintf(dev_name, sizeof(dev_name), "%s", ctx->config.port_name[i]);
} else {
- snprintf(dev_name, sizeof(dev_name), "port.%d", i);
+ ssnprintf(dev_name, sizeof(dev_name), "port.%d", i);
}
DEBUG(" === Dispatch stats for port %d (name=%s; stats_count=%d)", i,
long int tmp = strtol(value, NULL, 0);
if (tmp < 1) {
- fprintf(stderr, "email plugin: `MaxConns' was set to invalid "
- "value %li, will use default %i.\n",
+ fprintf(stderr,
+ "email plugin: `MaxConns' was set to invalid "
+ "value %li, will use default %i.\n",
tmp, MAX_CONNS);
ERROR("email plugin: `MaxConns' was set to invalid "
"value %li, will use default %i.\n",
tmp, MAX_CONNS);
max_conns = MAX_CONNS;
} else if (tmp > MAX_CONNS_LIMIT) {
- fprintf(stderr, "email plugin: `MaxConns' was set to invalid "
- "value %li, will use hardcoded limit %i.\n",
+ fprintf(stderr,
+ "email plugin: `MaxConns' was set to invalid "
+ "value %li, will use hardcoded limit %i.\n",
tmp, MAX_CONNS_LIMIT);
ERROR("email plugin: `MaxConns' was set to invalid "
"value %li, will use hardcoded limit %i.\n",
#define _DEFAULT_SOURCE
#define _BSD_SOURCE /* For setgroups */
+/* _GNU_SOURCE is needed in Linux to use execvpe */
+#define _GNU_SOURCE
+
#include "collectd.h"
#include "plugin.h"
#include <sys/capability.h>
#endif
+extern char **environ;
+
#define PL_NORMAL 0x01
#define PL_NOTIF_ACTION 0x02
return 0;
} /* int exec_config }}} */
-#if !defined(HAVE_SETENV)
-static char env_interval[64];
-// max hostname len is 255, so this should be enough
-static char env_hostname[300];
-#endif
-
-static void set_environment(void) /* {{{ */
-{
-#ifdef HAVE_SETENV
- char buffer[1024];
-
- snprintf(buffer, sizeof(buffer), "%.3f",
- CDTIME_T_TO_DOUBLE(plugin_get_interval()));
- setenv("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1);
-
- sstrncpy(buffer, hostname_g, sizeof(buffer));
- setenv("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1);
-#else
- snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL=%.3f",
- CDTIME_T_TO_DOUBLE(plugin_get_interval()));
- putenv(env_interval);
-
- snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME=%s",
- hostname_g);
- putenv(env_hostname);
-#endif
-} /* }}} void set_environment */
-
-static void unset_environment(void) /* {{{ */
-{
-#ifdef HAVE_SETENV
- unsetenv("COLLECTD_INTERVAL");
- unsetenv("COLLECTD_HOSTNAME");
-#else
- snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL");
- putenv(env_interval);
- snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME");
- putenv(env_hostname);
-#endif
-} /* }}} void unset_environment */
-
-__attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid,
- int gid, int egid) /* {{{ */
+__attribute__((noreturn)) static void exec_child(program_list_t *pl,
+ char **envp, int uid, int gid,
+ int egid) /* {{{ */
{
int status;
exit(-1);
}
+#ifdef HAVE_EXECVPE
+ execvpe(pl->exec, pl->argv, envp);
+#else
+ environ = envp;
execvp(pl->exec, pl->argv);
+#endif
ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec, STRERRNO);
exit(-1);
goto failed;
}
- set_environment();
+ double interval = CDTIME_T_TO_DOUBLE(plugin_get_interval());
pid = fork();
if (pid < 0) {
ERROR("exec plugin: fork failed: %s", STRERRNO);
goto failed;
} else if (pid == 0) {
- int fd_num;
+ char interval_buf[128];
+ snprintf(interval_buf, sizeof(interval_buf), "COLLECTD_INTERVAL=%.3f",
+ interval);
+
+ /* max hostname len is 255, so this should be enough */
+ char hostname_buf[300];
+ snprintf(hostname_buf, sizeof(hostname_buf), "COLLECTD_HOSTNAME=%s",
+ hostname_g);
+
+ size_t env_size = 0;
+ while (environ[env_size] != NULL) {
+ ++env_size;
+ }
+
+ /* Copy the environment variables */
+ char *envp[env_size + 3];
+ size_t envp_idx;
+ for (envp_idx = 0; environ[envp_idx] != NULL && envp_idx < env_size;
+ ++envp_idx) {
+ envp[envp_idx] = environ[envp_idx];
+ }
+
+ /* Add the collectd environment variables */
+ envp[envp_idx++] = interval_buf;
+ envp[envp_idx++] = hostname_buf;
+ envp[envp_idx++] = NULL;
/* Close all file descriptors but the pipe end we need. */
- fd_num = getdtablesize();
+ int fd_num = getdtablesize();
for (int fd = 0; fd < fd_num; fd++) {
if ((fd == fd_pipe_in[0]) || (fd == fd_pipe_out[1]) ||
(fd == fd_pipe_err[1]))
/* Unblock all signals */
reset_signal_mask();
- exec_child(pl, uid, gid, egid);
+ exec_child(pl, envp, uid, gid, egid);
/* does not return */
}
- unset_environment();
-
close(fd_pipe_in[0]);
close(fd_pipe_out[1]);
close(fd_pipe_err[1]);
return pid;
failed:
- unset_environment();
-
close_pipe(fd_pipe_in);
close_pipe(fd_pipe_out);
close_pipe(fd_pipe_err);
else if (n->severity == NOTIF_OKAY)
severity = "OKAY";
- fprintf(fh, "Severity: %s\n"
- "Time: %.3f\n",
+ fprintf(fh,
+ "Severity: %s\n"
+ "Time: %.3f\n",
severity, CDTIME_T_TO_DOUBLE(n->time));
/* Print the optional fields */
INFO("exec plugin: Sent SIGTERM to %hu", (unsigned short int)pl->pid);
}
+ for (int i = 0; pl->argv[i] != NULL; i++) {
+ sfree(pl->argv[i]);
+ }
+ sfree(pl->argv);
+ sfree(pl->exec);
sfree(pl->user);
sfree(pl);
if (staging_tree == NULL)
return NULL;
- snprintf(key, sizeof(key), "%s/%s/%s", host, type,
- (type_instance != NULL) ? type_instance : "");
+ ssnprintf(key, sizeof(key), "%s/%s/%s", host, type,
+ (type_instance != NULL) ? type_instance : "");
se = NULL;
status = c_avl_get(staging_tree, key, (void *)&se);
#define KEY_IGNORESELECTED "IgnoreSelected"
static const char *config_keys[] = {
- KEY_GPUINDEX, KEY_IGNORESELECTED,
+ KEY_GPUINDEX,
+ KEY_IGNORESELECTED,
};
static const unsigned int n_config_keys = STATIC_ARRAY_SIZE(config_keys);
auto callback_name = grpc::string("grpc/") + addr;
user_data_t ud = {
- .data = client, .free_func = c_grpc_destroy_write_callback,
+ .data = client,
+ .free_func = c_grpc_destroy_write_callback,
};
plugin_register_write(callback_name.c_str(), c_grpc_write, &ud);
/**
* collectd - src/intel_rdt.c
*
- * Copyright(c) 2016-2018 Intel Corporation. All rights reserved.
+ * Copyright(c) 2016-2019 Intel Corporation. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
*
* Authors:
* Serhiy Pshyk <serhiyx.pshyk@intel.com>
+ * Starzyk, Mateusz <mateuszx.starzyk@intel.com>
+ * Wojciech Andralojc <wojciechx.andralojc@intel.com>
+ * Michał Aleksiński <michalx.aleksinski@intel.com>
**/
#include "collectd.h"
#include "utils/common/common.h"
#include "utils/config_cores/config_cores.h"
-
+#include "utils/proc_pids/proc_pids.h"
#include <pqos.h>
#define RDT_PLUGIN "intel_rdt"
+/* libpqos v2.0 or newer is required for process monitoring*/
+#undef LIBPQOS2
+#if defined(PQOS_VERSION) && PQOS_VERSION >= 20000
+#define LIBPQOS2
+#endif
+
+#define RDT_PLUGIN "intel_rdt"
+
#define RDT_MAX_SOCKETS 8
#define RDT_MAX_SOCKET_CORES 64
#define RDT_MAX_CORES (RDT_MAX_SOCKET_CORES * RDT_MAX_SOCKETS)
+#ifdef LIBPQOS2
+/*
+ * Process name inside comm file is limited to 16 chars.
+ * More info here: http://man7.org/linux/man-pages/man5/proc.5.html
+ */
+#define RDT_MAX_NAMES_GROUPS 64
+#define RDT_PROC_PATH "/proc"
+#endif /* LIBPQOS2 */
+
typedef enum {
UNKNOWN = 0,
CONFIGURATION_ERROR,
} rdt_config_status;
+#ifdef LIBPQOS2
+struct rdt_name_group_s {
+ char *desc;
+ size_t num_names;
+ char **names;
+ proc_pids_t **proc_pids;
+ size_t monitored_pids_count;
+ enum pqos_mon_event events;
+};
+typedef struct rdt_name_group_s rdt_name_group_t;
+#endif /* LIBPQOS2 */
+
struct rdt_ctx_s {
core_groups_list_t cores;
enum pqos_mon_event events[RDT_MAX_CORES];
- struct pqos_mon_data *pgroups[RDT_MAX_CORES];
- size_t num_groups;
+ struct pqos_mon_data *pcgroups[RDT_MAX_CORES];
+#ifdef LIBPQOS2
+ rdt_name_group_t ngroups[RDT_MAX_NAMES_GROUPS];
+ struct pqos_mon_data *pngroups[RDT_MAX_NAMES_GROUPS];
+ size_t num_ngroups;
+ proc_pids_t **proc_pids;
+ size_t num_proc_pids;
+#endif /* LIBPQOS2 */
const struct pqos_cpuinfo *pqos_cpu;
const struct pqos_cap *pqos_cap;
const struct pqos_capability *cap_mon;
static rdt_config_status g_state = UNKNOWN;
+static int g_interface = -1;
+
+static void rdt_submit_derive(const char *cgroup, const char *type,
+ const char *type_instance, derive_t value) {
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = &(value_t){.derive = value};
+ vl.values_len = 1;
+
+ sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s", cgroup);
+ sstrncpy(vl.type, type, sizeof(vl.type));
+ if (type_instance)
+ sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
+
+ plugin_dispatch_values(&vl);
+}
+
+static void rdt_submit_gauge(const char *cgroup, const char *type,
+ const char *type_instance, gauge_t value) {
+ value_list_t vl = VALUE_LIST_INIT;
+
+ vl.values = &(value_t){.gauge = value};
+ vl.values_len = 1;
+
+ sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s", cgroup);
+ sstrncpy(vl.type, type, sizeof(vl.type));
+ if (type_instance)
+ sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
+
+ plugin_dispatch_values(&vl);
+}
+
#if COLLECT_DEBUG
static void rdt_dump_cgroups(void) {
char cores[RDT_MAX_CORES * 4];
return;
DEBUG(RDT_PLUGIN ": Core Groups Dump");
- DEBUG(RDT_PLUGIN ": groups count: %" PRIsz, g_rdt->num_groups);
+ DEBUG(RDT_PLUGIN ": groups count: %" PRIsz, g_rdt->cores.num_cgroups);
- for (size_t i = 0; i < g_rdt->num_groups; i++) {
+ for (size_t i = 0; i < g_rdt->cores.num_cgroups; i++) {
core_group_t *cgroup = g_rdt->cores.cgroups + i;
memset(cores, 0, sizeof(cores));
- for (int j = 0; j < cgroup->num_cores; j++) {
- snprintf(cores + strlen(cores), sizeof(cores) - strlen(cores) - 1, " %d",
- cgroup->cores[j]);
+ for (size_t j = 0; j < cgroup->num_cores; j++) {
+ ssnprintf(cores + strlen(cores), sizeof(cores) - strlen(cores) - 1, " %d",
+ cgroup->cores[j]);
}
DEBUG(RDT_PLUGIN ": group[%zu]:", i);
return;
}
+#ifdef LIBPQOS2
+static void rdt_dump_ngroups(void) {
+
+ char names[DATA_MAX_NAME_LEN];
+
+ if (g_rdt == NULL)
+ return;
+
+ DEBUG(RDT_PLUGIN ": Process Names Groups Dump");
+ DEBUG(RDT_PLUGIN ": groups count: %" PRIsz, g_rdt->num_ngroups);
+
+ for (size_t i = 0; i < g_rdt->num_ngroups; i++) {
+ memset(names, 0, sizeof(names));
+ for (size_t j = 0; j < g_rdt->ngroups[i].num_names; j++)
+ ssnprintf(names + strlen(names), sizeof(names) - strlen(names) - 1, " %s",
+ g_rdt->ngroups[i].names[j]);
+
+ DEBUG(RDT_PLUGIN ": group[%d]:", (int)i);
+ DEBUG(RDT_PLUGIN ": description: %s", g_rdt->ngroups[i].desc);
+ DEBUG(RDT_PLUGIN ": process names:%s", names);
+ DEBUG(RDT_PLUGIN ": events: 0x%X", g_rdt->ngroups[i].events);
+ }
+
+ return;
+}
+#endif /* LIBPQOS2 */
+
static inline double bytes_to_kb(const double bytes) { return bytes / 1024.0; }
static inline double bytes_to_mb(const double bytes) {
return bytes / (1024.0 * 1024.0);
}
-static void rdt_dump_data(void) {
+static void rdt_dump_cores_data(void) {
+/*
+ * CORE - monitored group of cores
+ * RMID - Resource Monitoring ID associated with the monitored group
+ * This is not available for monitoring with resource control
+ * LLC - last level cache occupancy
+ * MBL - local memory bandwidth
+ * MBR - remote memory bandwidth
+ */
+#ifdef LIBPQOS2
+ if (g_interface == PQOS_INTER_OS_RESCTRL_MON) {
+ DEBUG(RDT_PLUGIN ": CORE LLC[KB] MBL[MB] MBR[MB]");
+ } else {
+ DEBUG(RDT_PLUGIN ": CORE RMID LLC[KB] MBL[MB] MBR[MB]");
+ }
+#else
+ DEBUG(RDT_PLUGIN ": CORE RMID LLC[KB] MBL[MB] MBR[MB]");
+#endif /* LIBPQOS2 */
+
+ for (int i = 0; i < g_rdt->cores.num_cgroups; i++) {
+ const struct pqos_event_values *pv = &g_rdt->pcgroups[i]->values;
+
+ double llc = bytes_to_kb(pv->llc);
+ double mbr = bytes_to_mb(pv->mbm_remote_delta);
+ double mbl = bytes_to_mb(pv->mbm_local_delta);
+#ifdef LIBPQOS2
+ if (g_interface == PQOS_INTER_OS_RESCTRL_MON) {
+ DEBUG(RDT_PLUGIN ": [%s] %10.1f %10.1f %10.1f",
+ g_rdt->cores.cgroups[i].desc, llc, mbl, mbr);
+ } else {
+ DEBUG(RDT_PLUGIN ": [%s] %8u %10.1f %10.1f %10.1f",
+ g_rdt->cores.cgroups[i].desc, g_rdt->pcgroups[i]->poll_ctx[0].rmid,
+ llc, mbl, mbr);
+ }
+#else
+ DEBUG(RDT_PLUGIN ": [%s] %8u %10.1f %10.1f %10.1f",
+ g_rdt->cores.cgroups[i].desc, g_rdt->pcgroups[i]->poll_ctx[0].rmid,
+ llc, mbl, mbr);
+#endif /* LIBPQOS2 */
+ }
+}
+
+#ifdef LIBPQOS2
+static void rdt_dump_pids_data(void) {
/*
- * CORE - monitored group of cores
- * RMID - Resource Monitoring ID associated with the monitored group
+ * NAME - monitored group of processes
+ * PIDs - list of PID numbers in the NAME group
* LLC - last level cache occupancy
* MBL - local memory bandwidth
* MBR - remote memory bandwidth
*/
- DEBUG(" CORE RMID LLC[KB] MBL[MB] MBR[MB]");
- for (int i = 0; i < g_rdt->num_groups; i++) {
- const struct pqos_event_values *pv = &g_rdt->pgroups[i]->values;
+ DEBUG(RDT_PLUGIN ": NAME PIDs");
+ char pids[DATA_MAX_NAME_LEN];
+ for (size_t i = 0; i < g_rdt->num_ngroups; ++i) {
+ memset(pids, 0, sizeof(pids));
+ for (size_t j = 0; j < g_rdt->ngroups[i].num_names; ++j) {
+ pids_list_t *list = g_rdt->ngroups[i].proc_pids[j]->curr;
+ for (size_t k = 0; k < list->size; k++)
+ ssnprintf(pids + strlen(pids), sizeof(pids) - strlen(pids) - 1, " %u",
+ list->pids[k]);
+ }
+ DEBUG(RDT_PLUGIN ": [%s] %s", g_rdt->ngroups[i].desc, pids);
+ }
+
+ DEBUG(RDT_PLUGIN ": NAME LLC[KB] MBL[MB] MBR[MB]");
+ for (size_t i = 0; i < g_rdt->num_ngroups; i++) {
+
+ const struct pqos_event_values *pv = &g_rdt->pngroups[i]->values;
double llc = bytes_to_kb(pv->llc);
double mbr = bytes_to_mb(pv->mbm_remote_delta);
double mbl = bytes_to_mb(pv->mbm_local_delta);
- DEBUG(" [%s] %8u %10.1f %10.1f %10.1f", g_rdt->cores.cgroups[i].desc,
- g_rdt->pgroups[i]->poll_ctx[0].rmid, llc, mbl, mbr);
+ DEBUG(RDT_PLUGIN ": [%s] %10.1f %10.1f %10.1f", g_rdt->ngroups[i].desc,
+ llc, mbl, mbr);
+ }
+}
+#endif /* LIBPQOS2 */
+#endif /* COLLECT_DEBUG */
+
+#ifdef LIBPQOS2
+static int isdupstr(const char *names[], const size_t size, const char *name) {
+ for (size_t i = 0; i < size; i++)
+ if (strncmp(names[i], name, (size_t)MAX_PROC_NAME_LEN) == 0)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * NAME
+ * strlisttoarray
+ *
+ * DESCRIPTION
+ * Converts string representing list of strings into array of strings.
+ * Allowed format is:
+ * name,name1,name2,name3
+ *
+ * PARAMETERS
+ * `str_list' String representing list of strings.
+ * `names' Array to put extracted strings into.
+ * `names_num' Variable to put number of extracted strings.
+ *
+ * RETURN VALUE
+ * Number of elements placed into names.
+ */
+static int strlisttoarray(char *str_list, char ***names, size_t *names_num) {
+ char *saveptr = NULL;
+
+ if (str_list == NULL || names == NULL)
+ return -EINVAL;
+
+ if (strstr(str_list, ",,")) {
+ /* strtok ignores empty words between separators.
+ * This condition handles that by rejecting strings
+ * with consecutive seprators */
+ ERROR(RDT_PLUGIN ": Empty process name");
+ return -EINVAL;
+ }
+
+ for (;;) {
+ char *token = strtok_r(str_list, ",", &saveptr);
+ if (token == NULL)
+ break;
+
+ str_list = NULL;
+
+ while (isspace(*token))
+ token++;
+
+ if (*token == '\0')
+ continue;
+
+ if ((isdupstr((const char **)*names, *names_num, token))) {
+ ERROR(RDT_PLUGIN ": Duplicated process name \'%s\'", token);
+
+ return -EINVAL;
+ } else {
+ if (0 != strarray_add(names, names_num, token)) {
+ ERROR(RDT_PLUGIN ": Error allocating process name string");
+ return -ENOMEM;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * NAME
+ * ngroup_cmp
+ *
+ * DESCRIPTION
+ * Function to compare names in two name groups.
+ *
+ * PARAMETERS
+ * `ng_a' Pointer to name group a.
+ * `ng_b' Pointer to name group b.
+ *
+ * RETURN VALUE
+ * 1 if both groups contain the same names
+ * 0 if none of their names match
+ * -1 if some but not all names match
+ */
+static int ngroup_cmp(const rdt_name_group_t *ng_a,
+ const rdt_name_group_t *ng_b) {
+ unsigned found = 0;
+
+ assert(ng_a != NULL);
+ assert(ng_b != NULL);
+
+ const size_t sz_a = (unsigned)ng_a->num_names;
+ const size_t sz_b = (unsigned)ng_b->num_names;
+ const char **tab_a = (const char **)ng_a->names;
+ const char **tab_b = (const char **)ng_b->names;
+
+ for (size_t i = 0; i < sz_a; i++) {
+ for (size_t j = 0; j < sz_b; j++)
+ if (strncmp(tab_a[i], tab_b[j], (size_t)MAX_PROC_NAME_LEN) == 0)
+ found++;
+ }
+ /* if no names are the same */
+ if (!found)
+ return 0;
+ /* if group contains same names */
+ if (sz_a == sz_b && sz_b == (size_t)found)
+ return 1;
+ /* if not all names are the same */
+ return -1;
+}
+
+/*
+ * NAME
+ * oconfig_to_ngroups
+ *
+ * DESCRIPTION
+ * Function to set the descriptions and names for each process names group.
+ * Takes a config option containing list of strings that are used to set
+ * process group values.
+ *
+ * PARAMETERS
+ * `item' Config option containing process names groups.
+ * `groups' Table of process name groups to set values in.
+ * `max_groups' Maximum number of process name groups allowed.
+ *
+ * RETURN VALUE
+ * On success, the number of name groups set up. On error, appropriate
+ * negative error value.
+ */
+static int oconfig_to_ngroups(const oconfig_item_t *item,
+ rdt_name_group_t *groups,
+ const size_t max_groups) {
+ int index = 0;
+
+ assert(groups != NULL);
+ assert(max_groups > 0);
+ assert(item != NULL);
+
+ for (int j = 0; j < item->values_num; j++) {
+ int ret;
+ char value[DATA_MAX_NAME_LEN];
+
+ if ((item->values[j].value.string == NULL) ||
+ (strlen(item->values[j].value.string) == 0)) {
+ ERROR(RDT_PLUGIN ": Error - empty group");
+ return -EINVAL;
+ }
+
+ sstrncpy(value, item->values[j].value.string, sizeof(value));
+
+ ret = strlisttoarray(value, &groups[index].names, &groups[index].num_names);
+ if (ret != 0 || groups[index].num_names == 0) {
+ ERROR(RDT_PLUGIN ": Error parsing process names group (%s)",
+ item->values[j].value.string);
+ return -EINVAL;
+ }
+
+ /* set group description info */
+ groups[index].desc = sstrdup(item->values[j].value.string);
+ if (groups[index].desc == NULL) {
+ ERROR(RDT_PLUGIN ": Error allocating name group description");
+ return -ENOMEM;
+ }
+
+ groups[index].proc_pids = NULL;
+ groups[index].monitored_pids_count = 0;
+
+ index++;
+
+ if (index >= (const int)max_groups) {
+ WARNING(RDT_PLUGIN ": Too many process names groups configured");
+ return index;
+ }
+ }
+
+ return index;
+}
+
+/*
+ * NAME
+ * rdt_free_ngroups
+ *
+ * DESCRIPTION
+ * Function to deallocate memory allocated for name groups.
+ *
+ * PARAMETERS
+ * `rdt' Pointer to rdt context
+ */
+static void rdt_free_ngroups(rdt_ctx_t *rdt) {
+ for (int i = 0; i < RDT_MAX_NAMES_GROUPS; i++) {
+ if (rdt->ngroups[i].desc)
+ DEBUG(RDT_PLUGIN ": Freeing pids \'%s\' group\'s data...",
+ rdt->ngroups[i].desc);
+ sfree(rdt->ngroups[i].desc);
+ strarray_free(rdt->ngroups[i].names, rdt->ngroups[i].num_names);
+
+ if (rdt->ngroups[i].proc_pids)
+ proc_pids_free(rdt->ngroups[i].proc_pids, rdt->ngroups[i].num_names);
+
+ rdt->ngroups[i].num_names = 0;
+ sfree(rdt->pngroups[i]);
+ }
+ if (rdt->proc_pids)
+ sfree(rdt->proc_pids);
+
+ rdt->num_ngroups = 0;
+}
+
+/*
+ * NAME
+ * rdt_config_ngroups
+ *
+ * DESCRIPTION
+ * Reads name groups configuration.
+ *
+ * PARAMETERS
+ * `rdt` Pointer to rdt context
+ * `item' Config option containing process names groups.
+ *
+ * RETURN VALUE
+ * 0 on success. Negative number on error.
+ */
+static int rdt_config_ngroups(rdt_ctx_t *rdt, const oconfig_item_t *item) {
+ int n = 0;
+ enum pqos_mon_event events = 0;
+
+ if (item == NULL) {
+ DEBUG(RDT_PLUGIN ": ngroups_config: Invalid argument.");
+ return -EINVAL;
+ }
+
+ DEBUG(RDT_PLUGIN ": Process names groups [%d]:", item->values_num);
+ for (int j = 0; j < item->values_num; j++) {
+ if (item->values[j].type != OCONFIG_TYPE_STRING) {
+ ERROR(RDT_PLUGIN
+ ": given process names group value is not a string [idx=%d]",
+ j);
+ return -EINVAL;
+ }
+ DEBUG(RDT_PLUGIN ": [%d]: %s", j, item->values[j].value.string);
+ }
+
+ n = oconfig_to_ngroups(item, rdt->ngroups, RDT_MAX_NAMES_GROUPS);
+ if (n < 0) {
+ rdt_free_ngroups(rdt);
+ ERROR(RDT_PLUGIN ": Error parsing process name groups configuration.");
+ return -EINVAL;
+ }
+
+ /* validate configured process name values */
+ for (int group_idx = 0; group_idx < n; group_idx++) {
+ DEBUG(RDT_PLUGIN ": checking group [%d]: %s", group_idx,
+ rdt->ngroups[group_idx].desc);
+ for (size_t name_idx = 0; name_idx < rdt->ngroups[group_idx].num_names;
+ name_idx++) {
+ DEBUG(RDT_PLUGIN ": checking process name [%zu]: %s", name_idx,
+ rdt->ngroups[group_idx].names[name_idx]);
+ if (!proc_pids_is_name_valid(rdt->ngroups[group_idx].names[name_idx])) {
+ ERROR(RDT_PLUGIN ": Process name group '%s' contains invalid name '%s'",
+ rdt->ngroups[group_idx].desc,
+ rdt->ngroups[group_idx].names[name_idx]);
+ rdt_free_ngroups(rdt);
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (n == 0) {
+ ERROR(RDT_PLUGIN ": Empty process name groups configured.");
+ return -EINVAL;
+ }
+
+ /* Get all available events on this platform */
+ for (unsigned i = 0; i < rdt->cap_mon->u.mon->num_events; i++)
+ events |= rdt->cap_mon->u.mon->events[i].type;
+
+ events &= ~(PQOS_PERF_EVENT_LLC_MISS);
+
+ DEBUG(RDT_PLUGIN ": Available events to monitor: %#x", events);
+
+ rdt->num_ngroups = n;
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < i; j++) {
+ int found = ngroup_cmp(&rdt->ngroups[j], &rdt->ngroups[i]);
+ if (found != 0) {
+ rdt_free_ngroups(rdt);
+ ERROR(RDT_PLUGIN
+ ": Cannot monitor same process name in different groups.");
+ return -EINVAL;
+ }
+ }
+
+ rdt->ngroups[i].events = events;
+ rdt->pngroups[i] = calloc(1, sizeof(*rdt->pngroups[i]));
+ if (rdt->pngroups[i] == NULL) {
+ rdt_free_ngroups(rdt);
+ ERROR(RDT_PLUGIN
+ ": Failed to allocate memory for process name monitoring data.");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * NAME
+ * rdt_refresh_ngroup
+ *
+ * DESCRIPTION
+ * Refresh pids monitored by name group.
+ *
+ * PARAMETERS
+ * `ngroup` Pointer to name group.
+ * `group_mon_data' PQoS monitoring context.
+ *
+ * RETURN VALUE
+ * 0 on success. Negative number on error.
+ */
+static int rdt_refresh_ngroup(rdt_name_group_t *ngroup,
+ struct pqos_mon_data *group_mon_data) {
+
+ int result = 0;
+
+ if (NULL == ngroup)
+ return -1;
+
+ if (NULL == ngroup->proc_pids) {
+ ERROR(RDT_PLUGIN
+ ": rdt_refresh_ngroup: \'%s\' uninitialized process pids array.",
+ ngroup->desc);
+
+ return -1;
+ }
+
+ DEBUG(RDT_PLUGIN ": rdt_refresh_ngroup: \'%s\' process names group.",
+ ngroup->desc);
+
+ proc_pids_t **proc_pids = ngroup->proc_pids;
+ pids_list_t added_pids;
+ pids_list_t removed_pids;
+
+ memset(&added_pids, 0, sizeof(added_pids));
+ memset(&removed_pids, 0, sizeof(removed_pids));
+
+ for (size_t i = 0; i < ngroup->num_names; ++i) {
+ int diff_result = pids_list_diff(proc_pids[i], &added_pids, &removed_pids);
+ if (0 != diff_result) {
+ ERROR(RDT_PLUGIN
+ ": rdt_refresh_ngroup: \'%s\'. Error [%d] during PID diff.",
+ ngroup->desc, diff_result);
+ result = -1;
+ goto cleanup;
+ }
+ }
+
+ DEBUG(RDT_PLUGIN ": rdt_refresh_ngroup: \'%s\' process names group, added: "
+ "%u, removed: %u.",
+ ngroup->desc, (unsigned)added_pids.size, (unsigned)removed_pids.size);
+
+ if (added_pids.size > 0) {
+
+ /* no pids are monitored for this group yet: start monitoring */
+ if (0 == ngroup->monitored_pids_count) {
+
+ int start_result =
+ pqos_mon_start_pids(added_pids.size, added_pids.pids, ngroup->events,
+ (void *)ngroup->desc, group_mon_data);
+ if (PQOS_RETVAL_OK == start_result) {
+ ngroup->monitored_pids_count = added_pids.size;
+ } else {
+ ERROR(RDT_PLUGIN ": rdt_refresh_ngroup: \'%s\'. Error [%d] while "
+ "STARTING pids monitoring",
+ ngroup->desc, start_result);
+ result = -1;
+ goto pqos_error_recovery;
+ }
+
+ } else {
+
+ int add_result =
+ pqos_mon_add_pids(added_pids.size, added_pids.pids, group_mon_data);
+ if (PQOS_RETVAL_OK == add_result)
+ ngroup->monitored_pids_count += added_pids.size;
+ else {
+ ERROR(RDT_PLUGIN
+ ": rdt_refresh_ngroup: \'%s\'. Error [%d] while ADDING pids.",
+ ngroup->desc, add_result);
+ result = -1;
+ goto pqos_error_recovery;
+ }
+ }
+ }
+
+ if (removed_pids.size > 0) {
+
+ /* all pids are removed: stop monitoring */
+ if (removed_pids.size == ngroup->monitored_pids_count) {
+ /* all pids for this group are lost: stop monitoring */
+ int stop_result = pqos_mon_stop(group_mon_data);
+ if (PQOS_RETVAL_OK != stop_result) {
+ ERROR(RDT_PLUGIN ": rdt_refresh_ngroup: \'%s\'. Error [%d] while "
+ "STOPPING monitoring",
+ ngroup->desc, stop_result);
+ result = -1;
+ goto pqos_error_recovery;
+ }
+ ngroup->monitored_pids_count = 0;
+ } else {
+ int remove_result = pqos_mon_remove_pids(
+ removed_pids.size, removed_pids.pids, group_mon_data);
+ if (PQOS_RETVAL_OK == remove_result) {
+ ngroup->monitored_pids_count -= removed_pids.size;
+ } else {
+ ERROR(RDT_PLUGIN
+ ": rdt_refresh_ngroup: \'%s\'. Error [%d] while REMOVING pids.",
+ ngroup->desc, remove_result);
+ result = -1;
+ goto pqos_error_recovery;
+ }
+ }
}
+
+ goto cleanup;
+
+pqos_error_recovery:
+ /* Why?
+ * Resources might be temporary unavailable.
+ *
+ * How?
+ * Collectd will halt the reading thread for this
+ * plugin if it returns an error.
+ * Consecutive errors will be increasing the read period
+ * up to 1 day interval.
+ * On pqos error stop monitoring current group
+ * and reset the proc_pids array
+ * monitoring will be restarted on next collectd read cycle
+ */
+ DEBUG(RDT_PLUGIN ": rdt_refresh_ngroup: \'%s\' group RESET after error.",
+ ngroup->desc);
+ pqos_mon_stop(group_mon_data);
+ for (size_t i = 0; i < ngroup->num_names; ++i)
+ if (ngroup->proc_pids[i]->curr)
+ ngroup->proc_pids[i]->curr->size = 0;
+
+ ngroup->monitored_pids_count = 0;
+
+cleanup:
+ pids_list_clear(&added_pids);
+ pids_list_clear(&removed_pids);
+
+ return result;
}
+
+/*
+ * NAME
+ * read_pids_data
+ *
+ * DESCRIPTION
+ * Poll monitoring statistics for name groups
+ *
+ * RETURN VALUE
+ * 0 on success. Negative number on error.
+ */
+static int read_pids_data() {
+
+ if (0 == g_rdt->num_ngroups) {
+ DEBUG(RDT_PLUGIN ": read_pids_data: not configured - PIDs read skipped");
+ return 0;
+ }
+
+ DEBUG(RDT_PLUGIN ": read_pids_data: Scanning active groups");
+ struct pqos_mon_data *active_groups[RDT_MAX_NAMES_GROUPS] = {0};
+ size_t active_group_idx = 0;
+ for (size_t pngroups_idx = 0;
+ pngroups_idx < STATIC_ARRAY_SIZE(g_rdt->pngroups); ++pngroups_idx)
+ if (0 != g_rdt->ngroups[pngroups_idx].monitored_pids_count)
+ active_groups[active_group_idx++] = g_rdt->pngroups[pngroups_idx];
+
+ int ret = 0;
+
+ if (0 == active_group_idx) {
+ DEBUG(RDT_PLUGIN ": read_pids_data: no active groups - PIDs read skipped");
+ goto groups_refresh;
+ }
+
+ DEBUG(RDT_PLUGIN ": read_pids_data: PIDs data polling");
+
+ int poll_result = pqos_mon_poll(active_groups, active_group_idx);
+ if (poll_result != PQOS_RETVAL_OK) {
+ ERROR(RDT_PLUGIN ": read_pids_data: Failed to poll monitoring data for "
+ "pids. Error [%d].",
+ poll_result);
+ ret = -poll_result;
+ goto groups_refresh;
+ }
+
+ for (size_t i = 0; i < g_rdt->num_ngroups; i++) {
+ enum pqos_mon_event mbm_events =
+ (PQOS_MON_EVENT_LMEM_BW | PQOS_MON_EVENT_TMEM_BW |
+ PQOS_MON_EVENT_RMEM_BW);
+
+ if (g_rdt->pngroups[i] == NULL ||
+ g_rdt->ngroups[i].monitored_pids_count == 0)
+ continue;
+
+ const struct pqos_event_values *pv = &g_rdt->pngroups[i]->values;
+
+ /* Submit only monitored events data */
+
+ if (g_rdt->ngroups[i].events & PQOS_MON_EVENT_L3_OCCUP)
+ rdt_submit_gauge(g_rdt->ngroups[i].desc, "bytes", "llc", pv->llc);
+
+ if (g_rdt->ngroups[i].events & PQOS_PERF_EVENT_IPC)
+ rdt_submit_gauge(g_rdt->ngroups[i].desc, "ipc", NULL, pv->ipc);
+
+ if (g_rdt->ngroups[i].events & mbm_events) {
+ rdt_submit_derive(g_rdt->ngroups[i].desc, "memory_bandwidth", "local",
+ pv->mbm_local_delta);
+ rdt_submit_derive(g_rdt->ngroups[i].desc, "memory_bandwidth", "remote",
+ pv->mbm_remote_delta);
+ }
+ }
+
+#if COLLECT_DEBUG
+ rdt_dump_pids_data();
#endif /* COLLECT_DEBUG */
+groups_refresh:
+ ret = proc_pids_update(RDT_PROC_PATH, g_rdt->proc_pids, g_rdt->num_proc_pids);
+ if (0 != ret) {
+ ERROR(RDT_PLUGIN ": Initial update of proc pids failed");
+ return ret;
+ }
+
+ for (size_t i = 0; i < g_rdt->num_ngroups; i++) {
+ int refresh_result =
+ rdt_refresh_ngroup(&(g_rdt->ngroups[i]), g_rdt->pngroups[i]);
+
+ if (0 != refresh_result) {
+ ERROR(RDT_PLUGIN ": read_pids_data: NGroup %zu refresh failed. Error: %d",
+ i, refresh_result);
+ if (0 == ret) {
+ /* refresh error will be escalated only if there were no
+ * errors before.
+ */
+ ret = refresh_result;
+ }
+ }
+ }
+
+ assert(ret <= 0);
+ return ret;
+}
+
+/*
+ * NAME
+ * rdt_init_pids_monitoring
+ *
+ * DESCRIPTION
+ * Initialize pids monitoring for all name groups
+ */
+static void rdt_init_pids_monitoring() {
+ for (size_t group_idx = 0; group_idx < g_rdt->num_ngroups; group_idx++) {
+ /*
+ * Each group must have not-null proc_pids array.
+ * Initial refresh is not mandatory for proper
+ * PIDs statistics detection.
+ */
+ rdt_name_group_t *ng = &g_rdt->ngroups[group_idx];
+ int init_result =
+ proc_pids_init((const char **)ng->names, ng->num_names, &ng->proc_pids);
+ if (0 != init_result) {
+ ERROR(RDT_PLUGIN
+ ": Initialization of proc_pids for group %zu failed. Error: %d",
+ group_idx, init_result);
+ continue;
+ }
+
+ /* update global proc_pids table */
+ proc_pids_t **proc_pids =
+ realloc(g_rdt->proc_pids, (g_rdt->num_proc_pids + ng->num_names) *
+ sizeof(*g_rdt->proc_pids));
+ if (NULL == proc_pids) {
+ ERROR(RDT_PLUGIN ": Alloc error\n");
+ continue;
+ }
+
+ for (size_t i = 0; i < ng->num_names; i++)
+ proc_pids[g_rdt->num_proc_pids + i] = ng->proc_pids[i];
+
+ g_rdt->proc_pids = proc_pids;
+ g_rdt->num_proc_pids += ng->num_names;
+ }
+
+ if (g_rdt->num_ngroups > 0) {
+ int update_result =
+ proc_pids_update(RDT_PROC_PATH, g_rdt->proc_pids, g_rdt->num_proc_pids);
+ if (0 != update_result)
+ ERROR(RDT_PLUGIN ": Initial update of proc pids failed");
+ }
+
+ for (size_t group_idx = 0; group_idx < g_rdt->num_ngroups; group_idx++) {
+ int refresh_result = rdt_refresh_ngroup(&(g_rdt->ngroups[group_idx]),
+ g_rdt->pngroups[group_idx]);
+ if (0 != refresh_result)
+ ERROR(RDT_PLUGIN ": Initial refresh of group %zu failed. Error: %d",
+ group_idx, refresh_result);
+ }
+}
+#endif /* LIBPQOS2 */
+/*
+ * NAME
+ * rdt_free_cgroups
+ *
+ * DESCRIPTION
+ * Function to deallocate memory allocated for core groups.
+ */
static void rdt_free_cgroups(void) {
config_cores_cleanup(&g_rdt->cores);
for (int i = 0; i < RDT_MAX_CORES; i++) {
- sfree(g_rdt->pgroups[i]);
+ sfree(g_rdt->pcgroups[i]);
}
+ g_rdt->cores.num_cgroups = 0;
}
static int rdt_default_cgroups(void) {
unsigned num_cores = g_rdt->pqos_cpu->num_cores;
- g_rdt->cores.cgroups = calloc(num_cores, sizeof(*g_rdt->cores.cgroups));
+ g_rdt->cores.cgroups = calloc(num_cores, sizeof(*(g_rdt->cores.cgroups)));
if (g_rdt->cores.cgroups == NULL) {
ERROR(RDT_PLUGIN ": Error allocating core groups array");
return -ENOMEM;
cgroup->num_cores = 1;
cgroup->cores[0] = i;
- snprintf(desc, sizeof(desc), "%d", g_rdt->pqos_cpu->cores[i].lcore);
+ ssnprintf(desc, sizeof(desc), "%d", g_rdt->pqos_cpu->cores[i].lcore);
cgroup->desc = strdup(desc);
if (cgroup->desc == NULL) {
ERROR(RDT_PLUGIN ": Error allocating core group description");
g_rdt->pqos_cpu->num_cores);
DEBUG(RDT_PLUGIN ": Available events to monitor: %#x", events);
- g_rdt->num_groups = n;
- for (size_t i = 0; i < n; i++) {
- for (size_t j = 0; j < i; j++) {
+ g_rdt->cores.num_cgroups = n;
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < i; j++) {
int found = 0;
found = config_cores_cmp_cgroups(&g_rdt->cores.cgroups[j],
&g_rdt->cores.cgroups[i]);
}
g_rdt->events[i] = events;
- g_rdt->pgroups[i] = calloc(1, sizeof(*g_rdt->pgroups[i]));
- if (g_rdt->pgroups[i] == NULL) {
+ g_rdt->pcgroups[i] = calloc(1, sizeof(*g_rdt->pcgroups[i]));
+ if (g_rdt->pcgroups[i] == NULL) {
rdt_free_cgroups();
ERROR(RDT_PLUGIN ": Failed to allocate memory for monitoring data.");
return -ENOMEM;
struct pqos_config pqos = {.fd_log = -1,
.callback_log = rdt_pqos_log,
.context_log = NULL,
- .verbose = 0};
+ .verbose = 0,
+#ifdef LIBPQOS2
+ .interface = PQOS_INTER_OS_RESCTRL_MON};
+ DEBUG(RDT_PLUGIN ": Initializing PQoS with RESCTRL interface");
+#else
+ .interface = PQOS_INTER_MSR};
+ DEBUG(RDT_PLUGIN ": Initializing PQoS with MSR interface");
+#endif
ret = pqos_init(&pqos);
+ DEBUG(RDT_PLUGIN ": PQoS initialization result: [%d]", ret);
+
+#ifdef LIBPQOS2
+ if (ret == PQOS_RETVAL_INTER) {
+ pqos.interface = PQOS_INTER_MSR;
+ DEBUG(RDT_PLUGIN ": Initializing PQoS with MSR interface");
+ ret = pqos_init(&pqos);
+ DEBUG(RDT_PLUGIN ": PQoS initialization result: [%d]", ret);
+ }
+#endif
+
if (ret != PQOS_RETVAL_OK) {
ERROR(RDT_PLUGIN ": Error initializing PQoS library!");
goto rdt_preinit_error1;
}
+ g_interface = pqos.interface;
+
ret = pqos_cap_get(&g_rdt->pqos_cap, &g_rdt->pqos_cpu);
if (ret != PQOS_RETVAL_OK) {
ERROR(RDT_PLUGIN ": Error retrieving PQoS capabilities.");
pqos_fini();
rdt_preinit_error1:
-
sfree(g_rdt);
return -1;
reports a failure in configuration and
aborts
*/
- return (0);
+ return 0;
}
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *child = ci->children + i;
- if (strcasecmp("Cores", child->key) == 0) {
- if (rdt_config_cgroups(child) != 0) {
+ if (strncasecmp("Cores", child->key, (size_t)strlen("Cores")) == 0) {
+ if (g_rdt->cores.num_cgroups > 0) {
+ ERROR(RDT_PLUGIN
+ ": Configuration parameter \"%s\" can be used only once.",
+ child->key);
+ g_state = CONFIGURATION_ERROR;
+ } else if (rdt_config_cgroups(child) != 0)
g_state = CONFIGURATION_ERROR;
+
+ if (g_state == CONFIGURATION_ERROR)
/* if we return -1 at this point collectd
reports a failure in configuration and
aborts
*/
- return (0);
- }
+ return 0;
#if COLLECT_DEBUG
rdt_dump_cgroups();
#endif /* COLLECT_DEBUG */
+ } else if (strncasecmp("Processes", child->key,
+ (size_t)strlen("Processes")) == 0) {
+#ifdef LIBPQOS2
+ if (g_interface != PQOS_INTER_OS_RESCTRL_MON) {
+ ERROR(RDT_PLUGIN ": Configuration parameter \"%s\" not supported. "
+ "Resctrl monitoring is needed for PIDs monitoring.",
+ child->key);
+ g_state = CONFIGURATION_ERROR;
+ }
+
+ else if (g_rdt->num_ngroups > 0) {
+ ERROR(RDT_PLUGIN
+ ": Configuration parameter \"%s\" can be used only once.",
+ child->key);
+ g_state = CONFIGURATION_ERROR;
+ }
+
+ else if (rdt_config_ngroups(g_rdt, child) != 0)
+ g_state = CONFIGURATION_ERROR;
+
+ if (g_state == CONFIGURATION_ERROR)
+ /* if we return -1 at this point collectd
+ reports a failure in configuration and
+ aborts
+ */
+ return 0;
+
+#if COLLECT_DEBUG
+ rdt_dump_ngroups();
+#endif /* COLLECT_DEBUG */
+#else /* !LIBPQOS2 */
+ ERROR(RDT_PLUGIN ": Configuration parameter \"%s\" not supported, please "
+ "recompile collectd with libpqos version 2.0 or newer.",
+ child->key);
+#endif /* LIBPQOS2 */
} else {
ERROR(RDT_PLUGIN ": Unknown configuration parameter \"%s\".", child->key);
}
return 0;
}
-static void rdt_submit_derive(const char *cgroup, const char *type,
- const char *type_instance, derive_t value) {
- value_list_t vl = VALUE_LIST_INIT;
-
- vl.values = &(value_t){.derive = value};
- vl.values_len = 1;
-
- sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s", cgroup);
- sstrncpy(vl.type, type, sizeof(vl.type));
- if (type_instance)
- sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
-
- plugin_dispatch_values(&vl);
-}
-
-static void rdt_submit_gauge(const char *cgroup, const char *type,
- const char *type_instance, gauge_t value) {
- value_list_t vl = VALUE_LIST_INIT;
-
- vl.values = &(value_t){.gauge = value};
- vl.values_len = 1;
+static int read_cores_data() {
- sstrncpy(vl.plugin, RDT_PLUGIN, sizeof(vl.plugin));
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s", cgroup);
- sstrncpy(vl.type, type, sizeof(vl.type));
- if (type_instance)
- sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
-
- plugin_dispatch_values(&vl);
-}
-
-static int rdt_read(__attribute__((unused)) user_data_t *ud) {
- int ret;
-
- if (g_rdt == NULL) {
- ERROR(RDT_PLUGIN ": rdt_read: plugin not initialized.");
- return -EINVAL;
+ if (0 == g_rdt->cores.num_cgroups) {
+ DEBUG(RDT_PLUGIN ": read_cores_data: not configured - Cores read skipped");
+ return 0;
}
+ DEBUG(RDT_PLUGIN ": read_cores_data: Cores data poll");
- ret = pqos_mon_poll(&g_rdt->pgroups[0], (unsigned)g_rdt->num_groups);
+ int ret =
+ pqos_mon_poll(&g_rdt->pcgroups[0], (unsigned)g_rdt->cores.num_cgroups);
if (ret != PQOS_RETVAL_OK) {
- ERROR(RDT_PLUGIN ": Failed to poll monitoring data.");
+ ERROR(RDT_PLUGIN ": read_cores_data: Failed to poll monitoring data for "
+ "cores. Error [%d].",
+ ret);
return -1;
}
-#if COLLECT_DEBUG
- rdt_dump_data();
-#endif /* COLLECT_DEBUG */
-
- for (size_t i = 0; i < g_rdt->num_groups; i++) {
+ for (size_t i = 0; i < g_rdt->cores.num_cgroups; i++) {
core_group_t *cgroup = g_rdt->cores.cgroups + i;
-
enum pqos_mon_event mbm_events =
(PQOS_MON_EVENT_LMEM_BW | PQOS_MON_EVENT_TMEM_BW |
PQOS_MON_EVENT_RMEM_BW);
- const struct pqos_event_values *pv = &g_rdt->pgroups[i]->values;
+ const struct pqos_event_values *pv = &g_rdt->pcgroups[i]->values;
/* Submit only monitored events data */
}
}
+#if COLLECT_DEBUG
+ rdt_dump_cores_data();
+#endif /* COLLECT_DEBUG */
+
return 0;
}
-static int rdt_init(void) {
- int ret;
+static int rdt_read(__attribute__((unused)) user_data_t *ud) {
- if (g_state == CONFIGURATION_ERROR)
- return -1;
+ if (g_rdt == NULL) {
+ ERROR(RDT_PLUGIN ": rdt_read: plugin not initialized.");
+ return -EINVAL;
+ }
- ret = rdt_preinit();
- if (ret != 0)
- return ret;
+ int cores_read_result = read_cores_data();
+
+#ifdef LIBPQOS2
+ int pids_read_result = read_pids_data();
+#endif /* LIBPQOS2 */
+
+ if (0 != cores_read_result)
+ return cores_read_result;
+
+#ifdef LIBPQOS2
+ if (0 != pids_read_result)
+ return pids_read_result;
+#endif /* LIBPQOS2 */
- /* Start monitoring */
- for (size_t i = 0; i < g_rdt->num_groups; i++) {
+ return 0;
+}
+
+static void rdt_init_cores_monitoring() {
+ for (size_t i = 0; i < g_rdt->cores.num_cgroups; i++) {
core_group_t *cg = g_rdt->cores.cgroups + i;
- ret = pqos_mon_start(cg->num_cores, cg->cores, g_rdt->events[i],
- (void *)cg->desc, g_rdt->pgroups[i]);
+ int mon_start_result =
+ pqos_mon_start(cg->num_cores, cg->cores, g_rdt->events[i],
+ (void *)cg->desc, g_rdt->pcgroups[i]);
- if (ret != PQOS_RETVAL_OK)
- ERROR(RDT_PLUGIN ": Error starting monitoring group %s (pqos status=%d)",
- cg->desc, ret);
+ if (mon_start_result != PQOS_RETVAL_OK)
+ ERROR(RDT_PLUGIN
+ ": Error starting cores monitoring group %s (pqos status=%d)",
+ cg->desc, mon_start_result);
}
+}
+
+static int rdt_init(void) {
+
+ if (g_state == CONFIGURATION_ERROR) {
+ if (g_rdt != NULL) {
+ if (g_rdt->cores.num_cgroups > 0)
+ rdt_free_cgroups();
+#ifdef LIBPQOS2
+ if (g_rdt->num_ngroups > 0)
+ rdt_free_ngroups(g_rdt);
+#endif
+ }
+ return -1;
+ }
+
+ int rdt_preinint_result = rdt_preinit();
+ if (rdt_preinint_result != 0)
+ return rdt_preinint_result;
+
+ rdt_init_cores_monitoring();
+#ifdef LIBPQOS2
+ rdt_init_pids_monitoring();
+#endif /* LIBPQOS2 */
return 0;
}
if (g_rdt == NULL)
return 0;
- /* Stop monitoring */
- for (size_t i = 0; i < g_rdt->num_groups; i++) {
- pqos_mon_stop(g_rdt->pgroups[i]);
+ /* Stop monitoring cores */
+ for (size_t i = 0; i < g_rdt->cores.num_cgroups; i++) {
+ pqos_mon_stop(g_rdt->pcgroups[i]);
}
+/* Stop pids monitoring */
+#ifdef LIBPQOS2
+ for (size_t i = 0; i < g_rdt->num_ngroups; i++)
+ pqos_mon_stop(g_rdt->pngroups[i]);
+#endif
+
ret = pqos_fini();
if (ret != PQOS_RETVAL_OK)
ERROR(RDT_PLUGIN ": Error shutting down PQoS library.");
-
rdt_free_cgroups();
+#ifdef LIBPQOS2
+ rdt_free_ngroups(g_rdt);
+#endif /* LIBPQOS2 */
sfree(g_rdt);
return 0;
--- /dev/null
+#include "intel_rdt.c" /* sic */
+#include "testing.h"
+
+/***************************************************************************
+ * PQOS mocks
+ */
+int pqos_mon_reset(void) { return 0; }
+int pqos_mon_assoc_get(const unsigned lcore, pqos_rmid_t *rmid) { return 0; }
+int pqos_mon_start(const unsigned num_cores, const unsigned *cores,
+ const enum pqos_mon_event event, void *context,
+ struct pqos_mon_data *group) {
+ return 0;
+}
+#if PQOS_VERSION >= 30000
+int pqos_mon_start_pids(const unsigned num_pids, const pid_t *pids,
+ const enum pqos_mon_event event, void *context,
+ struct pqos_mon_data *group) {
+ return 0;
+}
+int pqos_mon_add_pids(const unsigned num_pids, const pid_t *pids,
+ struct pqos_mon_data *group) {
+ return 0;
+}
+int pqos_mon_remove_pids(const unsigned num_pids, const pid_t *pids,
+ struct pqos_mon_data *group) {
+ return 0;
+}
+
+#else
+int pqos_mon_start_pid(const pid_t pids, const enum pqos_mon_event event,
+ void *context, struct pqos_mon_data *group) {
+ return 0;
+}
+#endif
+int pqos_mon_stop(struct pqos_mon_data *group) { return 0; }
+int pqos_mon_poll(struct pqos_mon_data **groups, const unsigned num_groups) {
+ return 0;
+}
+
+#if PQOS_VERSION >= 30000
+int pqos_alloc_reset(const enum pqos_cdp_config l3_cdp_cfg,
+ const enum pqos_cdp_config l2_cdp_cfg,
+ const enum pqos_mba_config mba_cfg) {
+ return 0;
+}
+#elif PQOS_VERSION >= 20000
+int pqos_alloc_reset(const enum pqos_cdp_config l3_cdp_cfg,
+ const enum pqos_cdp_config l2_cdp_cfg) {
+ return 0;
+}
+#else
+int pqos_alloc_reset(const enum pqos_cdp_config l3_cdp_cfg) { return 0; }
+#endif
+int pqos_alloc_assoc_set(const unsigned lcore, const unsigned class_id) {
+ return 0;
+}
+int pqos_alloc_assoc_get(const unsigned lcore, unsigned *class_id) { return 0; }
+int pqos_alloc_assoc_set_pid(const pid_t task, const unsigned class_id) {
+ return 0;
+}
+int pqos_alloc_assoc_get_pid(const pid_t task, unsigned *class_id) { return 0; }
+int pqos_alloc_assign(const unsigned technology, const unsigned *core_array,
+ const unsigned core_num, unsigned *class_id) {
+ return 0;
+}
+int pqos_alloc_release(const unsigned *core_array, const unsigned core_num) {
+ return 0;
+}
+int pqos_alloc_assign_pid(const unsigned technology, const pid_t *task_array,
+ const unsigned task_num, unsigned *class_id) {
+ return 0;
+}
+int pqos_alloc_release_pid(const pid_t *task_array, const unsigned task_num) {
+ return 0;
+}
+int pqos_init(const struct pqos_config *config) { return 0; }
+int pqos_fini(void) { return 0; }
+int pqos_cap_get_type(const struct pqos_cap *cap, const enum pqos_cap_type type,
+ const struct pqos_capability **cap_item) {
+ return 0;
+}
+int pqos_cap_get(const struct pqos_cap **cap, const struct pqos_cpuinfo **cpu) {
+ return 0;
+}
+
+#ifdef LIBPQOS2
+/***************************************************************************
+ * helper functions
+ */
+rdt_ctx_t *stub_rdt_setup() {
+
+ rdt_ctx_t *rdt = calloc(1, sizeof(*rdt));
+ struct pqos_cpuinfo *pqos_cpu = calloc(1, sizeof(*pqos_cpu));
+ struct pqos_cap *pqos_cap = calloc(1, sizeof(*pqos_cap));
+ struct pqos_cap_mon *mon = calloc(1, sizeof(*mon));
+ struct pqos_capability *cap_mon = calloc(1, sizeof(*cap_mon));
+
+ cap_mon->u.mon = mon;
+ rdt->pqos_cap = pqos_cap;
+ rdt->pqos_cpu = pqos_cpu;
+ rdt->cap_mon = cap_mon;
+
+ return rdt;
+}
+
+void stub_rdt_teardown(rdt_ctx_t *rdt) {
+ free(rdt->cap_mon->u.mon);
+ free((void *)rdt->cap_mon);
+ free((void *)rdt->pqos_cpu);
+ free((void *)rdt->pqos_cap);
+ free(rdt);
+}
+
+/***************************************************************************
+ * tests
+ */
+DEF_TEST(rdt_config_ngroups__one_process) {
+ /* setup */
+ rdt_ctx_t *rdt = stub_rdt_setup();
+
+ oconfig_value_t values[] = {
+ {.value.string = "proc1", .type = OCONFIG_TYPE_STRING},
+ };
+ oconfig_item_t config_item = {
+ .values = values,
+ .values_num = STATIC_ARRAY_SIZE(values),
+ };
+
+ /* check */
+ int result = rdt_config_ngroups(rdt, &config_item);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_STR(values[0].value.string, rdt->ngroups[0].desc);
+ EXPECT_EQ_INT(1, rdt->num_ngroups);
+
+ /* cleanup */
+ rdt_free_ngroups(rdt);
+ stub_rdt_teardown(rdt);
+
+ return 0;
+}
+
+DEF_TEST(rdt_config_ngroups__two_groups) {
+ /* setup */
+ rdt_ctx_t *rdt = stub_rdt_setup();
+
+ oconfig_value_t values[] = {
+ {.value.string = "proc11,proc12,proc13", .type = OCONFIG_TYPE_STRING},
+ {.value.string = "proc21,proc22,proc23", .type = OCONFIG_TYPE_STRING},
+ };
+ oconfig_item_t config_item = {
+ .values = values,
+ .values_num = STATIC_ARRAY_SIZE(values),
+ };
+
+ /* check */
+ int result = rdt_config_ngroups(rdt, &config_item);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_INT(2, rdt->num_ngroups);
+ EXPECT_EQ_STR("proc11,proc12,proc13", rdt->ngroups[0].desc);
+ EXPECT_EQ_STR("proc21,proc22,proc23", rdt->ngroups[1].desc);
+ EXPECT_EQ_STR("proc11", rdt->ngroups[0].names[0]);
+ EXPECT_EQ_STR("proc12", rdt->ngroups[0].names[1]);
+ EXPECT_EQ_STR("proc13", rdt->ngroups[0].names[2]);
+ EXPECT_EQ_STR("proc21", rdt->ngroups[1].names[0]);
+ EXPECT_EQ_STR("proc22", rdt->ngroups[1].names[1]);
+ EXPECT_EQ_STR("proc23", rdt->ngroups[1].names[2]);
+
+ /* cleanup */
+ rdt_free_ngroups(rdt);
+ stub_rdt_teardown(rdt);
+
+ return 0;
+}
+
+DEF_TEST(rdt_config_ngroups__too_long_proc_name) {
+ /* setup */
+ rdt_ctx_t *rdt = stub_rdt_setup();
+
+ oconfig_value_t values[] = {
+ {.value.string = "_seventeen_chars_", .type = OCONFIG_TYPE_STRING},
+ };
+ oconfig_item_t config_item = {
+ .values = values,
+ .values_num = STATIC_ARRAY_SIZE(values),
+ };
+
+ /* check */
+ int result = rdt_config_ngroups(rdt, &config_item);
+ EXPECT_EQ_INT(-EINVAL, result);
+
+ /* cleanup */
+ stub_rdt_teardown(rdt);
+
+ return 0;
+}
+
+DEF_TEST(rdt_config_ngroups__duplicate_proc_name_between_groups) {
+ /* setup */
+ rdt_ctx_t *rdt = stub_rdt_setup();
+
+ oconfig_value_t values[] = {
+ {.value.string = "proc11,proc12,proc", .type = OCONFIG_TYPE_STRING},
+ {.value.string = "proc21,proc,proc23", .type = OCONFIG_TYPE_STRING},
+ };
+ oconfig_item_t config_item = {
+ .values = values,
+ .values_num = STATIC_ARRAY_SIZE(values),
+ };
+
+ /* check */
+ int result = rdt_config_ngroups(rdt, &config_item);
+ EXPECT_EQ_INT(-EINVAL, result);
+
+ /* cleanup */
+ stub_rdt_teardown(rdt);
+
+ return 0;
+}
+
+DEF_TEST(rdt_config_ngroups__duplicate_proc_name_in_group) {
+ /* setup */
+ rdt_ctx_t *rdt = stub_rdt_setup();
+
+ oconfig_value_t values[] = {
+ {.value.string = "proc11,proc,proc,proc14", .type = OCONFIG_TYPE_STRING},
+ };
+ oconfig_item_t config_item = {
+ .values = values,
+ .values_num = STATIC_ARRAY_SIZE(values),
+ };
+
+ /* check */
+ int result = rdt_config_ngroups(rdt, &config_item);
+ EXPECT_EQ_INT(-EINVAL, result);
+
+ /* cleanup */
+ stub_rdt_teardown(rdt);
+
+ return 0;
+}
+
+DEF_TEST(rdt_config_ngroups__empty_group) {
+ /* setup */
+ rdt_ctx_t *rdt = stub_rdt_setup();
+
+ oconfig_value_t values[] = {
+ {.value.string = "proc11,proc12,proc13", .type = OCONFIG_TYPE_STRING},
+ {.value.string = "", .type = OCONFIG_TYPE_STRING},
+
+ };
+ oconfig_item_t config_item = {
+ .values = values,
+ .values_num = STATIC_ARRAY_SIZE(values),
+ };
+
+ /* check */
+ int result = rdt_config_ngroups(rdt, &config_item);
+ EXPECT_EQ_INT(-EINVAL, result);
+
+ /* cleanup */
+ stub_rdt_teardown(rdt);
+
+ return 0;
+}
+
+DEF_TEST(rdt_config_ngroups__empty_proc_name) {
+ /* setup */
+ rdt_ctx_t *rdt = stub_rdt_setup();
+
+ oconfig_value_t values[] = {
+ {.value.string = "proc11,,proc13", .type = OCONFIG_TYPE_STRING},
+ };
+ oconfig_item_t config_item = {
+ .values = values,
+ .values_num = STATIC_ARRAY_SIZE(values),
+ };
+
+ /* check */
+ int result = rdt_config_ngroups(rdt, &config_item);
+ EXPECT_EQ_INT(-EINVAL, result);
+
+ /* cleanup */
+ stub_rdt_teardown(rdt);
+
+ return 0;
+}
+
+int main(void) {
+ RUN_TEST(rdt_config_ngroups__one_process);
+ RUN_TEST(rdt_config_ngroups__two_groups);
+ RUN_TEST(rdt_config_ngroups__too_long_proc_name);
+ RUN_TEST(rdt_config_ngroups__duplicate_proc_name_between_groups);
+ RUN_TEST(rdt_config_ngroups__duplicate_proc_name_in_group);
+ RUN_TEST(rdt_config_ngroups__empty_group);
+ RUN_TEST(rdt_config_ngroups__empty_proc_name);
+ END_TEST;
+}
+
+#else
+DEF_TEST(pqos12_test_stub) {
+ EXPECT_EQ_INT(0, 0);
+ return 0;
+}
+
+int main(void) {
+ RUN_TEST(pqos12_test_stub);
+ END_TEST;
+}
+#endif
* (Module-)Global variables
*/
static const char *config_keys[] = {
- "Interface", "IgnoreSelected", "ReportInactive",
+ "Interface",
+ "IgnoreSelected",
+ "ReportInactive",
};
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
derive_t tx) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
if (ignorelist_match(ignorelist, dev) != 0)
#define IFA_TX_PACKT ifi_opackets
#define IFA_RX_ERROR ifi_ierrors
#define IFA_TX_ERROR ifi_oerrors
-/* #endif HAVE_STRUCT_IF_DATA */
+ /* #endif HAVE_STRUCT_IF_DATA */
#elif HAVE_STRUCT_NET_DEVICE_STATS
#define IFA_DATA net_device_stats
}
freeifaddrs(if_list);
-/* #endif HAVE_GETIFADDRS */
+ /* #endif HAVE_GETIFADDRS */
#elif KERNEL_LINUX
FILE *fh;
}
fclose(fh);
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
derive_t rx;
continue;
if (unique_name)
- snprintf(iname, sizeof(iname), "%s_%d_%s", ksp[i]->ks_module,
- ksp[i]->ks_instance, ksp[i]->ks_name);
+ ssnprintf(iname, sizeof(iname), "%s_%d_%s", ksp[i]->ks_module,
+ ksp[i]->ks_instance, ksp[i]->ks_name);
else
sstrncpy(iname, ksp[i]->ks_name, sizeof(iname));
if ((rx != -1LL) || (tx != -1LL))
if_submit(iname, "if_errors", rx, tx);
}
-/* #endif HAVE_LIBKSTAT */
+ /* #endif HAVE_LIBKSTAT */
#elif defined(HAVE_LIBSTATGRAB)
sg_network_io_stats *ios;
continue;
if_submit(ios[i].interface_name, "if_octets", ios[i].rx, ios[i].tx);
}
-/* #endif HAVE_LIBSTATGRAB */
+ /* #endif HAVE_LIBSTATGRAB */
#elif defined(HAVE_PERFSTAT)
perfstat_id_t id;
pagesize_g = sysconf(_SC_PAGESIZE);
return 0;
}
-/* }}} */
-/* #endif KERNEL_LINUX */
+ /* }}} */
+ /* #endif KERNEL_LINUX */
#elif KERNEL_AIX
static caddr_t ipc_get_info(cid_t cid, int cmd, int version, int stsize,
}
if (errbuf[0] == 0) {
- snprintf(errbuf, sizeof(errbuf), "Unknown error %#x", status);
+ ssnprintf(errbuf, sizeof(errbuf), "Unknown error %#x", status);
}
errbuf[sizeof(errbuf) - 1] = '\0';
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",
- list_item->sensor_name);
+ ssnprintf(n.message, sizeof(n.message), "sensor %s not present",
+ list_item->sensor_name);
plugin_dispatch_notification(&n);
}
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",
- list_item->sensor_name);
+ ssnprintf(n.message, sizeof(n.message), "sensor %s present",
+ list_item->sensor_name);
plugin_dispatch_notification(&n);
}
temp[sizeof(temp) - 1] = '\0';
if (entity_id_string != NULL && strlen(temp))
- snprintf(sensor_name, sizeof(sensor_name), "%s %s", temp, entity_id_string);
+ ssnprintf(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
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);
+ ssnprintf(sensor_name, sizeof(sensor_name), "%s %s", sensor_name_ptr,
+ sensor_id_ptr);
}
/* else: don't touch sensor_name. */
}
/* 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);
+ ssnprintf(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(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);
+ ssnprintf(n.message, sizeof(n.message), "sensor %s added",
+ list_item->sensor_name);
plugin_dispatch_notification(&n);
}
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);
+ ssnprintf(n.message, sizeof(n.message), "sensor %s removed",
+ list_item->sensor_name);
plugin_dispatch_notification(&n);
}
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);
+ ssnprintf(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);
+ ssnprintf(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);
/* 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);
+ ssnprintf(buf, sizeof(buf), "0x%2.2x", raw_value);
plugin_notification_meta_add_string(&n, "raw", buf);
} break;
default:
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);
+ ssnprintf(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);
/* 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);
+ ssnprintf(callback_name, sizeof(callback_name), "ipmi/%s", st->name);
user_data_t ud = {
.data = st,
sstrncpy(vl.plugin, "ip6tables", sizeof(vl.plugin));
- status = snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s",
- chain->table, chain->chain);
+ status = ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s",
+ chain->table, chain->chain);
if ((status < 1) || ((unsigned int)status >= sizeof(vl.plugin_instance)))
return 0;
sstrncpy(vl.type_instance, chain->name, sizeof(vl.type_instance));
} else {
if (chain->rule_type == RTYPE_NUM)
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%i",
- chain->rule.num);
+ ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%i",
+ chain->rule.num);
else
sstrncpy(vl.type_instance, (char *)match->data, sizeof(vl.type_instance));
}
sstrncpy(vl.plugin, "iptables", sizeof(vl.plugin));
- status = snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s",
- chain->table, chain->chain);
+ status = ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s",
+ chain->table, chain->chain);
if ((status < 1) || ((unsigned int)status >= sizeof(vl.plugin_instance)))
return 0;
sstrncpy(vl.type_instance, chain->name, sizeof(vl.type_instance));
} else {
if (chain->rule_type == RTYPE_NUM)
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%i",
- chain->rule.num);
+ ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%i",
+ chain->rule.num);
else
sstrncpy(vl.type_instance, (char *)match->data, sizeof(vl.type_instance));
}
static void cipvs_submit_if(const char *pi, const char *t, const char *ti,
derive_t rx, derive_t tx) {
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
value_list_t vl = VALUE_LIST_INIT;
/* group = */ NULL, cbi->name, cjni_read,
/* interval = */ 0,
&(user_data_t){
- .data = cbi, .free_func = cjni_callback_info_destroy,
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
});
(*jvm_env)->DeleteLocalRef(jvm_env, o_read);
DEBUG("java plugin: Registering new write callback: %s", cbi->name);
- plugin_register_write(
- cbi->name, cjni_write,
- &(user_data_t){
- .data = cbi, .free_func = cjni_callback_info_destroy,
- });
+ plugin_register_write(cbi->name, cjni_write,
+ &(user_data_t){
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef(jvm_env, o_write);
DEBUG("java plugin: Registering new flush callback: %s", cbi->name);
- plugin_register_flush(
- cbi->name, cjni_flush,
- &(user_data_t){
- .data = cbi, .free_func = cjni_callback_info_destroy,
- });
+ plugin_register_flush(cbi->name, cjni_flush,
+ &(user_data_t){
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef(jvm_env, o_flush);
plugin_register_log(cbi->name, cjni_log,
&(user_data_t){
- .data = cbi, .free_func = cjni_callback_info_destroy,
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
});
(*jvm_env)->DeleteLocalRef(jvm_env, o_log);
DEBUG("java plugin: Registering new notification callback: %s", cbi->name);
- plugin_register_notification(
- cbi->name, cjni_notification,
- &(user_data_t){
- .data = cbi, .free_func = cjni_callback_info_destroy,
- });
+ plugin_register_notification(cbi->name, cjni_notification,
+ &(user_data_t){
+ .data = cbi,
+ .free_func = cjni_callback_info_destroy,
+ });
(*jvm_env)->DeleteLocalRef(jvm_env, o_notification);
"(Ljava/lang/String;Lorg/collectd/api/CollectdLogInterface;)I",
cjni_api_register_log},
- {"registerNotification", "(Ljava/lang/String;Lorg/collectd/api/"
- "CollectdNotificationInterface;)I",
+ {"registerNotification",
+ "(Ljava/lang/String;Lorg/collectd/api/"
+ "CollectdNotificationInterface;)I",
cjni_api_register_notification},
- {"registerMatch", "(Ljava/lang/String;Lorg/collectd/api/"
- "CollectdMatchFactoryInterface;)I",
+ {"registerMatch",
+ "(Ljava/lang/String;Lorg/collectd/api/"
+ "CollectdMatchFactoryInterface;)I",
cjni_api_register_match},
- {"registerTarget", "(Ljava/lang/String;Lorg/collectd/api/"
- "CollectdTargetFactoryInterface;)I",
+ {"registerTarget",
+ "(Ljava/lang/String;Lorg/collectd/api/"
+ "CollectdTargetFactoryInterface;)I",
cjni_api_register_target},
{"log", "(ILjava/lang/String;)V", cjni_api_log},
class->object = NULL;
if (class->object == NULL) {
ERROR("java plugin: cjni_config_load_plugin: "
- "Could create a new `%s' object.",
+ "Could not create a new `%s' object.",
class->name);
cjni_thread_detach();
free(class->name);
#if !HAVE_STRERROR_R
snprintf(buf, buflen, "Error #%i; strerror_r is not available.", errnum);
-/* #endif !HAVE_STRERROR_R */
+ /* #endif !HAVE_STRERROR_R */
#elif STRERROR_R_CHAR_P
{
if ((temp != NULL) && (temp != buf) && (temp[0] != 0))
strncpy(buf, temp, buflen);
else
- strncpy(buf, "strerror_r did not return "
- "an error message",
+ strncpy(buf,
+ "strerror_r did not return "
+ "an error message",
buflen);
}
}
-/* #endif STRERROR_R_CHAR_P */
+ /* #endif STRERROR_R_CHAR_P */
#else
if (strerror_r(errnum, buf, buflen) != 0) {
- snprintf(buf, buflen, "Error #%i; "
- "Additionally, strerror_r failed.",
+ snprintf(buf, buflen,
+ "Error #%i; "
+ "Additionally, strerror_r failed.",
errnum);
}
#endif /* STRERROR_R_CHAR_P */
size_t out_size) {
char *in = payload;
- if ((payload_size < 1) || (in[payload_size - 1] != 0) ||
+ if ((payload_size < 1) || (in[payload_size - 1] != '\0') ||
(payload_size > out_size))
return EINVAL;
- strncpy(out, in, out_size);
+ strncpy(out, in, out_size - 1);
+ out[out_size - 1] = '\0';
return 0;
}
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,
+ .data = payload,
+ .len = payload_size,
};
uint16_t n;
}
buffer_t *b = &(buffer_t){
- .data = signature, .len = signature_len,
+ .data = signature,
+ .len = signature_len,
};
uint8_t hash[32];
}
buffer_t *b = &(buffer_t){
- .data = data, .len = data_size,
+ .data = data,
+ .len = data_size,
};
uint16_t username_len;
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,
+ .data = data,
+ .len = data_size,
};
lcc_value_list_t state = {0};
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",
+ 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,
- });
+ 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",
int status = decrypt_aes256(
&(buffer_t){
- .data = ciphertext, .len = ciphertext_len,
+ .data = ciphertext,
+ .len = ciphertext_len,
},
iv, iv_len, "admin");
if (status != 0) {
#ifndef AUX_TYPES_H
#define AUX_TYPES_H 1
-struct statement_list_s
-{
- oconfig_item_t *statement;
- int statement_num;
+struct statement_list_s {
+ oconfig_item_t *statement;
+ int statement_num;
};
typedef struct statement_list_s statement_list_t;
-struct argument_list_s
-{
- oconfig_value_t *argument;
- int argument_num;
+struct argument_list_s {
+ oconfig_value_t *argument;
+ int argument_num;
};
typedef struct argument_list_s argument_list_t;
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
static int load_config(const char *key, const char *value) {
- if (strcasecmp(key, "ReportRelative") == 0)
+ if (strcasecmp(key, "ReportRelative") == 0) {
#ifdef _SC_NPROCESSORS_ONLN
report_relative_load = IS_TRUE(value);
#else
"is not available, because I can't determine the "
"number of CPUS on this system. Sorry.");
#endif
+ return 0;
+ }
return -1;
}
static void load_submit(gauge_t snum, gauge_t mnum, gauge_t lnum) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.gauge = snum}, {.gauge = mnum}, {.gauge = lnum},
+ {.gauge = snum},
+ {.gauge = mnum},
+ {.gauge = lnum},
};
vl.values = values;
else {
WARNING("load: getloadavg failed: %s", STRERRNO);
}
-/* #endif HAVE_GETLOADAVG */
+ /* #endif HAVE_GETLOADAVG */
#elif defined(KERNEL_LINUX)
gauge_t snum, mnum, lnum;
lnum = atof(fields[2]);
load_submit(snum, mnum, lnum);
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBSTATGRAB
gauge_t snum, mnum, lnum;
mnum = ls->min5;
lnum = ls->min15;
load_submit(snum, mnum, lnum);
-/* #endif HAVE_LIBSTATGRAB */
+ /* #endif HAVE_LIBSTATGRAB */
#elif HAVE_PERFSTAT
gauge_t snum, mnum, lnum;
mnum = (float)cputotal.loadavg[1] / (float)(1 << SBITS);
lnum = (float)cputotal.loadavg[2] / (float)(1 << SBITS);
load_submit(snum, mnum, lnum);
-/* #endif HAVE_PERFSTAT */
+ /* #endif HAVE_PERFSTAT */
#else
#error "No applicable input method."
log_level = parse_log_severity(value);
if (log_level < 0) {
log_level = LOG_INFO;
- ERROR("logfile: invalid loglevel [%s] defaulting to 'info'", value);
- return 1;
+ WARNING("logfile: invalid loglevel [%s] defaulting to 'info'", value);
+ return 0;
}
} else if (0 == strcasecmp(key, "File")) {
sfree(log_file);
if (pool_busy_cpus < 0.0)
pool_busy_cpus = 0.0;
- snprintf(typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id);
+ ssnprintf(typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id);
lpar_submit(typinst, pool_busy_cpus);
- snprintf(typinst, sizeof(typinst), "pool-%X-idle", lparstats.pool_id);
+ ssnprintf(typinst, sizeof(typinst), "pool-%X-idle", lparstats.pool_id);
lpar_submit(typinst, pool_idle_cpus);
}
#include <pthread.h>
+#define PLUGIN_READ 1
+#define PLUGIN_WRITE 2
+
typedef struct lua_script_s {
- char *script_path;
lua_State *lua_state;
struct lua_script_s *next;
} lua_script_t;
typedef struct {
lua_State *lua_state;
- const char *lua_function_name;
+ char *lua_function_name;
pthread_mutex_t lock;
int callback_id;
} clua_callback_data_t;
* garbage collector. */
static int clua_store_thread(lua_State *L, int idx) /* {{{ */
{
- if (idx < 0)
- idx += lua_gettop(L) + 1;
-
- /* Copy the thread pointer */
- lua_pushvalue(L, idx); /* +1 = 3 */
- if (!lua_isthread(L, -1)) {
- lua_pop(L, 3); /* -3 = 0 */
+ if (!lua_isthread(L, idx)) {
return -1;
}
+ /* Copy the thread pointer */
+ lua_pushvalue(L, idx);
+
luaL_ref(L, LUA_REGISTRYINDEX);
- lua_pop(L, 1); /* -1 = 0 */
return 0;
} /* }}} int clua_store_thread */
return 0;
} /* }}} lua_cb_dispatch_values */
-static int lua_cb_register_read(lua_State *L) /* {{{ */
+static void lua_cb_free(void *data) {
+ clua_callback_data_t *cb = data;
+ free(cb->lua_function_name);
+ pthread_mutex_destroy(&cb->lock);
+ free(cb);
+}
+
+static int lua_cb_register_generic(lua_State *L, int type) /* {{{ */
{
int nargs = lua_gettop(L);
if (nargs != 1)
return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
- luaL_checktype(L, 1, LUA_TFUNCTION);
-
- char function_name[DATA_MAX_NAME_LEN];
- snprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
-
- int callback_id = clua_store_callback(L, 1);
- if (callback_id < 0)
- return luaL_error(L, "%s", "Storing callback function failed");
-
- lua_State *thread = lua_newthread(L);
- if (thread == NULL)
- return luaL_error(L, "%s", "lua_newthread failed");
- clua_store_thread(L, -1);
- lua_pop(L, 1);
-
- clua_callback_data_t *cb = calloc(1, sizeof(*cb));
- if (cb == NULL)
- return luaL_error(L, "%s", "calloc failed");
-
- cb->lua_state = thread;
- cb->callback_id = callback_id;
- cb->lua_function_name = strdup(function_name);
- pthread_mutex_init(&cb->lock, NULL);
-
- int status = plugin_register_complex_read(/* group = */ "lua",
- /* name = */ function_name,
- /* callback = */ clua_read,
- /* interval = */ 0,
- &(user_data_t){
- .data = cb,
- });
+ char subname[DATA_MAX_NAME_LEN];
+ if (!lua_isfunction(L, 1) && lua_isstring(L, 1)) {
+ const char *fname = lua_tostring(L, 1);
+ ssnprintf(subname, sizeof(subname), "%s()", fname);
- if (status != 0)
- return luaL_error(L, "%s", "plugin_register_complex_read failed");
- return 0;
-} /* }}} int lua_cb_register_read */
-
-static int lua_cb_register_write(lua_State *L) /* {{{ */
-{
- int nargs = lua_gettop(L);
-
- if (nargs != 1)
- return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+ lua_getglobal(L, fname); // Push function into stack
+ lua_remove(L, 1); // Remove string from stack
+ if (!lua_isfunction(L, -1)) {
+ return luaL_error(L, "Unable to find function '%s'", fname);
+ }
+ } else {
+ lua_getfield(L, LUA_REGISTRYINDEX, "collectd:callback_num");
+ int tmp = lua_tointeger(L, -1);
+ ssnprintf(subname, sizeof(subname), "callback_%d", tmp);
+ lua_pop(L, 1); // Remove old value from stack
+ lua_pushinteger(L, tmp + 1);
+ lua_setfield(L, LUA_REGISTRYINDEX, "collectd:callback_num"); // pops value
+ }
luaL_checktype(L, 1, LUA_TFUNCTION);
- char function_name[DATA_MAX_NAME_LEN] = "";
- snprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
+ lua_getfield(L, LUA_REGISTRYINDEX, "collectd:script_path");
+ char function_name[DATA_MAX_NAME_LEN];
+ ssnprintf(function_name, sizeof(function_name), "lua/%s/%s",
+ lua_tostring(L, -1), subname);
+ lua_pop(L, 1);
int callback_id = clua_store_callback(L, 1);
if (callback_id < 0)
cb->lua_function_name = strdup(function_name);
pthread_mutex_init(&cb->lock, NULL);
- int status = plugin_register_write(/* name = */ function_name,
- /* callback = */ clua_write,
- &(user_data_t){
- .data = cb,
- });
+ if (PLUGIN_READ == type) {
+ int status = plugin_register_complex_read(/* group = */ "lua",
+ /* name = */ function_name,
+ /* callback = */ clua_read,
+ /* interval = */ 0,
+ &(user_data_t){
+ .data = cb,
+ .free_func = lua_cb_free,
+ });
+
+ if (status != 0)
+ return luaL_error(L, "%s", "plugin_register_complex_read failed");
+ return 0;
+ } else if (PLUGIN_WRITE == type) {
+ int status = plugin_register_write(/* name = */ function_name,
+ /* callback = */ clua_write,
+ &(user_data_t){
+ .data = cb,
+ .free_func = lua_cb_free,
+ });
+
+ if (status != 0)
+ return luaL_error(L, "%s", "plugin_register_write failed");
+ return 0;
+ } else {
+ return luaL_error(L, "%s", "lua_cb_register_generic unsupported type");
+ }
+} /* }}} int lua_cb_register_generic */
- if (status != 0)
- return luaL_error(L, "%s", "plugin_register_write failed");
- return 0;
-} /* }}} int lua_cb_register_write */
+static int lua_cb_register_read(lua_State *L) {
+ return lua_cb_register_generic(L, PLUGIN_READ);
+}
+
+static int lua_cb_register_write(lua_State *L) {
+ return lua_cb_register_generic(L, PLUGIN_WRITE);
+}
static const luaL_Reg collectdlib[] = {
{"log_debug", lua_cb_log_debug},
script->lua_state = NULL;
}
- sfree(script->script_path);
sfree(script);
lua_script_free(next);
return status;
}
- script->script_path = strdup(script_path);
- if (script->script_path == NULL) {
- ERROR("Lua plugin: strdup failed.");
- lua_script_free(script);
- return -1;
- }
-
- status = luaL_loadfile(script->lua_state, script->script_path);
+ status = luaL_loadfile(script->lua_state, script_path);
if (status != 0) {
ERROR("Lua plugin: luaL_loadfile failed: %s",
lua_tostring(script->lua_state, -1));
return -1;
}
+ lua_pushstring(script->lua_state, script_path);
+ lua_setfield(script->lua_state, LUA_REGISTRYINDEX, "collectd:script_path");
+ lua_pushinteger(script->lua_state, 0);
+ lua_setfield(script->lua_state, LUA_REGISTRYINDEX, "collectd:callback_num");
+
status = lua_pcall(script->lua_state,
/* nargs = */ 0,
/* nresults = */ LUA_MULTRET,
"In addition, no error message could be retrieved from the stack.",
status);
else
- ERROR("Lua plugin: Executing script \"%s\" failed:\n%s",
- script->script_path, errmsg);
-
- lua_script_free(script);
- return -1;
+ ERROR("Lua plugin: Executing script \"%s\" failed: %s", script_path,
+ errmsg);
}
/* Append this script to the global list of scripts. */
scripts = script;
}
+ if (status != 0)
+ return -1;
+
return 0;
} /* }}} int lua_script_load */
if (base_path[0] == '\0')
sstrncpy(abs_path, rel_path, sizeof(abs_path));
else
- snprintf(abs_path, sizeof(abs_path), "%s/%s", base_path, rel_path);
+ ssnprintf(abs_path, sizeof(abs_path), "%s/%s", base_path, rel_path);
DEBUG("Lua plugin: abs_path = \"%s\";", abs_path);
+++ /dev/null
-/**
- * collectd - src/lvm.c
- * Copyright (C) 2013 Chad Malfait
- * Copyright (C) 2014 Carnegie Mellon University
- *
- * 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:
- * Chad Malfait <malfaitc at yahoo.com>
- * Benjamin Gilbert <bgilbert at backtick.net>
- **/
-
-#include "collectd.h"
-
-#include "plugin.h"
-#include "utils/common/common.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
-
-static uint64_t get_lv_property_int(lv_t lv, char const *property) {
- lvm_property_value_t v;
-
- v = lvm_lv_get_property(lv, property);
- if (!v.is_valid || !v.is_integer)
- return NO_VALUE;
- /* May be NO_VALUE if @property does not apply to this LV */
- return v.value.integer;
-}
-
-static char const *get_lv_property_string(lv_t lv, char const *property) {
- lvm_property_value_t v;
-
- v = lvm_lv_get_property(lv, property);
- if (!v.is_valid || !v.is_string)
- return NULL;
- return v.value.string;
-}
-
-static void lvm_submit(char const *plugin_instance, char const *type_instance,
- uint64_t ivalue) {
- value_list_t vl = VALUE_LIST_INIT;
-
- vl.values = &(value_t){.gauge = (gauge_t)ivalue};
- vl.values_len = 1;
-
- sstrncpy(vl.plugin, "lvm", sizeof(vl.plugin));
- sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
- sstrncpy(vl.type, "df_complex", sizeof(vl.type));
- sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
-
- plugin_dispatch_values(&vl);
-}
-
-static void report_lv_utilization(lv_t lv, char const *vg_name,
- char const *lv_name, uint64_t lv_size,
- char const *used_percent_property) {
- uint64_t used_percent_unscaled;
- uint64_t used_bytes;
- char plugin_instance[DATA_MAX_NAME_LEN];
-
- used_percent_unscaled = get_lv_property_int(lv, used_percent_property);
- if (used_percent_unscaled == NO_VALUE)
- return;
- used_bytes = lv_size * (used_percent_unscaled * PERCENT_SCALE_FACTOR);
-
- snprintf(plugin_instance, sizeof(plugin_instance), "%s-%s", vg_name, lv_name);
- lvm_submit(plugin_instance, "used", used_bytes);
- lvm_submit(plugin_instance, "free", lv_size - used_bytes);
-}
-
-static void report_thin_pool_utilization(lv_t lv, char const *vg_name,
- uint64_t lv_size) {
- char const *data_lv;
- char const *metadata_lv;
- uint64_t metadata_size;
-
- data_lv = get_lv_property_string(lv, "data_lv");
- metadata_lv = get_lv_property_string(lv, "metadata_lv");
- metadata_size = get_lv_property_int(lv, "lv_metadata_size");
- if (data_lv == NULL || metadata_lv == NULL || metadata_size == NO_VALUE)
- return;
-
- report_lv_utilization(lv, vg_name, data_lv, lv_size, "data_percent");
- report_lv_utilization(lv, vg_name, metadata_lv, metadata_size,
- "metadata_percent");
-}
-
-static void vg_read(vg_t vg, char const *vg_name) {
- struct dm_list *lvs;
- struct lvm_lv_list *lvl;
- char const *name;
- char const *attrs;
- uint64_t size;
-
- lvm_submit(vg_name, "free", lvm_vg_get_free_size(vg));
-
- lvs = lvm_vg_list_lvs(vg);
- if (!lvs) {
- /* no VGs are defined, which is not an error per se */
- return;
- }
-
- dm_list_iterate_items(lvl, lvs) {
- name = lvm_lv_get_name(lvl->lv);
- attrs = get_lv_property_string(lvl->lv, "lv_attr");
- size = lvm_lv_get_size(lvl->lv);
- if (name == NULL || attrs == NULL || size == NO_VALUE)
- continue;
-
- /* Condition on volume type. We want the reported sizes in the
- volume group to sum to the size of the volume group, so we ignore
- virtual volumes. */
- switch (attrs[0]) {
- case 's':
- case 'S':
- /* Snapshot. Also report used/free space. */
- report_lv_utilization(lvl->lv, vg_name, name, size, "data_percent");
- break;
- case 't':
- /* Thin pool virtual volume. We report the underlying data
- and metadata volumes, not this one. Report used/free
- space, then ignore. */
- report_thin_pool_utilization(lvl->lv, vg_name, size);
- continue;
- case 'v':
- /* Virtual volume. Ignore. */
- continue;
- case 'V':
- /* Thin volume or thin snapshot. Ignore. */
- continue;
- }
- lvm_submit(vg_name, name, size);
- }
-}
-
-static int lvm_read(void) {
- lvm_t lvm;
- struct dm_list *vg_names;
- struct lvm_str_list *name_list;
-
- lvm = lvm_init(NULL);
- if (!lvm) {
- ERROR("lvm plugin: lvm_init failed.");
- return -1;
- }
-
- vg_names = lvm_list_vg_names(lvm);
- if (!vg_names) {
- ERROR("lvm plugin lvm_list_vg_name failed %s", lvm_errmsg(lvm));
- lvm_quit(lvm);
- return -1;
- }
-
- dm_list_iterate_items(name_list, vg_names) {
- vg_t vg;
-
- vg = lvm_vg_open(lvm, name_list->str, "r", 0);
- if (!vg) {
- ERROR("lvm plugin: lvm_vg_open (%s) failed: %s", name_list->str,
- lvm_errmsg(lvm));
- continue;
- }
-
- vg_read(vg, name_list->str);
- lvm_vg_close(vg);
- }
-
- lvm_quit(lvm);
- 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 */
static void submit_derive2(const char *dev, const char *type, const char *ti1,
const char *ti2, derive_t val1, derive_t val2) {
value_t values[] = {
- {.derive = val1}, {.derive = val2},
+ {.derive = val1},
+ {.derive = val2},
};
submit(dev, type, ti1, ti2, values, STATIC_ARRAY_SIZE(values));
#ifndef MADWIFI_H
#define MADWIFI_H
-#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
-#define IEEE80211_RATE_VAL 0x7f
-#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */
-#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */
-
+#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
+#define IEEE80211_RATE_VAL 0x7f
+#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */
+#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */
/*
* Per/node (station) statistics available when operating as an AP.
*/
struct ieee80211_nodestats {
- u_int32_t ns_rx_data; /* rx data frames */
- u_int32_t ns_rx_mgmt; /* rx management frames */
- u_int32_t ns_rx_ctrl; /* rx control frames */
- u_int32_t ns_rx_ucast; /* rx unicast frames */
- u_int32_t ns_rx_mcast; /* rx multi/broadcast frames */
- u_int64_t ns_rx_bytes; /* rx data count (bytes) */
- u_int64_t ns_rx_beacons; /* rx beacon frames */
- u_int32_t ns_rx_proberesp; /* rx probe response frames */
+ u_int32_t ns_rx_data; /* rx data frames */
+ u_int32_t ns_rx_mgmt; /* rx management frames */
+ u_int32_t ns_rx_ctrl; /* rx control frames */
+ u_int32_t ns_rx_ucast; /* rx unicast frames */
+ u_int32_t ns_rx_mcast; /* rx multi/broadcast frames */
+ u_int64_t ns_rx_bytes; /* rx data count (bytes) */
+ u_int64_t ns_rx_beacons; /* rx beacon frames */
+ u_int32_t ns_rx_proberesp; /* rx probe response frames */
- u_int32_t ns_rx_dup; /* rx discard because it's a dup */
- u_int32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */
- u_int32_t ns_rx_wepfail; /* rx wep processing failed */
- u_int32_t ns_rx_demicfail; /* rx demic failed */
- u_int32_t ns_rx_decap; /* rx decapsulation failed */
- u_int32_t ns_rx_defrag; /* rx defragmentation failed */
- u_int32_t ns_rx_disassoc; /* rx disassociation */
- u_int32_t ns_rx_deauth; /* rx deauthentication */
- u_int32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */
- u_int32_t ns_rx_unauth; /* rx on unauthorized port */
- u_int32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */
+ u_int32_t ns_rx_dup; /* rx discard because it's a dup */
+ u_int32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */
+ u_int32_t ns_rx_wepfail; /* rx wep processing failed */
+ u_int32_t ns_rx_demicfail; /* rx demic failed */
+ u_int32_t ns_rx_decap; /* rx decapsulation failed */
+ u_int32_t ns_rx_defrag; /* rx defragmentation failed */
+ u_int32_t ns_rx_disassoc; /* rx disassociation */
+ u_int32_t ns_rx_deauth; /* rx deauthentication */
+ u_int32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */
+ u_int32_t ns_rx_unauth; /* rx on unauthorized port */
+ u_int32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */
- u_int32_t ns_tx_data; /* tx data frames */
- u_int32_t ns_tx_mgmt; /* tx management frames */
- u_int32_t ns_tx_ucast; /* tx unicast frames */
- u_int32_t ns_tx_mcast; /* tx multi/broadcast frames */
- u_int64_t ns_tx_bytes; /* tx data count (bytes) */
- u_int32_t ns_tx_probereq; /* tx probe request frames */
- u_int32_t ns_tx_uapsd; /* tx on uapsd queue */
+ u_int32_t ns_tx_data; /* tx data frames */
+ u_int32_t ns_tx_mgmt; /* tx management frames */
+ u_int32_t ns_tx_ucast; /* tx unicast frames */
+ u_int32_t ns_tx_mcast; /* tx multi/broadcast frames */
+ u_int64_t ns_tx_bytes; /* tx data count (bytes) */
+ u_int32_t ns_tx_probereq; /* tx probe request frames */
+ u_int32_t ns_tx_uapsd; /* tx on uapsd queue */
- u_int32_t ns_tx_novlantag; /* tx discard due to no tag */
- u_int32_t ns_tx_vlanmismatch; /* tx discard due to of bad tag */
+ u_int32_t ns_tx_novlantag; /* tx discard due to no tag */
+ u_int32_t ns_tx_vlanmismatch; /* tx discard due to of bad tag */
- u_int32_t ns_tx_eosplost; /* uapsd EOSP retried out */
+ u_int32_t ns_tx_eosplost; /* uapsd EOSP retried out */
- u_int32_t ns_ps_discard; /* ps discard due to of age */
+ u_int32_t ns_ps_discard; /* ps discard due to of age */
- u_int32_t ns_uapsd_triggers; /* uapsd triggers */
+ u_int32_t ns_uapsd_triggers; /* uapsd triggers */
- /* MIB-related state */
- u_int32_t ns_tx_assoc; /* [re]associations */
- u_int32_t ns_tx_assoc_fail; /* [re]association failures */
- u_int32_t ns_tx_auth; /* [re]authentications */
- u_int32_t ns_tx_auth_fail; /* [re]authentication failures*/
- u_int32_t ns_tx_deauth; /* deauthentications */
- u_int32_t ns_tx_deauth_code; /* last deauth reason */
- u_int32_t ns_tx_disassoc; /* disassociations */
- u_int32_t ns_tx_disassoc_code; /* last disassociation reason */
- u_int32_t ns_psq_drops; /* power save queue drops */
+ /* MIB-related state */
+ u_int32_t ns_tx_assoc; /* [re]associations */
+ u_int32_t ns_tx_assoc_fail; /* [re]association failures */
+ u_int32_t ns_tx_auth; /* [re]authentications */
+ u_int32_t ns_tx_auth_fail; /* [re]authentication failures*/
+ u_int32_t ns_tx_deauth; /* deauthentications */
+ u_int32_t ns_tx_deauth_code; /* last deauth reason */
+ u_int32_t ns_tx_disassoc; /* disassociations */
+ u_int32_t ns_tx_disassoc_code; /* last disassociation reason */
+ u_int32_t ns_psq_drops; /* power save queue drops */
};
/*
* Summary statistics.
*/
struct ieee80211_stats {
- u_int32_t is_rx_badversion; /* rx frame with bad version */
- u_int32_t is_rx_tooshort; /* rx frame too short */
- u_int32_t is_rx_wrongbss; /* rx from wrong bssid */
- u_int32_t is_rx_dup; /* rx discard due to it's a dup */
- u_int32_t is_rx_wrongdir; /* rx w/ wrong direction */
- u_int32_t is_rx_mcastecho; /* rx discard due to of mcast echo */
- u_int32_t is_rx_notassoc; /* rx discard due to sta !assoc */
- u_int32_t is_rx_noprivacy; /* rx w/ wep but privacy off */
- u_int32_t is_rx_unencrypted; /* rx w/o wep and privacy on */
- u_int32_t is_rx_wepfail; /* rx wep processing failed */
- u_int32_t is_rx_decap; /* rx decapsulation failed */
- u_int32_t is_rx_mgtdiscard; /* rx discard mgt frames */
- u_int32_t is_rx_ctl; /* rx discard ctrl frames */
- u_int32_t is_rx_beacon; /* rx beacon frames */
- u_int32_t is_rx_rstoobig; /* rx rate set truncated */
- u_int32_t is_rx_elem_missing; /* rx required element missing*/
- u_int32_t is_rx_elem_toobig; /* rx element too big */
- u_int32_t is_rx_elem_toosmall; /* rx element too small */
- u_int32_t is_rx_elem_unknown; /* rx element unknown */
- u_int32_t is_rx_badchan; /* rx frame w/ invalid chan */
- u_int32_t is_rx_chanmismatch; /* rx frame chan mismatch */
- u_int32_t is_rx_nodealloc; /* rx frame dropped */
- u_int32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */
- u_int32_t is_rx_auth_unsupported;/* rx w/ unsupported auth alg */
- u_int32_t is_rx_auth_fail; /* rx sta auth failure */
- u_int32_t is_rx_auth_countermeasures;/* rx auth discard due to CM */
- u_int32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */
- u_int32_t is_rx_assoc_notauth; /* rx assoc w/o auth */
- u_int32_t is_rx_assoc_capmismatch;/* rx assoc w/ cap mismatch */
- u_int32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */
- u_int32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */
- u_int32_t is_rx_deauth; /* rx deauthentication */
- u_int32_t is_rx_disassoc; /* rx disassociation */
- u_int32_t is_rx_badsubtype; /* rx frame w/ unknown subtype*/
- u_int32_t is_rx_nobuf; /* rx failed for lack of buf */
- u_int32_t is_rx_decryptcrc; /* rx decrypt failed on crc */
- u_int32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame*/
- u_int32_t is_rx_bad_auth; /* rx bad auth request */
- u_int32_t is_rx_unauth; /* rx on unauthorized port */
- u_int32_t is_rx_badkeyid; /* rx w/ incorrect keyid */
- u_int32_t is_rx_ccmpreplay; /* rx seq# violation (CCMP) */
- u_int32_t is_rx_ccmpformat; /* rx format bad (CCMP) */
- u_int32_t is_rx_ccmpmic; /* rx MIC check failed (CCMP) */
- u_int32_t is_rx_tkipreplay; /* rx seq# violation (TKIP) */
- u_int32_t is_rx_tkipformat; /* rx format bad (TKIP) */
- u_int32_t is_rx_tkipmic; /* rx MIC check failed (TKIP) */
- u_int32_t is_rx_tkipicv; /* rx ICV check failed (TKIP) */
- u_int32_t is_rx_badcipher; /* rx failed due to of key type */
- u_int32_t is_rx_nocipherctx; /* rx failed due to key !setup */
- u_int32_t is_rx_acl; /* rx discard due to of acl policy */
- u_int32_t is_rx_ffcnt; /* rx fast frames */
- u_int32_t is_rx_badathtnl; /* driver key alloc failed */
- u_int32_t is_tx_nobuf; /* tx failed for lack of buf */
- u_int32_t is_tx_nonode; /* tx failed for no node */
- u_int32_t is_tx_unknownmgt; /* tx of unknown mgt frame */
- u_int32_t is_tx_badcipher; /* tx failed due to of key type */
- u_int32_t is_tx_nodefkey; /* tx failed due to no defkey */
- u_int32_t is_tx_noheadroom; /* tx failed due to no space */
- u_int32_t is_tx_ffokcnt; /* tx fast frames sent success */
- u_int32_t is_tx_fferrcnt; /* tx fast frames sent success */
- u_int32_t is_scan_active; /* active scans started */
- u_int32_t is_scan_passive; /* passive scans started */
- u_int32_t is_node_timeout; /* nodes timed out inactivity */
- u_int32_t is_crypto_nomem; /* no memory for crypto ctx */
- u_int32_t is_crypto_tkip; /* tkip crypto done in s/w */
- u_int32_t is_crypto_tkipenmic; /* tkip en-MIC done in s/w */
- u_int32_t is_crypto_tkipdemic; /* tkip de-MIC done in s/w */
- u_int32_t is_crypto_tkipcm; /* tkip counter measures */
- u_int32_t is_crypto_ccmp; /* ccmp crypto done in s/w */
- u_int32_t is_crypto_wep; /* wep crypto done in s/w */
- u_int32_t is_crypto_setkey_cipher;/* cipher rejected key */
- u_int32_t is_crypto_setkey_nokey;/* no key index for setkey */
- u_int32_t is_crypto_delkey; /* driver key delete failed */
- u_int32_t is_crypto_badcipher; /* unknown cipher */
- u_int32_t is_crypto_nocipher; /* cipher not available */
- u_int32_t is_crypto_attachfail; /* cipher attach failed */
- u_int32_t is_crypto_swfallback; /* cipher fallback to s/w */
- u_int32_t is_crypto_keyfail; /* driver key alloc failed */
- u_int32_t is_crypto_enmicfail; /* en-MIC failed */
- u_int32_t is_ibss_capmismatch; /* merge failed-cap mismatch */
- u_int32_t is_ibss_norate; /* merge failed-rate mismatch */
- u_int32_t is_ps_unassoc; /* ps-poll for unassoc. sta */
- u_int32_t is_ps_badaid; /* ps-poll w/ incorrect aid */
- u_int32_t is_ps_qempty; /* ps-poll w/ nothing to send */
+ u_int32_t is_rx_badversion; /* rx frame with bad version */
+ u_int32_t is_rx_tooshort; /* rx frame too short */
+ u_int32_t is_rx_wrongbss; /* rx from wrong bssid */
+ u_int32_t is_rx_dup; /* rx discard due to it's a dup */
+ u_int32_t is_rx_wrongdir; /* rx w/ wrong direction */
+ u_int32_t is_rx_mcastecho; /* rx discard due to of mcast echo */
+ u_int32_t is_rx_notassoc; /* rx discard due to sta !assoc */
+ u_int32_t is_rx_noprivacy; /* rx w/ wep but privacy off */
+ u_int32_t is_rx_unencrypted; /* rx w/o wep and privacy on */
+ u_int32_t is_rx_wepfail; /* rx wep processing failed */
+ u_int32_t is_rx_decap; /* rx decapsulation failed */
+ u_int32_t is_rx_mgtdiscard; /* rx discard mgt frames */
+ u_int32_t is_rx_ctl; /* rx discard ctrl frames */
+ u_int32_t is_rx_beacon; /* rx beacon frames */
+ u_int32_t is_rx_rstoobig; /* rx rate set truncated */
+ u_int32_t is_rx_elem_missing; /* rx required element missing*/
+ u_int32_t is_rx_elem_toobig; /* rx element too big */
+ u_int32_t is_rx_elem_toosmall; /* rx element too small */
+ u_int32_t is_rx_elem_unknown; /* rx element unknown */
+ u_int32_t is_rx_badchan; /* rx frame w/ invalid chan */
+ u_int32_t is_rx_chanmismatch; /* rx frame chan mismatch */
+ u_int32_t is_rx_nodealloc; /* rx frame dropped */
+ u_int32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */
+ u_int32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */
+ u_int32_t is_rx_auth_fail; /* rx sta auth failure */
+ u_int32_t is_rx_auth_countermeasures; /* rx auth discard due to CM */
+ u_int32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */
+ u_int32_t is_rx_assoc_notauth; /* rx assoc w/o auth */
+ u_int32_t is_rx_assoc_capmismatch; /* rx assoc w/ cap mismatch */
+ u_int32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */
+ u_int32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */
+ u_int32_t is_rx_deauth; /* rx deauthentication */
+ u_int32_t is_rx_disassoc; /* rx disassociation */
+ u_int32_t is_rx_badsubtype; /* rx frame w/ unknown subtype*/
+ u_int32_t is_rx_nobuf; /* rx failed for lack of buf */
+ u_int32_t is_rx_decryptcrc; /* rx decrypt failed on crc */
+ u_int32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame*/
+ u_int32_t is_rx_bad_auth; /* rx bad auth request */
+ u_int32_t is_rx_unauth; /* rx on unauthorized port */
+ u_int32_t is_rx_badkeyid; /* rx w/ incorrect keyid */
+ u_int32_t is_rx_ccmpreplay; /* rx seq# violation (CCMP) */
+ u_int32_t is_rx_ccmpformat; /* rx format bad (CCMP) */
+ u_int32_t is_rx_ccmpmic; /* rx MIC check failed (CCMP) */
+ u_int32_t is_rx_tkipreplay; /* rx seq# violation (TKIP) */
+ u_int32_t is_rx_tkipformat; /* rx format bad (TKIP) */
+ u_int32_t is_rx_tkipmic; /* rx MIC check failed (TKIP) */
+ u_int32_t is_rx_tkipicv; /* rx ICV check failed (TKIP) */
+ u_int32_t is_rx_badcipher; /* rx failed due to of key type */
+ u_int32_t is_rx_nocipherctx; /* rx failed due to key !setup */
+ u_int32_t is_rx_acl; /* rx discard due to of acl policy */
+ u_int32_t is_rx_ffcnt; /* rx fast frames */
+ u_int32_t is_rx_badathtnl; /* driver key alloc failed */
+ u_int32_t is_tx_nobuf; /* tx failed for lack of buf */
+ u_int32_t is_tx_nonode; /* tx failed for no node */
+ u_int32_t is_tx_unknownmgt; /* tx of unknown mgt frame */
+ u_int32_t is_tx_badcipher; /* tx failed due to of key type */
+ u_int32_t is_tx_nodefkey; /* tx failed due to no defkey */
+ u_int32_t is_tx_noheadroom; /* tx failed due to no space */
+ u_int32_t is_tx_ffokcnt; /* tx fast frames sent success */
+ u_int32_t is_tx_fferrcnt; /* tx fast frames sent success */
+ u_int32_t is_scan_active; /* active scans started */
+ u_int32_t is_scan_passive; /* passive scans started */
+ u_int32_t is_node_timeout; /* nodes timed out inactivity */
+ u_int32_t is_crypto_nomem; /* no memory for crypto ctx */
+ u_int32_t is_crypto_tkip; /* tkip crypto done in s/w */
+ u_int32_t is_crypto_tkipenmic; /* tkip en-MIC done in s/w */
+ u_int32_t is_crypto_tkipdemic; /* tkip de-MIC done in s/w */
+ u_int32_t is_crypto_tkipcm; /* tkip counter measures */
+ u_int32_t is_crypto_ccmp; /* ccmp crypto done in s/w */
+ u_int32_t is_crypto_wep; /* wep crypto done in s/w */
+ u_int32_t is_crypto_setkey_cipher; /* cipher rejected key */
+ u_int32_t is_crypto_setkey_nokey; /* no key index for setkey */
+ u_int32_t is_crypto_delkey; /* driver key delete failed */
+ u_int32_t is_crypto_badcipher; /* unknown cipher */
+ u_int32_t is_crypto_nocipher; /* cipher not available */
+ u_int32_t is_crypto_attachfail; /* cipher attach failed */
+ u_int32_t is_crypto_swfallback; /* cipher fallback to s/w */
+ u_int32_t is_crypto_keyfail; /* driver key alloc failed */
+ u_int32_t is_crypto_enmicfail; /* en-MIC failed */
+ u_int32_t is_ibss_capmismatch; /* merge failed-cap mismatch */
+ u_int32_t is_ibss_norate; /* merge failed-rate mismatch */
+ u_int32_t is_ps_unassoc; /* ps-poll for unassoc. sta */
+ u_int32_t is_ps_badaid; /* ps-poll w/ incorrect aid */
+ u_int32_t is_ps_qempty; /* ps-poll w/ nothing to send */
};
/*
* Retrieve per-node statistics.
*/
struct ieee80211req_sta_stats {
- union {
- /* NB: explicitly force 64-bit alignment */
- u_int8_t macaddr[IEEE80211_ADDR_LEN];
- u_int64_t pad;
- } is_u;
- struct ieee80211_nodestats is_stats;
+ union {
+ /* NB: explicitly force 64-bit alignment */
+ u_int8_t macaddr[IEEE80211_ADDR_LEN];
+ u_int64_t pad;
+ } is_u;
+ struct ieee80211_nodestats is_stats;
};
/*
* to retrieve other data like stats, unicast key, etc.
*/
struct ieee80211req_sta_info {
- u_int16_t isi_len; /* length (mult of 4) */
- u_int16_t isi_freq; /* MHz */
- u_int16_t isi_flags; /* channel flags */
- u_int16_t isi_state; /* state flags */
- u_int8_t isi_authmode; /* authentication algorithm */
- u_int8_t isi_rssi;
- u_int16_t isi_capinfo; /* capabilities */
- u_int8_t isi_athflags; /* Atheros capabilities */
- u_int8_t isi_erp; /* ERP element */
- u_int8_t isi_macaddr[IEEE80211_ADDR_LEN];
- u_int8_t isi_nrates; /* negotiated rates */
- u_int8_t isi_rates[IEEE80211_RATE_MAXSIZE];
- u_int8_t isi_txrate; /* index to isi_rates[] */
- u_int16_t isi_ie_len; /* IE length */
- u_int16_t isi_associd; /* assoc response */
- u_int16_t isi_txpower; /* current tx power */
- u_int16_t isi_vlan; /* vlan tag */
- u_int16_t isi_txseqs[17]; /* seq to be transmitted */
- u_int16_t isi_rxseqs[17]; /* seq previous for qos frames*/
- u_int16_t isi_inact; /* inactivity timer */
- u_int8_t isi_uapsd; /* UAPSD queues */
- u_int8_t isi_opmode; /* sta operating mode */
+ u_int16_t isi_len; /* length (mult of 4) */
+ u_int16_t isi_freq; /* MHz */
+ u_int16_t isi_flags; /* channel flags */
+ u_int16_t isi_state; /* state flags */
+ u_int8_t isi_authmode; /* authentication algorithm */
+ u_int8_t isi_rssi;
+ u_int16_t isi_capinfo; /* capabilities */
+ u_int8_t isi_athflags; /* Atheros capabilities */
+ u_int8_t isi_erp; /* ERP element */
+ u_int8_t isi_macaddr[IEEE80211_ADDR_LEN];
+ u_int8_t isi_nrates; /* negotiated rates */
+ u_int8_t isi_rates[IEEE80211_RATE_MAXSIZE];
+ u_int8_t isi_txrate; /* index to isi_rates[] */
+ u_int16_t isi_ie_len; /* IE length */
+ u_int16_t isi_associd; /* assoc response */
+ u_int16_t isi_txpower; /* current tx power */
+ u_int16_t isi_vlan; /* vlan tag */
+ u_int16_t isi_txseqs[17]; /* seq to be transmitted */
+ u_int16_t isi_rxseqs[17]; /* seq previous for qos frames*/
+ u_int16_t isi_inact; /* inactivity timer */
+ u_int8_t isi_uapsd; /* UAPSD queues */
+ u_int8_t isi_opmode; /* sta operating mode */
- /* XXX frag state? */
- /* variable length IE data */
+ /* XXX frag state? */
+ /* variable length IE data */
};
-
struct ath_stats {
- u_int32_t ast_watchdog; /* device reset by watchdog */
- u_int32_t ast_hardware; /* fatal hardware error interrupts */
- u_int32_t ast_bmiss; /* beacon miss interrupts */
- u_int32_t ast_rxorn; /* rx overrun interrupts */
- u_int32_t ast_rxeol; /* rx eol interrupts */
- u_int32_t ast_txurn; /* tx underrun interrupts */
- u_int32_t ast_mib; /* mib interrupts */
- u_int32_t ast_tx_packets; /* packet sent on the interface */
- u_int32_t ast_tx_mgmt; /* management frames transmitted */
- u_int32_t ast_tx_discard; /* frames discarded prior to assoc */
- u_int32_t ast_tx_invalid; /* frames discarded due to is device gone */
- u_int32_t ast_tx_qstop; /* tx queue stopped because it's full */
- u_int32_t ast_tx_encap; /* tx encapsulation failed */
- u_int32_t ast_tx_nonode; /* tx failed due to of no node */
- u_int32_t ast_tx_nobuf; /* tx failed due to of no tx buffer (data) */
- u_int32_t ast_tx_nobufmgt; /* tx failed due to of no tx buffer (mgmt)*/
- u_int32_t ast_tx_xretries; /* tx failed due to of too many retries */
- u_int32_t ast_tx_fifoerr; /* tx failed due to of FIFO underrun */
- u_int32_t ast_tx_filtered; /* tx failed due to xmit filtered */
- u_int32_t ast_tx_shortretry; /* tx on-chip retries (short) */
- u_int32_t ast_tx_longretry; /* tx on-chip retries (long) */
- u_int32_t ast_tx_badrate; /* tx failed due to of bogus xmit rate */
- u_int32_t ast_tx_noack; /* tx frames with no ack marked */
- u_int32_t ast_tx_rts; /* tx frames with rts enabled */
- u_int32_t ast_tx_cts; /* tx frames with cts enabled */
- u_int32_t ast_tx_shortpre; /* tx frames with short preamble */
- u_int32_t ast_tx_altrate; /* tx frames with alternate rate */
- u_int32_t ast_tx_protect; /* tx frames with protection */
- u_int32_t ast_rx_orn; /* rx failed due to of desc overrun */
- u_int32_t ast_rx_crcerr; /* rx failed due to of bad CRC */
- u_int32_t ast_rx_fifoerr; /* rx failed due to of FIFO overrun */
- u_int32_t ast_rx_badcrypt; /* rx failed due to of decryption */
- u_int32_t ast_rx_badmic; /* rx failed due to of MIC failure */
- u_int32_t ast_rx_phyerr; /* rx PHY error summary count */
- u_int32_t ast_rx_phy[32]; /* rx PHY error per-code counts */
- u_int32_t ast_rx_tooshort; /* rx discarded due to frame too short */
- u_int32_t ast_rx_toobig; /* rx discarded due to frame too large */
- u_int32_t ast_rx_nobuf; /* rx setup failed due to of no skbuff */
- u_int32_t ast_rx_packets; /* packet recv on the interface */
- u_int32_t ast_rx_mgt; /* management frames received */
- u_int32_t ast_rx_ctl; /* control frames received */
- int8_t ast_tx_rssi; /* tx rssi of last ack */
- int8_t ast_rx_rssi; /* rx rssi from histogram */
- u_int32_t ast_be_xmit; /* beacons transmitted */
- u_int32_t ast_be_nobuf; /* no skbuff available for beacon */
- u_int32_t ast_per_cal; /* periodic calibration calls */
- u_int32_t ast_per_calfail; /* periodic calibration failed */
- u_int32_t ast_per_rfgain; /* periodic calibration rfgain reset */
- u_int32_t ast_rate_calls; /* rate control checks */
- u_int32_t ast_rate_raise; /* rate control raised xmit rate */
- u_int32_t ast_rate_drop; /* rate control dropped xmit rate */
- u_int32_t ast_ant_defswitch; /* rx/default antenna switches */
- u_int32_t ast_ant_txswitch; /* tx antenna switches */
- u_int32_t ast_ant_rx[8]; /* rx frames with antenna */
- u_int32_t ast_ant_tx[8]; /* tx frames with antenna */
+ u_int32_t ast_watchdog; /* device reset by watchdog */
+ u_int32_t ast_hardware; /* fatal hardware error interrupts */
+ u_int32_t ast_bmiss; /* beacon miss interrupts */
+ u_int32_t ast_rxorn; /* rx overrun interrupts */
+ u_int32_t ast_rxeol; /* rx eol interrupts */
+ u_int32_t ast_txurn; /* tx underrun interrupts */
+ u_int32_t ast_mib; /* mib interrupts */
+ u_int32_t ast_tx_packets; /* packet sent on the interface */
+ u_int32_t ast_tx_mgmt; /* management frames transmitted */
+ u_int32_t ast_tx_discard; /* frames discarded prior to assoc */
+ u_int32_t ast_tx_invalid; /* frames discarded due to is device gone */
+ u_int32_t ast_tx_qstop; /* tx queue stopped because it's full */
+ u_int32_t ast_tx_encap; /* tx encapsulation failed */
+ u_int32_t ast_tx_nonode; /* tx failed due to of no node */
+ u_int32_t ast_tx_nobuf; /* tx failed due to of no tx buffer (data) */
+ u_int32_t ast_tx_nobufmgt; /* tx failed due to of no tx buffer (mgmt)*/
+ u_int32_t ast_tx_xretries; /* tx failed due to of too many retries */
+ u_int32_t ast_tx_fifoerr; /* tx failed due to of FIFO underrun */
+ u_int32_t ast_tx_filtered; /* tx failed due to xmit filtered */
+ u_int32_t ast_tx_shortretry; /* tx on-chip retries (short) */
+ u_int32_t ast_tx_longretry; /* tx on-chip retries (long) */
+ u_int32_t ast_tx_badrate; /* tx failed due to of bogus xmit rate */
+ u_int32_t ast_tx_noack; /* tx frames with no ack marked */
+ u_int32_t ast_tx_rts; /* tx frames with rts enabled */
+ u_int32_t ast_tx_cts; /* tx frames with cts enabled */
+ u_int32_t ast_tx_shortpre; /* tx frames with short preamble */
+ u_int32_t ast_tx_altrate; /* tx frames with alternate rate */
+ u_int32_t ast_tx_protect; /* tx frames with protection */
+ u_int32_t ast_rx_orn; /* rx failed due to of desc overrun */
+ u_int32_t ast_rx_crcerr; /* rx failed due to of bad CRC */
+ u_int32_t ast_rx_fifoerr; /* rx failed due to of FIFO overrun */
+ u_int32_t ast_rx_badcrypt; /* rx failed due to of decryption */
+ u_int32_t ast_rx_badmic; /* rx failed due to of MIC failure */
+ u_int32_t ast_rx_phyerr; /* rx PHY error summary count */
+ u_int32_t ast_rx_phy[32]; /* rx PHY error per-code counts */
+ u_int32_t ast_rx_tooshort; /* rx discarded due to frame too short */
+ u_int32_t ast_rx_toobig; /* rx discarded due to frame too large */
+ u_int32_t ast_rx_nobuf; /* rx setup failed due to of no skbuff */
+ u_int32_t ast_rx_packets; /* packet recv on the interface */
+ u_int32_t ast_rx_mgt; /* management frames received */
+ u_int32_t ast_rx_ctl; /* control frames received */
+ int8_t ast_tx_rssi; /* tx rssi of last ack */
+ int8_t ast_rx_rssi; /* rx rssi from histogram */
+ u_int32_t ast_be_xmit; /* beacons transmitted */
+ u_int32_t ast_be_nobuf; /* no skbuff available for beacon */
+ u_int32_t ast_per_cal; /* periodic calibration calls */
+ u_int32_t ast_per_calfail; /* periodic calibration failed */
+ u_int32_t ast_per_rfgain; /* periodic calibration rfgain reset */
+ u_int32_t ast_rate_calls; /* rate control checks */
+ u_int32_t ast_rate_raise; /* rate control raised xmit rate */
+ u_int32_t ast_rate_drop; /* rate control dropped xmit rate */
+ u_int32_t ast_ant_defswitch; /* rx/default antenna switches */
+ u_int32_t ast_ant_txswitch; /* tx antenna switches */
+ u_int32_t ast_ant_rx[8]; /* rx frames with antenna */
+ u_int32_t ast_ant_tx[8]; /* tx frames with antenna */
};
-#define SIOCGATHSTATS (SIOCDEVPRIVATE+0)
-#define SIOCGATHDIAG (SIOCDEVPRIVATE+1)
-#define SIOCGATHRADARSIG (SIOCDEVPRIVATE+2)
-#define SIOCGATHHALDIAG (SIOCDEVPRIVATE+3)
-#define SIOCG80211STATS (SIOCDEVPRIVATE+2)
+#define SIOCGATHSTATS (SIOCDEVPRIVATE + 0)
+#define SIOCGATHDIAG (SIOCDEVPRIVATE + 1)
+#define SIOCGATHRADARSIG (SIOCDEVPRIVATE + 2)
+#define SIOCGATHHALDIAG (SIOCDEVPRIVATE + 3)
+#define SIOCG80211STATS (SIOCDEVPRIVATE + 2)
/* NB: require in+out parameters so cannot use wireless extensions, yech */
-#define IEEE80211_IOCTL_GETKEY (SIOCDEVPRIVATE+3)
-#define IEEE80211_IOCTL_GETWPAIE (SIOCDEVPRIVATE+4)
-#define IEEE80211_IOCTL_STA_STATS (SIOCDEVPRIVATE+5)
-#define IEEE80211_IOCTL_STA_INFO (SIOCDEVPRIVATE+6)
-#define SIOC80211IFCREATE (SIOCDEVPRIVATE+7)
-#define SIOC80211IFDESTROY (SIOCDEVPRIVATE+8)
-#define IEEE80211_IOCTL_SCAN_RESULTS (SIOCDEVPRIVATE+9)
-
+#define IEEE80211_IOCTL_GETKEY (SIOCDEVPRIVATE + 3)
+#define IEEE80211_IOCTL_GETWPAIE (SIOCDEVPRIVATE + 4)
+#define IEEE80211_IOCTL_STA_STATS (SIOCDEVPRIVATE + 5)
+#define IEEE80211_IOCTL_STA_INFO (SIOCDEVPRIVATE + 6)
+#define SIOC80211IFCREATE (SIOCDEVPRIVATE + 7)
+#define SIOC80211IFDESTROY (SIOCDEVPRIVATE + 8)
+#define IEEE80211_IOCTL_SCAN_RESULTS (SIOCDEVPRIVATE + 9)
#endif
} /* }}} int mec_match */
void module_register(void) {
- fc_register_match(
- "empty_counter",
- (match_proc_t){
- .create = mec_create, .destroy = mec_destroy, .match = mec_match,
- });
+ fc_register_match("empty_counter", (match_proc_t){
+ .create = mec_create,
+ .destroy = mec_destroy,
+ .match = mec_match,
+ });
} /* module_register */
if (mr_match_regexen(m->type_instance, vl->type_instance) ==
FC_MATCH_NO_MATCH)
return nomatch_value;
- if (vl->meta != NULL) {
- for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next) {
- mr_regex_t *meta_re = (mr_regex_t *)e->value;
- char *value;
- int status = meta_data_get_string(vl->meta, e->key, &value);
- if (status == (-ENOENT)) /* key is not present */
- return nomatch_value;
- if (status != 0) /* some other problem */
- continue; /* error will have already been printed. */
- if (mr_match_regexen(meta_re, value) == FC_MATCH_NO_MATCH) {
- sfree(value);
- return nomatch_value;
- }
+ for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next) {
+ mr_regex_t *meta_re = (mr_regex_t *)e->value;
+ char *value;
+ int status;
+ if (vl->meta == NULL)
+ return nomatch_value;
+ status = meta_data_get_string(vl->meta, e->key, &value);
+ if (status == (-ENOENT)) /* key is not present */
+ return nomatch_value;
+ if (status != 0) /* some other problem */
+ continue; /* error will have already been printed. */
+ if (mr_match_regexen(meta_re, value) == FC_MATCH_NO_MATCH) {
sfree(value);
+ return nomatch_value;
}
+ sfree(value);
}
return match_value;
static int socket_receive(socket_adapter_t *self, FILE **p_file);
static mcelog_config_t g_mcelog_config = {
- .logfile = "/var/log/mcelog", .persist = false,
+ .logfile = "/var/log/mcelog",
+ .persist = false,
};
static socket_adapter_t socket_adapter = {
.sock_fd = -1,
.unix_sock =
{
- .sun_family = AF_UNIX, .sun_path = "/var/run/mcelog-client",
+ .sun_family = AF_UNIX,
+ .sun_path = "/var/run/mcelog-client",
},
.lock = PTHREAD_RWLOCK_INITIALIZER,
.close = socket_close,
int res = -1;
pthread_rwlock_rdlock(&self->lock);
struct pollfd poll_fd = {
- .fd = self->sock_fd, .events = POLLIN | POLLPRI,
+ .fd = self->sock_fd,
+ .events = POLLIN | POLLPRI,
};
if ((res = poll(&poll_fd, 1, MCELOG_POLL_TIMEOUT)) <= 0) {
/* Wait until connection establishes */
struct pollfd pollfd = {
- .fd = fd, .events = POLLOUT,
+ .fd = fd,
+ .events = POLLOUT,
};
do
status = poll(&pollfd, 1, MEMCACHED_CONNECT_TIMEOUT);
}
struct pollfd pollfd = {
- .fd = st->fd, .events = POLLOUT,
+ .fd = st->fd,
+ .events = POLLOUT,
};
do
derive_t value0, derive_t value1, memcached_t *st) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = value0}, {.derive = value1},
+ {.derive = value0},
+ {.derive = value1},
};
memcached_init_vl(&vl, st);
gauge_t value0, gauge_t value1, memcached_t *st) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.gauge = value0}, {.gauge = value1},
+ {.gauge = value0},
+ {.gauge = value1},
};
memcached_init_vl(&vl, st);
}
/*
+ * Number of secs since the server started
+ */
+ else if (FIELD_IS("uptime")) {
+ submit_gauge("uptime", NULL, atof(fields[2]), st);
+ }
+
+ /*
* Number of bytes used and available (total - used)
*/
else if (FIELD_IS("bytes")) {
/* callback = */ memcached_read,
/* interval = */ 0,
&(user_data_t){
- .data = st, .free_func = memcached_free,
+ .data = st,
+ .free_func = memcached_free,
});
} /* int memcached_add_read_callback */
#include "plugin.h"
#include "utils/common/common.h"
-#ifdef HAVE_SYS_SYSCTL_H
+#if (defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)) || \
+ defined(__OpenBSD__)
+/* Implies BSD variant */
#include <sys/sysctl.h>
#endif
#ifdef HAVE_SYS_VMMETER_H
static kstat_t *ksz;
/* #endif HAVE_LIBKSTAT */
-#elif HAVE_SYSCTL
+#elif HAVE_SYSCTL && __OpenBSD__
+/* OpenBSD variant does not have sysctlbyname */
static int pagesize;
-/* #endif HAVE_SYSCTL */
+/* #endif HAVE_SYSCTL && __OpenBSD__ */
#elif HAVE_LIBSTATGRAB
/* no global variables */
#if HAVE_HOST_STATISTICS
port_host = mach_host_self();
host_page_size(port_host, &pagesize);
-/* #endif HAVE_HOST_STATISTICS */
+ /* #endif HAVE_HOST_STATISTICS */
#elif HAVE_SYSCTLBYNAME
/* no init stuff */
return -1;
}
-/* #endif HAVE_LIBKSTAT */
+ /* #endif HAVE_LIBKSTAT */
-#elif HAVE_SYSCTL
+#elif HAVE_SYSCTL && __OpenBSD__
+ /* OpenBSD variant does not have sysctlbyname */
pagesize = getpagesize();
if (pagesize <= 0) {
ERROR("memory plugin: Invalid pagesize: %i", pagesize);
return -1;
}
-/* #endif HAVE_SYSCTL */
+ /* #endif HAVE_SYSCTL && __OpenBSD__ */
#elif HAVE_LIBSTATGRAB
/* no init stuff */
MEMORY_SUBMIT("wired", wired, "active", active, "inactive", inactive, "free",
free);
-/* #endif HAVE_HOST_STATISTICS */
+ /* #endif HAVE_HOST_STATISTICS */
#elif HAVE_SYSCTLBYNAME
/*
(gauge_t)sysctl_vals[3], "active", (gauge_t)sysctl_vals[4],
"inactive", (gauge_t)sysctl_vals[5], "cache",
(gauge_t)sysctl_vals[6]);
-/* #endif HAVE_SYSCTLBYNAME */
+ /* #endif HAVE_SYSCTLBYNAME */
#elif KERNEL_LINUX
FILE *fh;
else
MEMORY_SUBMIT("used", mem_used, "buffered", mem_buffered, "cached",
mem_cached, "free", mem_free, "slab", mem_slab_total);
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
/* Most of the additions here were taken as-is from the k9toolkit from
MEMORY_SUBMIT("used", (gauge_t)mem_used, "free", (gauge_t)mem_free, "locked",
(gauge_t)mem_lock, "kernel", (gauge_t)mem_kern, "arc",
(gauge_t)arcsize, "unusable", (gauge_t)mem_unus);
-/* #endif HAVE_LIBKSTAT */
+ /* #endif HAVE_LIBKSTAT */
-#elif HAVE_SYSCTL
+#elif HAVE_SYSCTL && __OpenBSD__
+ /* OpenBSD variant does not have HAVE_SYSCTLBYNAME */
int mib[] = {CTL_VM, VM_METER};
struct vmtotal vmtotal = {0};
gauge_t mem_active;
MEMORY_SUBMIT("active", mem_active, "inactive", mem_inactive, "free",
mem_free);
-/* #endif HAVE_SYSCTL */
+ /* #endif HAVE_SYSCTL && __OpenBSD__ */
#elif HAVE_LIBSTATGRAB
sg_mem_stats *ios;
MEMORY_SUBMIT("used", (gauge_t)ios->used, "cached", (gauge_t)ios->cache,
"free", (gauge_t)ios->free);
-/* #endif HAVE_LIBSTATGRAB */
+ /* #endif HAVE_LIBSTATGRAB */
#elif HAVE_PERFSTAT
perfstat_memory_total_t pmemory = {0};
vl.values_len = 1;
strncpy(vl.plugin, "mic", sizeof(vl.plugin));
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
strncpy(vl.type, "memory", sizeof(vl.type));
strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
vl.values_len = 1;
strncpy(vl.plugin, "mic", sizeof(vl.plugin));
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
strncpy(vl.type, "temperature", sizeof(vl.type));
strncpy(vl.type_instance, type, sizeof(vl.type_instance));
strncpy(vl.plugin, "mic", sizeof(vl.plugin));
if (core < 0) /* global aggregation */
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
else /* per-core statistics */
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i-cpu-%i",
- micnumber, core);
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i-cpu-%i",
+ micnumber, core);
strncpy(vl.type, "cpu", sizeof(vl.type));
strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
vl.values_len = 1;
strncpy(vl.plugin, "mic", sizeof(vl.plugin));
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%i", micnumber);
strncpy(vl.type, type, sizeof(vl.type));
strncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
MBCONN_RTU }; /* }}} */
typedef enum mb_conntype_e mb_conntype_t;
+enum mb_uarttype_e /* {{{ */
+{ UARTTYPE_RS232,
+ UARTTYPE_RS422,
+ UARTTYPE_RS485 }; /* }}} */
+typedef enum mb_uarttype_e mb_uarttype_t;
+
struct mb_data_s;
typedef struct mb_data_s mb_data_t;
struct mb_data_s /* {{{ */
char host[DATA_MAX_NAME_LEN];
char node[NI_MAXHOST]; /* TCP hostname or RTU serial device */
/* char service[NI_MAXSERV]; */
- int port; /* for Modbus/TCP */
- int baudrate; /* for Modbus/RTU */
+ int port; /* for Modbus/TCP */
+ int baudrate; /* for Modbus/RTU */
+ mb_uarttype_t uarttype; /* UART type for Modbus/RTU */
mb_conntype_t conntype;
mb_slave_t *slaves;
return EINVAL;
if (slave->instance[0] == 0)
- snprintf(slave->instance, sizeof(slave->instance), "slave_%i", slave->id);
+ ssnprintf(slave->instance, sizeof(slave->instance), "slave_%i", slave->id);
vl.values = &value;
vl.values_len = 1;
host->is_connected = true;
return 0;
} /* }}} int mb_init_connection */
-/* #endif LEGACY_LIBMODBUS */
+ /* #endif LEGACY_LIBMODBUS */
#else /* if !LEGACY_LIBMODBUS */
/* Version 2.9.2 */
return status;
}
+#if defined(linux) && LIBMODBUS_VERSION_CHECK(2, 9, 4)
+ switch (host->uarttype) {
+ case UARTTYPE_RS485:
+ if (modbus_rtu_set_serial_mode(host->connection, MODBUS_RTU_RS485))
+ DEBUG("Modbus plugin: Setting RS485 mode failed.");
+ break;
+ case UARTTYPE_RS422:
+ /* libmodbus doesn't say anything about full-duplex symmetric RS422 UART */
+ break;
+ case UARTTYPE_RS232:
+ break;
+ default:
+ DEBUG("Modbus plugin: Invalid UART type!.");
+ }
+#endif /* defined(linux) && LIBMODBUS_VERSION_CHECK(2, 9, 4) */
+
return 0;
} /* }}} int mb_init_connection */
#endif /* !LEGACY_LIBMODBUS */
status = -1;
} else if (strcasecmp("Device", child->key) == 0) {
status = cf_util_get_string_buffer(child, host->node, sizeof(host->node));
- if (status == 0)
+ if (status == 0) {
host->conntype = MBCONN_RTU;
+ host->uarttype = UARTTYPE_RS232;
+ }
} else if (strcasecmp("Baudrate", child->key) == 0)
status = cf_util_get_int(child, &host->baudrate);
- else if (strcasecmp("Interval", child->key) == 0)
+ else if (strcasecmp("UARTType", child->key) == 0) {
+#if defined(linux) && !LEGACY_LIBMODBUS && LIBMODBUS_VERSION_CHECK(2, 9, 4)
+ char buffer[NI_MAXHOST];
+ status = cf_util_get_string_buffer(child, buffer, sizeof(buffer));
+ if (status != 0)
+ break;
+ if (strncmp(buffer, "RS485", 6) == 0)
+ host->uarttype = UARTTYPE_RS485;
+ else if (strncmp(buffer, "RS422", 6) == 0)
+ host->uarttype = UARTTYPE_RS422;
+ else if (strncmp(buffer, "RS232", 6) == 0)
+ host->uarttype = UARTTYPE_RS232;
+ else {
+ ERROR("Modbus plugin: The UARTType \"%s\" is unknown.", buffer);
+ status = -1;
+ break;
+ }
+#else
+ ERROR("Modbus plugin: Option `UARTType' not supported. Please "
+ "upgrade libmodbus to at least 2.9.4");
+ return -1;
+#endif
+ } else if (strcasecmp("Interval", child->key) == 0)
status = cf_util_get_cdtime(child, &interval);
else if (strcasecmp("Slave", child->key) == 0)
/* Don't set status: Gracefully continue if a slave fails. */
if (status == 0) {
char name[1024];
- snprintf(name, sizeof(name), "modbus-%s", host->host);
+ ssnprintf(name, sizeof(name), "modbus-%s", host->host);
plugin_register_complex_read(/* group = */ NULL, name,
/* callback = */ mb_read,
/* interval = */ interval,
&(user_data_t){
- .data = host, .free_func = host_free,
+ .data = host,
+ .free_func = host_free,
});
} else {
host_free(host);
if (status != 0)
return status;
- status = snprintf(buf, buf_len, "%s/%s", conf->topic_prefix, name);
+ status = ssnprintf(buf, buf_len, "%s/%s", conf->topic_prefix, name);
if ((status < 0) || (((size_t)status) >= buf_len))
return ENOMEM;
ERROR("mqtt plugin: Unknown config option: %s", child->key);
}
- snprintf(cb_name, sizeof(cb_name), "mqtt/%s", conf->name);
+ ssnprintf(cb_name, sizeof(cb_name), "mqtt/%s", conf->name);
plugin_register_write(cb_name, mqtt_write,
&(user_data_t){
.data = conf,
(db->database != NULL) ? db->database : "<default>");
if (db->instance != NULL)
- snprintf(cb_name, sizeof(cb_name), "mysql-%s", db->instance);
+ ssnprintf(cb_name, sizeof(cb_name), "mysql-%s", db->instance);
else
sstrncpy(cb_name, "mysql", sizeof(cb_name));
plugin_register_complex_read(
/* group = */ NULL, cb_name, mysql_read, /* interval = */ 0,
&(user_data_t){
- .data = db, .free_func = mysql_database_free,
+ .data = db,
+ .free_func = mysql_database_free,
});
} else {
mysql_database_free(db);
static void traffic_submit(derive_t rx, derive_t tx, mysql_database_t *db) {
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
submit("mysql_octets", NULL, values, STATIC_ARRAY_SIZE(values), db);
if (((io == NULL) || (strcasecmp(io, "yes") != 0)) &&
(db->slave_io_running)) {
n.severity = NOTIF_WARNING;
- snprintf(n.message, sizeof(n.message),
- "slave I/O thread not started or not connected to master");
+ ssnprintf(n.message, sizeof(n.message),
+ "slave I/O thread not started or not connected to master");
plugin_dispatch_notification(&n);
db->slave_io_running = false;
} else if (((io != NULL) && (strcasecmp(io, "yes") == 0)) &&
(!db->slave_io_running)) {
n.severity = NOTIF_OKAY;
- snprintf(n.message, sizeof(n.message),
- "slave I/O thread started and connected to master");
+ ssnprintf(n.message, sizeof(n.message),
+ "slave I/O thread started and connected to master");
plugin_dispatch_notification(&n);
db->slave_io_running = true;
}
if (((sql == NULL) || (strcasecmp(sql, "yes") != 0)) &&
(db->slave_sql_running)) {
n.severity = NOTIF_WARNING;
- snprintf(n.message, sizeof(n.message), "slave SQL thread not started");
+ ssnprintf(n.message, sizeof(n.message), "slave SQL thread not started");
plugin_dispatch_notification(&n);
db->slave_sql_running = false;
} else if (((sql != NULL) && (strcasecmp(sql, "yes") == 0)) &&
(!db->slave_sql_running)) {
n.severity = NOTIF_OKAY;
- snprintf(n.message, sizeof(n.message), "slave SQL thread started");
+ ssnprintf(n.message, sizeof(n.message), "slave SQL thread started");
plugin_dispatch_notification(&n);
db->slave_sql_running = true;
}
} else if (strncmp(key, "Slow_queries", strlen("Slow_queries")) == 0) {
derive_submit("mysql_slow_queries", NULL, val, db);
+ } else if (strcmp(key, "Uptime") == 0) {
+ gauge_submit("uptime", NULL, val, db);
}
}
mysql_free_result(res);
derive_t val0, derive_t val1, cdtime_t timestamp,
cdtime_t interval) {
value_t values[] = {
- {.derive = val0}, {.derive = val1},
+ {.derive = val0},
+ {.derive = val1},
};
return submit_values(host, plugin_inst, type, type_inst, values,
gauge_t val0, gauge_t val1, cdtime_t timestamp,
cdtime_t interval) {
value_t values[] = {
- {.gauge = val0}, {.gauge = val1},
+ {.gauge = val0},
+ {.gauge = val1},
};
return submit_values(host, plugin_inst, type, type_inst, values,
if ((hostname == NULL) || (old_data == NULL) || (new_data == NULL))
return -1;
- snprintf(plugin_instance, sizeof(plugin_instance), "volume-%s",
- old_data->name);
+ ssnprintf(plugin_instance, sizeof(plugin_instance), "volume-%s",
+ old_data->name);
/* Check for and submit disk-octet values */
if (HAS_ALL_FLAGS(old_data->flags, CFG_VOLUME_PERF_IO) &&
- HAS_ALL_FLAGS(new_data->flags,
- HAVE_VOLUME_PERF_BYTES_READ |
- HAVE_VOLUME_PERF_BYTES_WRITE)) {
+ HAS_ALL_FLAGS(new_data->flags, HAVE_VOLUME_PERF_BYTES_READ |
+ HAVE_VOLUME_PERF_BYTES_WRITE)) {
submit_two_derive(
hostname, plugin_instance, "disk_octets", /* type instance = */ NULL,
(derive_t)new_data->read_bytes, (derive_t)new_data->write_bytes,
}
/* Check for, calculate and submit disk-latency values */
- if (HAS_ALL_FLAGS(old_data->flags,
- CFG_VOLUME_PERF_LATENCY | HAVE_VOLUME_PERF_OPS_READ |
- HAVE_VOLUME_PERF_OPS_WRITE |
- HAVE_VOLUME_PERF_LATENCY_READ |
- HAVE_VOLUME_PERF_LATENCY_WRITE) &&
- HAS_ALL_FLAGS(new_data->flags,
- HAVE_VOLUME_PERF_OPS_READ | HAVE_VOLUME_PERF_OPS_WRITE |
- HAVE_VOLUME_PERF_LATENCY_READ |
- HAVE_VOLUME_PERF_LATENCY_WRITE)) {
+ if (HAS_ALL_FLAGS(old_data->flags, CFG_VOLUME_PERF_LATENCY |
+ HAVE_VOLUME_PERF_OPS_READ |
+ HAVE_VOLUME_PERF_OPS_WRITE |
+ HAVE_VOLUME_PERF_LATENCY_READ |
+ HAVE_VOLUME_PERF_LATENCY_WRITE) &&
+ HAS_ALL_FLAGS(new_data->flags, HAVE_VOLUME_PERF_OPS_READ |
+ HAVE_VOLUME_PERF_OPS_WRITE |
+ HAVE_VOLUME_PERF_LATENCY_READ |
+ HAVE_VOLUME_PERF_LATENCY_WRITE)) {
gauge_t latency_per_op_read;
gauge_t latency_per_op_write;
uint64_t snap_reserve_free = v->snap_reserved;
uint64_t snap_norm_used = v->snap_used;
- snprintf(plugin_instance, sizeof(plugin_instance), "volume-%s", v->name);
+ ssnprintf(plugin_instance, sizeof(plugin_instance), "volume-%s", v->name);
- if (HAS_ALL_FLAGS(v->flags,
- HAVE_VOLUME_USAGE_SNAP_USED |
- HAVE_VOLUME_USAGE_SNAP_RSVD)) {
+ if (HAS_ALL_FLAGS(v->flags, HAVE_VOLUME_USAGE_SNAP_USED |
+ HAVE_VOLUME_USAGE_SNAP_RSVD)) {
if (v->snap_reserved > v->snap_used) {
snap_reserve_free = v->snap_reserved - v->snap_used;
snap_reserve_used = v->snap_used;
/* The space used by snapshots but not reserved for them is included in
* both, norm_used and snap_norm_used. If possible, subtract this here. */
- if (HAS_ALL_FLAGS(v->flags,
- HAVE_VOLUME_USAGE_NORM_USED |
- HAVE_VOLUME_USAGE_SNAP_USED)) {
+ if (HAS_ALL_FLAGS(v->flags, HAVE_VOLUME_USAGE_NORM_USED |
+ HAVE_VOLUME_USAGE_SNAP_USED)) {
if (norm_used >= snap_norm_used)
norm_used -= snap_norm_used;
else {
"df_complex", "snap_reserved", (double)snap_reserve_free,
/* timestamp = */ 0, interval);
- if (HAS_ALL_FLAGS(v->flags,
- HAVE_VOLUME_USAGE_SNAP_USED |
- HAVE_VOLUME_USAGE_SNAP_RSVD))
+ if (HAS_ALL_FLAGS(v->flags, HAVE_VOLUME_USAGE_SNAP_USED |
+ HAVE_VOLUME_USAGE_SNAP_RSVD))
submit_double(hostname, /* plugin instance = */ plugin_instance,
"df_complex", "snap_reserve_used",
(double)snap_reserve_used, /* timestamp = */ 0, interval);
if ((v->flags & IS_VOLUME_USAGE_OFFLINE) != 0) {
n.severity = NOTIF_OKAY;
- snprintf(n.message, sizeof(n.message), "Volume %s is now online.", v->name);
+ ssnprintf(n.message, sizeof(n.message), "Volume %s is now online.",
+ v->name);
v->flags &= ~IS_VOLUME_USAGE_OFFLINE;
} else {
n.severity = NOTIF_WARNING;
- snprintf(n.message, sizeof(n.message), "Volume %s is now offline.",
- v->name);
+ ssnprintf(n.message, sizeof(n.message), "Volume %s is now offline.",
+ v->name);
v->flags |= IS_VOLUME_USAGE_OFFLINE;
}
if (volume_name == NULL)
continue;
- snprintf(plugin_instance, sizeof(plugin_instance), "quota-%s-%s",
- volume_name, tree_name);
+ ssnprintf(plugin_instance, sizeof(plugin_instance), "quota-%s-%s",
+ volume_name, tree_name);
value = na_child_get_uint64(elem_quota, "disk-used", UINT64_MAX);
if (value != UINT64_MAX) {
continue;
/* possible TODO: make plugin instance configurable */
- snprintf(plugin_instance, sizeof(plugin_instance), "snapvault-%s",
- dest_path);
+ ssnprintf(plugin_instance, sizeof(plugin_instance), "snapvault-%s",
+ dest_path);
submit_double(hostname, plugin_instance, /* type = */ "delay", NULL,
(double)value, /* timestamp = */ 0, interval);
char cb_name[256];
if (host->vfiler)
- snprintf(cb_name, sizeof(cb_name), "netapp-%s-%s", host->name,
- host->vfiler);
+ ssnprintf(cb_name, sizeof(cb_name), "netapp-%s-%s", host->name,
+ host->vfiler);
else
- snprintf(cb_name, sizeof(cb_name), "netapp-%s", host->name);
+ ssnprintf(cb_name, sizeof(cb_name), "netapp-%s", host->name);
plugin_register_complex_read(
/* group = */ NULL, cb_name,
/* callback = */ cna_read,
/* interval = */ host->interval,
&(user_data_t){
- .data = host, .free_func = (void *)free_host_config,
+ .data = host,
+ .free_func = (void *)free_host_config,
});
return 0;
const char *type_instance, derive_t rx, derive_t tx) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
vl.values = values;
if (strcmp(tc_type, "filter") == 0)
numberic_id = tm->tcm_parent;
- snprintf(tc_inst, sizeof(tc_inst), "%s-%x:%x", kind, numberic_id >> 16,
- numberic_id & 0x0000FFFF);
+ ssnprintf(tc_inst, sizeof(tc_inst), "%s-%x:%x", kind, numberic_id >> 16,
+ numberic_id & 0x0000FFFF);
}
DEBUG("netlink plugin: qos_filter_cb: got %s for %s (%i).", tc_type, dev,
stats_submitted = true;
- int r = snprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type,
- tc_inst);
+ int r = ssnprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type,
+ tc_inst);
if ((size_t)r >= sizeof(type_instance)) {
ERROR("netlink plugin: type_instance truncated to %zu bytes, need %d",
sizeof(type_instance), r);
if (!stats_submitted && ts != NULL) {
char type_instance[DATA_MAX_NAME_LEN];
- int r = snprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type,
- tc_inst);
+ int r = ssnprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type,
+ tc_inst);
if ((size_t)r >= sizeof(type_instance)) {
ERROR("netlink plugin: type_instance truncated to %zu bytes, need %d",
sizeof(type_instance), r);
} else if ((strcasecmp(key, "QDisc") == 0) ||
(strcasecmp(key, "Class") == 0) ||
(strcasecmp(key, "Filter") == 0)) {
- if ((fields_num < 1) || (fields_num > 2)) {
+ if (fields_num > 2) {
ERROR("netlink plugin: Invalid number of fields for option "
"`%s'. Got %i, expected 1 or 2.",
key, fields_num);
} data;
struct sockent *next;
+ pthread_mutex_t lock;
} sockent_t;
/* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
LOG_ERR, &complain_forwarding,
"network plugin: A notification has been received via the network "
"and forwarding is enabled. Forwarding of notifications is currently "
- "not supported, because there is not loop-deteciton available. "
+ "not supported, because there is not loop-detection available. "
"Please contact the collectd mailing list if you need this "
"feature.");
}
return 0;
} /* }}} int parse_part_sign_sha256 */
-/* #endif HAVE_GCRYPT_H */
+ /* #endif HAVE_GCRYPT_H */
#else /* if !HAVE_GCRYPT_H */
static int parse_part_sign_sha256(sockent_t *se, /* {{{ */
return 0;
} /* }}} int parse_part_encr_aes256 */
-/* #endif HAVE_GCRYPT_H */
+ /* #endif HAVE_GCRYPT_H */
#else /* if !HAVE_GCRYPT_H */
static int parse_part_encr_aes256(sockent_t *se, /* {{{ */
sfree(se->node);
sfree(se->service);
+ pthread_mutex_destroy(&se->lock);
if (se->type == SOCKENT_TYPE_CLIENT)
free_sockent_client(&se->data.client);
ERROR("network plugin: setsockopt (bind-if): %s", STRERRNO);
return -1;
}
-/* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
+ /* #endif HAVE_IF_INDEXTONAME && SO_BINDTODEVICE */
#else
WARNING("network plugin: Cannot set the interface on a unicast "
se->service = NULL;
se->interface = 0;
se->next = NULL;
+ pthread_mutex_init(&se->lock, NULL);
if (type == SOCKENT_TYPE_SERVER) {
se->data.server.fd = NULL;
client->fd = -1;
}
+ DEBUG("network plugin: free (se = %p, addr = %p);", (void *)se,
+ (void *)client->addr);
sfree(client->addr);
client->addrlen = 0;
client->fd = -1;
continue;
}
+ DEBUG("network plugin: alloc (se = %p, addr = %p);", (void *)se,
+ (void *)client->addr);
assert(sizeof(*client->addr) >= ai_ptr->ai_addrlen);
memcpy(client->addr, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
buffer_len);
for (sockent_t *se = sending_sockets; se != NULL; se = se->next) {
+ pthread_mutex_lock(&se->lock);
#if HAVE_GCRYPT_H
if (se->data.client.security_level == SECURITY_LEVEL_ENCRYPT)
network_send_buffer_encrypted(se, buffer, buffer_len);
else /* if (se->data.client.security_level == SECURITY_LEVEL_NONE) */
#endif /* HAVE_GCRYPT_H */
network_send_buffer_plain(se, buffer, buffer_len);
+ pthread_mutex_unlock(&se->lock);
} /* for (sending_sockets) */
} /* }}} void network_send_buffer */
*bind_address = malloc(sizeof(**bind_address));
if (*bind_address == NULL) {
ERROR("network plugin: network_config_set_bind_address: malloc failed.");
+ freeaddrinfo(res);
return -1;
}
(*bind_address)->ss_family = res->ai_family;
--- /dev/null
+/**
+ * Copyright (C) 2019 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>
+ **/
+
+#define TEST_PLUGIN_NETWORK 1
+
+#include "network.c" /* (sic) */
+
+#include "testing.h"
+
+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;
+}
+
+DEF_TEST(parse_packet) {
+ sockent_t se = {
+ .data.server =
+ (struct sockent_server){
+#if HAVE_GCRYPT_H
+ .cypher = NULL,
+ .userdb = NULL,
+ .security_level = SECURITY_LEVEL_NONE,
+#endif
+ },
+ };
+
+ for (size_t i = 0; i < sizeof(raw_packet_data) / sizeof(raw_packet_data[0]);
+ i++) {
+ uint8_t buffer[network_config_packet_size];
+ size_t buffer_size = sizeof(buffer);
+
+ EXPECT_EQ_INT(0, decode_string(raw_packet_data[i], buffer, &buffer_size));
+ EXPECT_EQ_INT(0, parse_packet(&se, buffer, buffer_size, 0, NULL));
+ }
+ EXPECT_EQ_INT(139, (int)stats_values_dispatched);
+
+ return 0;
+}
+
+int main() {
+ RUN_TEST(parse_packet);
+
+ END_TEST;
+}
#if KERNEL_LINUX
static int nfs_init(void) { return 0; }
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
static int nfs_init(void) {
return 0;
}
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
static int nfs_read(void) {
curl_easy_setopt(curl, CURLOPT_PASSWORD, (pass == NULL) ? "" : pass);
#else
static char credentials[1024];
- int status = snprintf(credentials, sizeof(credentials), "%s:%s", user,
- pass == NULL ? "" : pass);
+ int status = ssnprintf(credentials, sizeof(credentials), "%s:%s", user,
+ pass == NULL ? "" : pass);
if ((status < 0) || ((size_t)status >= sizeof(credentials))) {
ERROR("nginx plugin: Credentials would have been truncated.");
return -1;
timeout = fail_timeout;
}
- snprintf(summary, sizeof(summary), "collectd %s notification",
- (NOTIF_FAILURE == n->severity)
- ? "FAILURE"
- : (NOTIF_WARNING == n->severity)
- ? "WARNING"
- : (NOTIF_OKAY == n->severity) ? "OKAY" : "UNKNOWN");
+ ssnprintf(summary, sizeof(summary), "collectd %s notification",
+ (NOTIF_FAILURE == n->severity)
+ ? "FAILURE"
+ : (NOTIF_WARNING == n->severity)
+ ? "WARNING"
+ : (NOTIF_OKAY == n->severity) ? "OKAY" : "UNKNOWN");
notification = notify_notification_new(summary, n->message, NULL
#if NOTIFY_CHECK_VERSION(0, 7, 0)
- );
+ );
#else
,
NULL);
static int notify_email_init(void) {
char server[MAXSTRING];
- snprintf(server, sizeof(server), "%s:%i",
- (smtp_host == NULL) ? DEFAULT_SMTP_HOST : smtp_host, smtp_port);
+ ssnprintf(server, sizeof(server), "%s:%i",
+ (smtp_host == NULL) ? DEFAULT_SMTP_HOST : smtp_host, smtp_port);
pthread_mutex_lock(&session_lock);
char *buf_ptr = buf;
int buf_len = sizeof(buf);
- snprintf(severity, sizeof(severity), "%s",
- (n->severity == NOTIF_FAILURE)
- ? "FAILURE"
- : ((n->severity == NOTIF_WARNING)
- ? "WARNING"
- : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN")));
+ ssnprintf(severity, sizeof(severity), "%s",
+ (n->severity == NOTIF_FAILURE)
+ ? "FAILURE"
+ : ((n->severity == NOTIF_WARNING)
+ ? "WARNING"
+ : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN")));
- snprintf(subject, sizeof(subject),
- (email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject,
- severity, n->host);
+ ssnprintf(subject, sizeof(subject),
+ (email_subject == NULL) ? DEFAULT_SMTP_SUBJECT : email_subject,
+ severity, n->host);
localtime_r(&CDTIME_T_TO_TIME_T(n->time), ×tamp_tm);
strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S",
timestamp_str[sizeof(timestamp_str) - 1] = '\0';
/* Let's make RFC822 message text with \r\n EOLs */
- int status = snprintf(buf, buf_len,
- "MIME-Version: 1.0\r\n"
- "Content-Type: text/plain; charset=\"US-ASCII\"\r\n"
- "Content-Transfer-Encoding: 8bit\r\n"
- "Subject: %s\r\n"
- "\r\n"
- "%s - %s@%s\r\n"
- "\r\n",
- subject, timestamp_str, severity, n->host);
+ int status = ssnprintf(buf, buf_len,
+ "MIME-Version: 1.0\r\n"
+ "Content-Type: text/plain; charset=\"US-ASCII\"\r\n"
+ "Content-Transfer-Encoding: 8bit\r\n"
+ "Subject: %s\r\n"
+ "\r\n"
+ "%s - %s@%s\r\n"
+ "\r\n",
+ subject, timestamp_str, severity, n->host);
if (status > 0) {
buf_ptr += status;
#define APPEND(format, value) \
if ((buf_len > 0) && (strlen(value) > 0)) { \
- status = snprintf(buf_ptr, buf_len, format "\r\n", value); \
+ status = ssnprintf(buf_ptr, buf_len, format "\r\n", value); \
if (status > 0) { \
buf_ptr += status; \
buf_len -= status; \
/* name = */ cb_name,
/* callback = */ nut_read,
/* interval = */ 0,
- /* user_data = */ &(user_data_t){
- .data = ups, .free_func = free_nut_ups_t,
+ /* user_data = */
+ &(user_data_t){
+ .data = ups,
+ .free_func = free_nut_ups_t,
});
sfree(cb_name);
char file[4096];
char *endptr;
- snprintf(file, sizeof(file), "%s/%s", path,
- family_info->features[i].filename);
+ ssnprintf(file, sizeof(file), "%s/%s", path,
+ family_info->features[i].filename);
file[sizeof(file) - 1] = '\0';
buffer = NULL;
char subpath[4096];
int status;
- status = snprintf(subpath, sizeof(subpath), "%s/main", path);
+ status = ssnprintf(subpath, sizeof(subpath), "%s/main", path);
if ((status > 0) && (status < (int)sizeof(subpath)))
cow_read_bus(subpath);
- status = snprintf(subpath, sizeof(subpath), "%s/aux", path);
+ status = ssnprintf(subpath, sizeof(subpath), "%s/aux", path);
if ((status > 0) && (status < (int)sizeof(subpath)))
cow_read_bus(subpath);
dummy = NULL;
if (strcmp("/", path) == 0)
- status = snprintf(subpath, sizeof(subpath), "/%s", buffer_ptr);
+ status = ssnprintf(subpath, sizeof(subpath), "/%s", buffer_ptr);
else
- status = snprintf(subpath, sizeof(subpath), "%s/%s", path, buffer_ptr);
+ status = ssnprintf(subpath, sizeof(subpath), "%s/%s", path, buffer_ptr);
if ((status <= 0) || (status >= (int)sizeof(subpath)))
continue;
if ((olmbdb_list =
ldap_get_values_len(st->ld, e, "olmBDBEntryCache")) != NULL) {
olmbdb_data = *olmbdb_list[0];
- snprintf(typeinst, sizeof(typeinst), "bdbentrycache-%s",
- nc_data.bv_val);
+ ssnprintf(typeinst, sizeof(typeinst), "bdbentrycache-%s",
+ nc_data.bv_val);
cldap_submit_gauge("cache_size", typeinst, atoll(olmbdb_data.bv_val),
st);
ldap_value_free_len(olmbdb_list);
if ((olmbdb_list = ldap_get_values_len(st->ld, e, "olmBDBDNCache")) !=
NULL) {
olmbdb_data = *olmbdb_list[0];
- snprintf(typeinst, sizeof(typeinst), "bdbdncache-%s", nc_data.bv_val);
+ ssnprintf(typeinst, sizeof(typeinst), "bdbdncache-%s",
+ nc_data.bv_val);
cldap_submit_gauge("cache_size", typeinst, atoll(olmbdb_data.bv_val),
st);
ldap_value_free_len(olmbdb_list);
if ((olmbdb_list = ldap_get_values_len(st->ld, e, "olmBDBIDLCache")) !=
NULL) {
olmbdb_data = *olmbdb_list[0];
- snprintf(typeinst, sizeof(typeinst), "bdbidlcache-%s",
- nc_data.bv_val);
+ ssnprintf(typeinst, sizeof(typeinst), "bdbidlcache-%s",
+ nc_data.bv_val);
cldap_submit_gauge("cache_size", typeinst, atoll(olmbdb_data.bv_val),
st);
ldap_value_free_len(olmbdb_list);
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");
+ ssnprintf(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,
+ .data = st,
+ .free_func = cldap_free,
});
} /* }}} int cldap_config_add */
derive_t tx) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
/* NOTE ON THE NEW NAMING SCHEMA:
derive_t uncompressed, derive_t compressed) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = uncompressed}, {.derive = compressed},
+ {.derive = uncompressed},
+ {.derive = compressed},
};
vl.values = values;
/* callback = */ openvpn_read,
/* interval = */ 0,
&(user_data_t){
- .data = instance, .free_func = openvpn_free,
+ .data = instance,
+ .free_func = openvpn_free,
});
if (status == EINVAL) {
- WARNING("openvpn plugin: status filename \"%s\" "
- "already used, please choose a "
- "different one.",
- status_name);
+ ERROR("openvpn plugin: status filename \"%s\" "
+ "already used, please choose a "
+ "different one.",
+ status_name);
return -1;
}
if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO)) {
char errfunc[256];
- snprintf(errfunc, sizeof(errfunc), "OCILogon(\"%s\")", db->connect_id);
+ ssnprintf(errfunc, sizeof(errfunc), "OCILogon(\"%s\")", db->connect_id);
o_report_error("o_read_database", db->name, NULL, errfunc, oci_error);
DEBUG("oracle plugin: OCILogon (%s): db->oci_service_context = %p;",
return NULL;
}
opt_buff = new_buff;
- int ret = snprintf(opt_buff + buff_off, buff_size - buff_off, option_fmt,
- iface->name);
+ int ret = ssnprintf(opt_buff + buff_off, buff_size - buff_off, option_fmt,
+ iface->name);
if (ret < 0) {
sfree(opt_buff);
return NULL;
}
/* fill the notification data */
- snprintf(n.message, sizeof(n.message),
- "link state of \"%s\" interface has been changed to \"%s\"",
- ifinfo->name, msg_link_status);
+ ssnprintf(n.message, sizeof(n.message),
+ "link state of \"%s\" interface has been changed to \"%s\"",
+ ifinfo->name, msg_link_status);
sstrncpy(n.host, hostname_g, sizeof(n.host));
sstrncpy(n.plugin_instance, ifinfo->name, sizeof(n.plugin_instance));
sstrncpy(n.type, "gauge", sizeof(n.type));
}
strjoin(devname, sizeof(devname),
(char *[]){
- bridge->name, port->name, iface->name,
+ bridge->name,
+ port->name,
+ iface->name,
},
3, ".");
ovs_stats_submit_one(devname, "if_collisions", NULL,
for (interface_list_t *iface = port->iface; iface != NULL;
iface = iface->next) {
- snprintf(key_str, sizeof(key_str), "uuid%d", i);
+ ssnprintf(key_str, sizeof(key_str), "uuid%d", i);
meta_data_add_string(meta, key_str, iface->iface_uuid);
if (strlen(iface->ex_vm_id)) {
- snprintf(key_str, sizeof(key_str), "vm-uuid%d", i);
+ ssnprintf(key_str, sizeof(key_str), "vm-uuid%d", i);
meta_data_add_string(meta, key_str, iface->ex_vm_id);
}
if (strlen(iface->ex_iface_id)) {
- snprintf(key_str, sizeof(key_str), "iface-id%d", i);
+ ssnprintf(key_str, sizeof(key_str), "iface-id%d", i);
meta_data_add_string(meta, key_str, iface->ex_iface_id);
}
}
}
bridge_list_t *bridge = port->br;
- snprintf(devname, sizeof(devname), "%s.%s", bridge->name, port->name);
+ ssnprintf(devname, sizeof(devname), "%s.%s", bridge->name, port->name);
ovs_stats_submit_one(devname, "if_collisions", NULL,
ovs_stats_get_port_stat_value(port, collisions), meta);
ovs_stats_submit_two(devname, "if_dropped", NULL,
// ifaces_list is [[ "uuid", "<some_uuid>" ], [ "uuid",
// "<another_uuid>" ], ... ]]
- for (int i = 0; i < YAJL_GET_ARRAY(ifaces_list)->len; i++) {
+ for (size_t i = 0; i < YAJL_GET_ARRAY(ifaces_list)->len; i++) {
yajl_val iface_tuple = YAJL_GET_ARRAY(ifaces_list)->values[i];
// iface_tuple is [ "uuid", "<some_uuid>" ]
/* Find offset of PCI Express Capability Structure
* in PCI configuration space.
* Returns offset, -1 if not found.
-**/
+ **/
static int pcie_find_cap_exp(pcie_device_t *dev) {
int pos = pcie_read8(dev, PCI_CAPABILITY_LIST) & ~3;
/* Find offset of Advanced Error Reporting Capability.
* Returns AER offset, -1 if not found.
-**/
+ **/
static int pcie_find_ecap_aer(pcie_device_t *dev) {
int pos = PCIE_ECAP_OFFSET;
uint32_t header = pcie_read32(dev, pos);
static char *get_module_name(char *buf, size_t buf_len, const char *module) {
int status = 0;
if (base_name[0] == '\0')
- status = snprintf(buf, buf_len, "%s", module);
+ status = ssnprintf(buf, buf_len, "%s", module);
else
- status = snprintf(buf, buf_len, "%s::%s", base_name, module);
+ status = ssnprintf(buf, buf_len, "%s::%s", base_name, module);
if ((status < 0) || ((unsigned int)status >= buf_len))
return NULL;
return buf;
* is ignored. */
#define C_PSQL_PAR_APPEND(buf, buf_len, parameter, value) \
if ((0 < (buf_len)) && (NULL != (value)) && ('\0' != *(value))) { \
- int s = snprintf(buf, buf_len, " %s = '%s'", parameter, value); \
+ int s = ssnprintf(buf, buf_len, " %s = '%s'", parameter, value); \
if (0 < s) { \
buf += s; \
buf_len -= s; \
if ((!db) || (!db->database))
return -1;
- status = snprintf(buf, buf_len, "dbname = '%s'", db->database);
+ status = ssnprintf(buf, buf_len, "dbname = '%s'", db->database);
if (0 < status) {
buf += status;
buf_len -= status;
params[i] = db->user;
break;
case C_PSQL_PARAM_INTERVAL:
- snprintf(interval, sizeof(interval), "%.3f",
- CDTIME_T_TO_DOUBLE(plugin_get_interval()));
+ ssnprintf(interval, sizeof(interval), "%.3f",
+ CDTIME_T_TO_DOUBLE(plugin_get_interval()));
params[i] = interval;
break;
case C_PSQL_PARAM_INSTANCE:
str_len = string_len;
for (size_t i = 0; i < ds->ds_num; ++i) {
- int status = snprintf(str_ptr, str_len, ",'%s'", ds->ds[i].name);
+ int status = ssnprintf(str_ptr, str_len, ",'%s'", ds->ds[i].name);
if (status < 1)
return NULL;
int status;
if (store_rates)
- status = snprintf(str_ptr, str_len, ",'gauge'");
+ status = ssnprintf(str_ptr, str_len, ",'gauge'");
else
- status = snprintf(str_ptr, str_len, ",'%s'",
- DS_TYPE_TO_STRING(ds->ds[i].type));
+ status = ssnprintf(str_ptr, str_len, ",'%s'",
+ DS_TYPE_TO_STRING(ds->ds[i].type));
if (status < 1) {
str_len = 0;
if (ds->ds[i].type == DS_TYPE_GAUGE)
status =
- snprintf(str_ptr, str_len, "," GAUGE_FORMAT, vl->values[i].gauge);
+ ssnprintf(str_ptr, str_len, "," GAUGE_FORMAT, vl->values[i].gauge);
else if (store_rates) {
if (rates == NULL)
rates = uc_get_rate(ds, vl);
return NULL;
}
- status = snprintf(str_ptr, str_len, ",%lf", rates[i]);
+ status = ssnprintf(str_ptr, str_len, ",%lf", rates[i]);
} else if (ds->ds[i].type == DS_TYPE_COUNTER)
- status = snprintf(str_ptr, str_len, ",%" PRIu64,
- (uint64_t)vl->values[i].counter);
+ status = ssnprintf(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);
+ status = ssnprintf(str_ptr, str_len, ",%" PRIi64, vl->values[i].derive);
else if (ds->ds[i].type == DS_TYPE_ABSOLUTE)
- status = snprintf(str_ptr, str_len, ",%" PRIu64, vl->values[i].absolute);
+ status = ssnprintf(str_ptr, str_len, ",%" PRIu64, vl->values[i].absolute);
if (status < 1) {
str_len = 0;
if (db->writers_num > 0) {
char cb_name[DATA_MAX_NAME_LEN];
- snprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->database);
+ ssnprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->database);
if (!had_flush) {
plugin_unregister_flush("postgresql");
}
}
- snprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->instance);
+ ssnprintf(cb_name, sizeof(cb_name), "postgresql-%s", db->instance);
user_data_t ud = {.data = db, .free_func = c_psql_database_delete};
answers-slow counts the number of queries answered after 1 second
answers0-1 counts the number of queries answered within 1 millisecond
answers1-10 counts the number of queries answered within 10
-milliseconds
+ milliseconds
answers10-100 counts the number of queries answered within 100
-milliseconds
+ milliseconds
answers100-1000 counts the number of queries answered within 1 second
cache-bytes size of the cache in bytes (since 3.3.1)
cache-entries shows the number of entries in the cache
cache-hits counts the number of cache hits since starting, this does
-not include hits that got answered from the packet-cache
+ not include hits that got answered from the packet-cache
cache-misses counts the number of cache misses since starting
case-mismatches counts the number of mismatches in character case since
-starting
+ starting
chain-resends number of queries chained to existing outstanding query
client-parse-errors counts number of client packets that could not be parsed
concurrent-queries shows the number of MThreads currently running
dlg-only-drops number of records dropped because of delegation only
-setting
+ setting
dont-outqueries number of outgoing queries dropped because of 'dont-query'
-setting (since 3.3)
+ setting (since 3.3)
edns-ping-matches number of servers that sent a valid EDNS PING respons
edns-ping-mismatches number of servers that sent an invalid EDNS PING response
failed-host-entries number of servers that failed to resolve
ipv6-outqueries number of outgoing queries over IPv6
ipv6-questions counts all End-user initiated queries with the RD bit set,
-received over IPv6 UDP
+ received over IPv6 UDP
malloc-bytes returns the number of bytes allocated by the process
-(broken, always returns 0)
+ (broken, always returns 0)
max-mthread-stack maximum amount of thread stack ever used
negcache-entries shows the number of entries in the Negative answer cache
no-packet-error number of errorneous received packets
noedns-outqueries number of queries sent out without EDNS
noerror-answers counts the number of times it answered NOERROR since
-starting
+ starting
noping-outqueries number of queries sent out without ENDS PING
nsset-invalidations number of times an nsset was dropped because it no longer
-worked
+ worked
nsspeeds-entries shows the number of entries in the NS speeds map
nxdomain-answers counts the number of times it answered NXDOMAIN since
-starting
+ starting
outgoing-timeouts counts the number of timeouts on outgoing UDP queries
-since starting
+ since starting
over-capacity-drops questions dropped because over maximum concurrent query
-limit (since 3.2)
+ limit (since 3.2)
packetcache-bytes size of the packet cache in bytes (since 3.3.1)
packetcache-entries size of packet cache (since 3.2)
packetcache-hits packet cache hits (since 3.2)
qa-latency shows the current latency average
questions counts all end-user initiated queries with the RD bit set
resource-limits counts number of queries that could not be performed
-because of resource limits
+ because of resource limits
security-status security status based on security polling
server-parse-errors counts number of server replied packets that could not be
-parsed
+ parsed
servfail-answers counts the number of times it answered SERVFAIL since
-starting
+ starting
spoof-prevents number of times PowerDNS considered itself spoofed, and
-dropped the data
+ dropped the data
sys-msec number of CPU milliseconds spent in 'system' mode
tcp-client-overflow number of times an IP address was denied TCP access
-because it already had too many connections
+ because it already had too many connections
tcp-clients counts the number of currently active TCP/IP clients
tcp-outqueries counts the number of outgoing TCP queries since starting
tcp-questions counts all incoming TCP queries (since starting)
throttle-entries shows the number of entries in the throttle map
throttled-out counts the number of throttled outgoing UDP queries since
-starting
+ starting
throttled-outqueries idem to throttled-out
unauthorized-tcp number of TCP questions denied because of allow-from
-restrictions
+ restrictions
unauthorized-udp number of UDP questions denied because of allow-from
-restrictions
+ restrictions
unexpected-packets number of answers from remote servers that were unexpected
-(might point to spoofing)
+ (might point to spoofing)
unreachables number of times nameservers were unreachable since
-starting
+ starting
uptime number of seconds process has been running (since 3.1.5)
user-msec number of CPU milliseconds spent in 'user' mode
}}} */
{"unauthorized-tcp", "counter", "denied-unauthorized_tcp"},
{"unauthorized-udp", "counter", "denied-unauthorized_udp"},
{"unexpected-packets", "dns_answer", "unexpected"},
+ {"unreachables", "counter", "unreachables"},
{"uptime", "uptime", NULL}}; /* }}} */
static int lookup_table_length = STATIC_ARRAY_SIZE(lookup_table);
pset_list_len = 0;
return -1;
}
-/* #endif HAVE_THREAD_INFO */
+ /* #endif HAVE_THREAD_INFO */
#elif KERNEL_LINUX
pagesize_g = sysconf(_SC_PAGESIZE);
}
}
#endif
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKVM_GETPROCS && \
(HAVE_STRUCT_KINFO_PROC_FREEBSD || HAVE_STRUCT_KINFO_PROC_OPENBSD)
pagesize = getpagesize();
-/* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD ||
- * HAVE_STRUCT_KINFO_PROC_OPENBSD) */
+ /* #endif HAVE_LIBKVM_GETPROCS && (HAVE_STRUCT_KINFO_PROC_FREEBSD ||
+ * HAVE_STRUCT_KINFO_PROC_OPENBSD) */
#elif HAVE_PROCINFO_H
pagesize = getpagesize();
snprintf(filename, sizeof(filename), "/proc/%li/stat", pid);
- status = read_file_contents(filename, buffer, sizeof(buffer) - 1);
+ status = read_text_file_contents(filename, buffer, sizeof(buffer));
if (status <= 0)
return -1;
buffer_len = (size_t)status;
- buffer[buffer_len] = 0;
/* The name of the process is enclosed in parens. Since the name can
* contain parens itself, spaces, numbers and pretty much everything
snprintf(path, sizeof(path), "/proc/%li/psinfo", pid);
- status = read_file_contents(path, (void *)&info, sizeof(info));
+ status = read_file_contents(path, &info, sizeof(info));
if ((status < 0) || (((size_t)status) != sizeof(info))) {
ERROR("processes plugin: Unexpected return value "
"while reading \"%s\": "
/*
* TODO: context switch counters for Solaris
-*/
+ */
ps->cswitch_vol = -1;
ps->cswitch_invol = -1;
for (ps = list_head_g; ps != NULL; ps = ps->next)
ps_submit_proc_list(ps);
-/* #endif HAVE_THREAD_INFO */
+ /* #endif HAVE_THREAD_INFO */
#elif KERNEL_LINUX
int running = 0;
ps_submit_proc_list(ps_ptr);
read_fork_rate();
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD
int running = 0;
for (procstat_t *ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
ps_submit_proc_list(ps_ptr);
-/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
+ /* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_FREEBSD */
#elif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_OPENBSD
int running = 0;
for (procstat_t *ps_ptr = list_head_g; ps_ptr != NULL; ps_ptr = ps_ptr->next)
ps_submit_proc_list(ps_ptr);
-/* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_OPENBSD */
+ /* #endif HAVE_LIBKVM_GETPROCS && HAVE_STRUCT_KINFO_PROC_OPENBSD */
#elif HAVE_PROCINFO_H
/* AIX */
for (procstat_t *ps = list_head_g; ps != NULL; ps = ps->next)
ps_submit_proc_list(ps);
-/* #endif HAVE_PROCINFO_H */
+ /* #endif HAVE_PROCINFO_H */
#elif KERNEL_SOLARIS
/*
--- /dev/null
+/**
+ * collectd - src/procevent.c
+ *
+ * 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:
+ * Red Hat NFVPE
+ * Andrew Bays <abays at redhat.com>
+ **/
+
+#include "collectd.h"
+
+#include "plugin.h"
+#include "utils/common/common.h"
+#include "utils/ignorelist/ignorelist.h"
+#include "utils_complain.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <dirent.h>
+#include <linux/cn_proc.h>
+#include <linux/connector.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <yajl/yajl_common.h>
+#include <yajl/yajl_gen.h>
+#if HAVE_YAJL_YAJL_VERSION_H
+#include <yajl/yajl_version.h>
+#endif
+#if defined(YAJL_MAJOR) && (YAJL_MAJOR > 1)
+#define HAVE_YAJL_V2 1
+#endif
+
+#define PROCEVENT_EXITED 0
+#define PROCEVENT_STARTED 1
+#define PROCEVENT_FIELDS 3 // pid, status, timestamp
+#define BUFSIZE 512
+#define PROCDIR "/proc"
+#define RBUF_PROC_ID_INDEX 0
+#define RBUF_PROC_STATUS_INDEX 1
+#define RBUF_TIME_INDEX 2
+
+#define PROCEVENT_DOMAIN_FIELD "domain"
+#define PROCEVENT_DOMAIN_VALUE "fault"
+#define PROCEVENT_EVENT_ID_FIELD "eventId"
+#define PROCEVENT_EVENT_NAME_FIELD "eventName"
+#define PROCEVENT_EVENT_NAME_DOWN_VALUE "down"
+#define PROCEVENT_EVENT_NAME_UP_VALUE "up"
+#define PROCEVENT_LAST_EPOCH_MICROSEC_FIELD "lastEpochMicrosec"
+#define PROCEVENT_PRIORITY_FIELD "priority"
+#define PROCEVENT_PRIORITY_VALUE "high"
+#define PROCEVENT_REPORTING_ENTITY_NAME_FIELD "reportingEntityName"
+#define PROCEVENT_REPORTING_ENTITY_NAME_VALUE "collectd procevent plugin"
+#define PROCEVENT_SEQUENCE_FIELD "sequence"
+#define PROCEVENT_SEQUENCE_VALUE "0"
+#define PROCEVENT_SOURCE_NAME_FIELD "sourceName"
+#define PROCEVENT_START_EPOCH_MICROSEC_FIELD "startEpochMicrosec"
+#define PROCEVENT_VERSION_FIELD "version"
+#define PROCEVENT_VERSION_VALUE "1.0"
+
+#define PROCEVENT_ALARM_CONDITION_FIELD "alarmCondition"
+#define PROCEVENT_ALARM_INTERFACE_A_FIELD "alarmInterfaceA"
+#define PROCEVENT_EVENT_SEVERITY_FIELD "eventSeverity"
+#define PROCEVENT_EVENT_SEVERITY_CRITICAL_VALUE "CRITICAL"
+#define PROCEVENT_EVENT_SEVERITY_NORMAL_VALUE "NORMAL"
+#define PROCEVENT_EVENT_SOURCE_TYPE_FIELD "eventSourceType"
+#define PROCEVENT_EVENT_SOURCE_TYPE_VALUE "process"
+#define PROCEVENT_FAULT_FIELDS_FIELD "faultFields"
+#define PROCEVENT_FAULT_FIELDS_VERSION_FIELD "faultFieldsVersion"
+#define PROCEVENT_FAULT_FIELDS_VERSION_VALUE "1.0"
+#define PROCEVENT_SPECIFIC_PROBLEM_FIELD "specificProblem"
+#define PROCEVENT_SPECIFIC_PROBLEM_DOWN_VALUE "down"
+#define PROCEVENT_SPECIFIC_PROBLEM_UP_VALUE "up"
+#define PROCEVENT_VF_STATUS_FIELD "vfStatus"
+#define PROCEVENT_VF_STATUS_CRITICAL_VALUE "Ready to terminate"
+#define PROCEVENT_VF_STATUS_NORMAL_VALUE "Active"
+
+/*
+ * Private data types
+ */
+
+typedef struct {
+ int head;
+ int tail;
+ int maxLen;
+ cdtime_t **buffer;
+} circbuf_t;
+
+struct processlist_s {
+ char *process;
+
+ long pid;
+ int32_t last_status;
+
+ struct processlist_s *next;
+};
+typedef struct processlist_s processlist_t;
+
+/*
+ * Private variables
+ */
+static ignorelist_t *ignorelist = NULL;
+
+static int procevent_netlink_thread_loop = 0;
+static int procevent_netlink_thread_error = 0;
+static pthread_t procevent_netlink_thread_id;
+static int procevent_dequeue_thread_loop = 0;
+static pthread_t procevent_dequeue_thread_id;
+static pthread_mutex_t procevent_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t procevent_data_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t procevent_cond = PTHREAD_COND_INITIALIZER;
+static int nl_sock = -1;
+static int buffer_length;
+static circbuf_t ring;
+static processlist_t *processlist_head = NULL;
+static int event_id = 0;
+
+static const char *config_keys[] = {"BufferLength", "Process", "ProcessRegex"};
+static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
+
+/*
+ * Private functions
+ */
+
+static int gen_message_payload(int state, long pid, char *process,
+ cdtime_t timestamp, char **buf) {
+ const unsigned char *buf2;
+ yajl_gen g;
+ char json_str[DATA_MAX_NAME_LEN];
+
+#if !defined(HAVE_YAJL_V2)
+ yajl_gen_config conf = {0};
+#endif
+
+#if HAVE_YAJL_V2
+ size_t len;
+ g = yajl_gen_alloc(NULL);
+ yajl_gen_config(g, yajl_gen_beautify, 0);
+#else
+ unsigned int len;
+ g = yajl_gen_alloc(&conf, NULL);
+#endif
+
+ yajl_gen_clear(g);
+
+ // *** BEGIN common event header ***
+
+ if (yajl_gen_map_open(g) != yajl_gen_status_ok)
+ goto err;
+
+ // domain
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_DOMAIN_FIELD,
+ strlen(PROCEVENT_DOMAIN_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_DOMAIN_VALUE,
+ strlen(PROCEVENT_DOMAIN_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // eventId
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_EVENT_ID_FIELD,
+ strlen(PROCEVENT_EVENT_ID_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ event_id = event_id + 1;
+ if (snprintf(json_str, sizeof(json_str), "%d", event_id) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // eventName
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_EVENT_NAME_FIELD,
+ strlen(PROCEVENT_EVENT_NAME_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "process %s (%ld) %s", process, pid,
+ (state == 0 ? PROCEVENT_EVENT_NAME_DOWN_VALUE
+ : PROCEVENT_EVENT_NAME_UP_VALUE)) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
+ yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // lastEpochMicrosec
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_LAST_EPOCH_MICROSEC_FIELD,
+ strlen(PROCEVENT_LAST_EPOCH_MICROSEC_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "%" PRIu64,
+ CDTIME_T_TO_US(cdtime())) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // priority
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_PRIORITY_FIELD,
+ strlen(PROCEVENT_PRIORITY_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_PRIORITY_VALUE,
+ strlen(PROCEVENT_PRIORITY_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // reportingEntityName
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_REPORTING_ENTITY_NAME_FIELD,
+ strlen(PROCEVENT_REPORTING_ENTITY_NAME_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_REPORTING_ENTITY_NAME_VALUE,
+ strlen(PROCEVENT_REPORTING_ENTITY_NAME_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // sequence
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_SEQUENCE_FIELD,
+ strlen(PROCEVENT_SEQUENCE_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, PROCEVENT_SEQUENCE_VALUE,
+ strlen(PROCEVENT_SEQUENCE_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // sourceName
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_SOURCE_NAME_FIELD,
+ strlen(PROCEVENT_SOURCE_NAME_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)process, strlen(process)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // startEpochMicrosec
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_START_EPOCH_MICROSEC_FIELD,
+ strlen(PROCEVENT_START_EPOCH_MICROSEC_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "%" PRIu64,
+ CDTIME_T_TO_US(timestamp)) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // version
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_VERSION_FIELD,
+ strlen(PROCEVENT_VERSION_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, PROCEVENT_VERSION_VALUE,
+ strlen(PROCEVENT_VERSION_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // *** END common event header ***
+
+ // *** BEGIN fault fields ***
+
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_FAULT_FIELDS_FIELD,
+ strlen(PROCEVENT_FAULT_FIELDS_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_map_open(g) != yajl_gen_status_ok)
+ goto err;
+
+ // alarmCondition
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_ALARM_CONDITION_FIELD,
+ strlen(PROCEVENT_ALARM_CONDITION_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "process %s (%ld) state change",
+ process, pid) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
+ yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // alarmInterfaceA
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_ALARM_INTERFACE_A_FIELD,
+ strlen(PROCEVENT_ALARM_INTERFACE_A_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)process, strlen(process)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // eventSeverity
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_EVENT_SEVERITY_FIELD,
+ strlen(PROCEVENT_EVENT_SEVERITY_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(
+ g,
+ (u_char *)(state == 0 ? PROCEVENT_EVENT_SEVERITY_CRITICAL_VALUE
+ : PROCEVENT_EVENT_SEVERITY_NORMAL_VALUE),
+ strlen((state == 0 ? PROCEVENT_EVENT_SEVERITY_CRITICAL_VALUE
+ : PROCEVENT_EVENT_SEVERITY_NORMAL_VALUE))) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // eventSourceType
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_EVENT_SOURCE_TYPE_FIELD,
+ strlen(PROCEVENT_EVENT_SOURCE_TYPE_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_EVENT_SOURCE_TYPE_VALUE,
+ strlen(PROCEVENT_EVENT_SOURCE_TYPE_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // faultFieldsVersion
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_FAULT_FIELDS_VERSION_FIELD,
+ strlen(PROCEVENT_FAULT_FIELDS_VERSION_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, PROCEVENT_FAULT_FIELDS_VERSION_VALUE,
+ strlen(PROCEVENT_FAULT_FIELDS_VERSION_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // specificProblem
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_SPECIFIC_PROBLEM_FIELD,
+ strlen(PROCEVENT_SPECIFIC_PROBLEM_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (snprintf(json_str, sizeof(json_str), "process %s (%ld) %s", process, pid,
+ (state == 0 ? PROCEVENT_SPECIFIC_PROBLEM_DOWN_VALUE
+ : PROCEVENT_SPECIFIC_PROBLEM_UP_VALUE)) < 0) {
+ goto err;
+ }
+
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
+ yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // vfStatus
+ if (yajl_gen_string(g, (u_char *)PROCEVENT_VF_STATUS_FIELD,
+ strlen(PROCEVENT_VF_STATUS_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(
+ g,
+ (u_char *)(state == 0 ? PROCEVENT_VF_STATUS_CRITICAL_VALUE
+ : PROCEVENT_VF_STATUS_NORMAL_VALUE),
+ strlen((state == 0 ? PROCEVENT_VF_STATUS_CRITICAL_VALUE
+ : PROCEVENT_VF_STATUS_NORMAL_VALUE))) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // *** END fault fields ***
+
+ // close fault and header fields
+ if (yajl_gen_map_close(g) != yajl_gen_status_ok ||
+ yajl_gen_map_close(g) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_get_buf(g, &buf2, &len) != yajl_gen_status_ok)
+ goto err;
+
+ *buf = strdup((char *)buf2);
+
+ if (*buf == NULL) {
+ ERROR("procevent plugin: strdup failed during gen_message_payload: %s",
+ STRERRNO);
+ goto err;
+ }
+
+ yajl_gen_free(g);
+
+ return 0;
+
+err:
+ yajl_gen_free(g);
+ ERROR("procevent plugin: gen_message_payload failed to generate JSON");
+ return -1;
+}
+
+// Does /proc/<pid>/comm contain a process name we are interested in?
+// NOTE: Caller MUST hold procevent_data_lock when calling this function
+static processlist_t *process_check(long pid) {
+ char file[BUFSIZE];
+
+ int len = snprintf(file, sizeof(file), PROCDIR "/%ld/comm", pid);
+
+ if ((len < 0) || (len >= BUFSIZE)) {
+ WARNING("procevent process_check: process name too large");
+ return NULL;
+ }
+
+ FILE *fh;
+
+ if (NULL == (fh = fopen(file, "r"))) {
+ // No /proc/<pid>/comm for this pid, just ignore
+ DEBUG("procevent plugin: no comm file available for pid %ld", pid);
+ return NULL;
+ }
+
+ char buffer[BUFSIZE];
+ int retval = fscanf(fh, "%[^\n]", buffer);
+
+ if (retval < 0) {
+ WARNING("procevent process_check: unable to read comm file for pid %ld",
+ pid);
+ fclose(fh);
+ return NULL;
+ }
+
+ // Now that we have the process name in the buffer, check if we are
+ // even interested in it
+ if (ignorelist_match(ignorelist, buffer) != 0) {
+ DEBUG("procevent process_check: ignoring process %s (%ld)", buffer, pid);
+ fclose(fh);
+ return NULL;
+ }
+
+ if (fh != NULL) {
+ fclose(fh);
+ fh = NULL;
+ }
+
+ //
+ // Go through the processlist linked list and look for the process name
+ // in /proc/<pid>/comm. If found:
+ // 1. If pl->pid is -1, then set pl->pid to <pid> (and return that object)
+ // 2. If pl->pid is not -1, then another <process name> process was already
+ // found. If <pid> == pl->pid, this is an old match, so do nothing.
+ // If the <pid> is different, however, make a new processlist_t and
+ // associate <pid> with it (with the same process name as the existing).
+ //
+
+ processlist_t *match = NULL;
+
+ for (processlist_t *pl = processlist_head; pl != NULL; pl = pl->next) {
+
+ int is_match = (strcmp(buffer, pl->process) == 0 ? 1 : 0);
+
+ if (is_match == 1) {
+ DEBUG("procevent plugin: process %ld name match for %s", pid, buffer);
+
+ if (pl->pid == pid) {
+ // this is a match, and we've already stored the exact pid/name combo
+ DEBUG("procevent plugin: found exact match with name %s, PID %ld for "
+ "incoming PID %ld",
+ pl->process, pl->pid, pid);
+ match = pl;
+ break;
+ } else if (pl->pid == -1) {
+ // this is a match, and we've found a candidate processlist_t to store
+ // this new pid/name combo
+ DEBUG("procevent plugin: reusing pl object with PID %ld for incoming "
+ "PID %ld",
+ pl->pid, pid);
+ pl->pid = pid;
+ match = pl;
+ break;
+ } else if (pl->pid != -1) {
+ // this is a match, but another instance of this process has already
+ // claimed this pid/name combo,
+ // so keep looking
+ DEBUG("procevent plugin: found pl object with matching name for "
+ "incoming PID %ld, but object is in use by PID %ld",
+ pid, pl->pid);
+ match = pl;
+ continue;
+ }
+ }
+ }
+
+ if (match == NULL ||
+ (match != NULL && match->pid != -1 && match->pid != pid)) {
+ // if there wasn't an existing match, OR
+ // if there was a match but the associated processlist_t object already
+ // contained a pid/name combo,
+ // then make a new one and add it to the linked list
+
+ DEBUG("procevent plugin: allocating new processlist_t object for PID %ld "
+ "(%s)",
+ pid, buffer);
+
+ processlist_t *pl2 = calloc(1, sizeof(*pl2));
+ if (pl2 == NULL) {
+ ERROR("procevent plugin: calloc failed during process_check: %s",
+ STRERRNO);
+ return NULL;
+ }
+
+ char *process = strdup(buffer);
+ if (process == NULL) {
+ sfree(pl2);
+ ERROR("procevent plugin: strdup failed during process_check: %s",
+ STRERRNO);
+ return NULL;
+ }
+
+ pl2->process = process;
+ pl2->pid = pid;
+ pl2->next = processlist_head;
+ processlist_head = pl2;
+
+ match = pl2;
+ }
+
+ return match;
+}
+
+// Does our map have this PID or name?
+// NOTE: Caller MUST hold procevent_data_lock when calling this function
+static processlist_t *process_map_check(long pid, char *process) {
+ for (processlist_t *pl = processlist_head; pl != NULL; pl = pl->next) {
+ int match_pid = 0;
+
+ if (pid > 0) {
+ if (pl->pid == pid)
+ match_pid = 1;
+ }
+
+ int match_process = 0;
+
+ if (process != NULL) {
+ if (strcmp(pl->process, process) == 0)
+ match_process = 1;
+ }
+
+ int match = 0;
+
+ if ((pid > 0 && process == NULL && match_pid == 1) ||
+ (pid < 0 && process != NULL && match_process == 1) ||
+ (pid > 0 && process != NULL && match_pid == 1 && match_process == 1)) {
+ match = 1;
+ }
+
+ if (match == 1) {
+ return pl;
+ }
+ }
+
+ return NULL;
+}
+
+static int process_map_refresh(void) {
+ errno = 0;
+ DIR *proc = opendir(PROCDIR);
+
+ if (proc == NULL) {
+ ERROR("procevent plugin: fopen (%s): %s", PROCDIR, STRERRNO);
+ return -1;
+ }
+
+ while (42) {
+ errno = 0;
+ struct dirent *dent = readdir(proc);
+ if (dent == NULL) {
+ if (errno == 0) /* end of directory */
+ break;
+
+ ERROR("procevent plugin: failed to read directory %s: %s", PROCDIR,
+ STRERRNO);
+ closedir(proc);
+ return -1;
+ }
+
+ if (dent->d_name[0] == '.')
+ continue;
+
+ char file[BUFSIZE];
+
+ int len = snprintf(file, sizeof(file), PROCDIR "/%s", dent->d_name);
+ if ((len < 0) || (len >= BUFSIZE))
+ continue;
+
+ struct stat statbuf;
+
+ int status = stat(file, &statbuf);
+ if (status != 0) {
+ WARNING("procevent plugin: stat (%s) failed: %s", file, STRERRNO);
+ continue;
+ }
+
+ if (!S_ISDIR(statbuf.st_mode))
+ continue;
+
+ len = snprintf(file, sizeof(file), PROCDIR "/%s/comm", dent->d_name);
+ if ((len < 0) || (len >= BUFSIZE))
+ continue;
+
+ int not_number = 0;
+
+ for (int i = 0; i < strlen(dent->d_name); i++) {
+ if (!isdigit(dent->d_name[i])) {
+ not_number = 1;
+ break;
+ }
+ }
+
+ if (not_number != 0)
+ continue;
+
+ // Check if we need to store this pid/name combo in our processlist_t linked
+ // list
+ int this_pid = atoi(dent->d_name);
+ pthread_mutex_lock(&procevent_data_lock);
+ processlist_t *pl = process_check(this_pid);
+ pthread_mutex_unlock(&procevent_data_lock);
+
+ if (pl != NULL)
+ DEBUG("procevent plugin: process map refreshed for PID %d and name %s",
+ this_pid, pl->process);
+ }
+
+ closedir(proc);
+
+ return 0;
+}
+
+static int nl_connect() {
+ struct sockaddr_nl sa_nl = {
+ .nl_family = AF_NETLINK,
+ .nl_groups = CN_IDX_PROC,
+ .nl_pid = getpid(),
+ };
+
+ nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
+ if (nl_sock == -1) {
+ ERROR("procevent plugin: socket open failed: %d", errno);
+ return -1;
+ }
+
+ int rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
+ if (rc == -1) {
+ ERROR("procevent plugin: socket bind failed: %d", errno);
+ close(nl_sock);
+ nl_sock = -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int set_proc_ev_listen(bool enable) {
+ struct __attribute__((aligned(NLMSG_ALIGNTO))) {
+ struct nlmsghdr nl_hdr;
+ struct __attribute__((__packed__)) {
+ struct cn_msg cn_msg;
+ enum proc_cn_mcast_op cn_mcast;
+ };
+ } nlcn_msg;
+
+ memset(&nlcn_msg, 0, sizeof(nlcn_msg));
+ nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
+ nlcn_msg.nl_hdr.nlmsg_pid = getpid();
+ nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;
+
+ nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
+ nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
+ nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
+
+ nlcn_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;
+
+ int rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
+ if (rc == -1) {
+ ERROR("procevent plugin: subscribing to netlink process events failed: %d",
+ errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+// Read from netlink socket and write to ring buffer
+static int read_event() {
+ int recv_flags = MSG_DONTWAIT;
+ struct __attribute__((aligned(NLMSG_ALIGNTO))) {
+ struct nlmsghdr nl_hdr;
+ struct __attribute__((__packed__)) {
+ struct cn_msg cn_msg;
+ struct proc_event proc_ev;
+ };
+ } nlcn_msg;
+
+ if (nl_sock == -1)
+ return 0;
+
+ while (42) {
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ if (procevent_netlink_thread_loop <= 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return 0;
+ }
+
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ int status = recv(nl_sock, &nlcn_msg, sizeof(nlcn_msg), recv_flags);
+
+ if (status == 0) {
+ return 0;
+ } else if (status < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ pthread_mutex_lock(&procevent_data_lock);
+
+ // There was nothing more to receive for now, so...
+ // If ring head does not equal ring tail, then there is data
+ // in the ring buffer for the dequeue thread to read, so
+ // signal it
+ if (ring.head != ring.tail)
+ pthread_cond_signal(&procevent_cond);
+
+ pthread_mutex_unlock(&procevent_data_lock);
+
+ // Since there was nothing to receive, set recv to block and
+ // try again
+ recv_flags = 0;
+ continue;
+ } else if (errno != EINTR) {
+ ERROR("procevent plugin: socket receive error: %d", errno);
+ return -1;
+ } else {
+ // Interrupt, so just continue and try again
+ continue;
+ }
+ }
+
+ // We successfully received a message, so don't block on the next
+ // read in case there are more (and if there aren't, it will be
+ // handled above in the EWOULDBLOCK error-checking)
+ recv_flags = MSG_DONTWAIT;
+
+ int proc_id = -1;
+ int proc_status = -1;
+
+ switch (nlcn_msg.proc_ev.what) {
+ case PROC_EVENT_EXEC:
+ proc_status = PROCEVENT_STARTED;
+ proc_id = nlcn_msg.proc_ev.event_data.exec.process_pid;
+ break;
+ case PROC_EVENT_EXIT:
+ proc_id = nlcn_msg.proc_ev.event_data.exit.process_pid;
+ proc_status = PROCEVENT_EXITED;
+ break;
+ default:
+ // Otherwise not of interest
+ break;
+ }
+
+ // If we're interested in this process status event, place the event
+ // in the ring buffer for consumption by the dequeue (dispatch) thread.
+
+ if (proc_status != -1) {
+ pthread_mutex_lock(&procevent_data_lock);
+
+ int next = ring.head + 1;
+ if (next >= ring.maxLen)
+ next = 0;
+
+ if (next == ring.tail) {
+ // Buffer is full, signal the dequeue thread to process the buffer
+ // and clean it out, and then sleep
+ WARNING("procevent plugin: ring buffer full");
+
+ pthread_cond_signal(&procevent_cond);
+ pthread_mutex_unlock(&procevent_data_lock);
+
+ usleep(1000);
+ continue;
+ } else {
+ DEBUG("procevent plugin: Process %d status is now %s at %llu", proc_id,
+ (proc_status == PROCEVENT_EXITED ? "EXITED" : "STARTED"),
+ (unsigned long long)cdtime());
+
+ ring.buffer[ring.head][RBUF_PROC_ID_INDEX] = proc_id;
+ ring.buffer[ring.head][RBUF_PROC_STATUS_INDEX] = proc_status;
+ ring.buffer[ring.head][RBUF_TIME_INDEX] = cdtime();
+
+ ring.head = next;
+ }
+
+ pthread_mutex_unlock(&procevent_data_lock);
+ }
+ }
+
+ return 0;
+}
+
+static void procevent_dispatch_notification(long pid, gauge_t value,
+ char *process, cdtime_t timestamp) {
+
+ notification_t n = {
+ .severity = (value == 1 ? NOTIF_OKAY : NOTIF_FAILURE),
+ .time = cdtime(),
+ .plugin = "procevent",
+ .type = "gauge",
+ .type_instance = "process_status",
+ };
+
+ sstrncpy(n.host, hostname_g, sizeof(n.host));
+ sstrncpy(n.plugin_instance, process, sizeof(n.plugin_instance));
+
+ char *buf = NULL;
+ gen_message_payload(value, pid, process, timestamp, &buf);
+
+ int status = plugin_notification_meta_add_string(&n, "ves", buf);
+
+ if (status < 0) {
+ sfree(buf);
+ ERROR("procevent plugin: unable to set notification VES metadata: %s",
+ STRERRNO);
+ return;
+ }
+
+ DEBUG("procevent plugin: notification VES metadata: %s",
+ n.meta->nm_value.nm_string);
+
+ DEBUG("procevent plugin: dispatching state %d for PID %ld (%s)", (int)value,
+ pid, process);
+
+ plugin_dispatch_notification(&n);
+ plugin_notification_meta_free(n.meta);
+
+ // strdup'd in gen_message_payload
+ if (buf != NULL)
+ sfree(buf);
+}
+
+// Read from ring buffer and dispatch to write plugins
+static void read_ring_buffer() {
+ pthread_mutex_lock(&procevent_data_lock);
+
+ // If there's currently nothing to read from the buffer,
+ // then wait
+ if (ring.head == ring.tail)
+ pthread_cond_wait(&procevent_cond, &procevent_data_lock);
+
+ while (ring.head != ring.tail) {
+ int next = ring.tail + 1;
+
+ if (next >= ring.maxLen)
+ next = 0;
+
+ if (ring.buffer[ring.tail][RBUF_PROC_STATUS_INDEX] == PROCEVENT_EXITED) {
+ processlist_t *pl = process_map_check(ring.buffer[ring.tail][0], NULL);
+
+ if (pl != NULL) {
+ // This process is of interest to us, so publish its EXITED status
+ procevent_dispatch_notification(
+ ring.buffer[ring.tail][RBUF_PROC_ID_INDEX],
+ ring.buffer[ring.tail][RBUF_PROC_STATUS_INDEX], pl->process,
+ ring.buffer[ring.tail][RBUF_TIME_INDEX]);
+ DEBUG(
+ "procevent plugin: PID %ld (%s) EXITED, removing PID from process "
+ "list",
+ pl->pid, pl->process);
+ pl->pid = -1;
+ pl->last_status = -1;
+ }
+ } else if (ring.buffer[ring.tail][RBUF_PROC_STATUS_INDEX] ==
+ PROCEVENT_STARTED) {
+ // a new process has started, so check if we should monitor it
+ processlist_t *pl = process_check(ring.buffer[ring.tail][0]);
+
+ // If we had already seen this process name and pid combo before,
+ // and the last message was a "process started" message, don't send
+ // the notfication again
+
+ if (pl != NULL && pl->last_status != PROCEVENT_STARTED) {
+ // This process is of interest to us, so publish its STARTED status
+ procevent_dispatch_notification(
+ ring.buffer[ring.tail][RBUF_PROC_ID_INDEX],
+ ring.buffer[ring.tail][RBUF_PROC_STATUS_INDEX], pl->process,
+ ring.buffer[ring.tail][RBUF_TIME_INDEX]);
+
+ pl->last_status = PROCEVENT_STARTED;
+
+ DEBUG("procevent plugin: PID %ld (%s) STARTED, adding PID to process "
+ "list",
+ pl->pid, pl->process);
+ }
+ }
+
+ ring.tail = next;
+ }
+
+ pthread_mutex_unlock(&procevent_data_lock);
+}
+
+// Entry point for thread responsible for listening
+// to netlink socket and writing data to ring buffer
+static void *procevent_netlink_thread(void *arg) /* {{{ */
+{
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ while (procevent_netlink_thread_loop > 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ int status = read_event();
+
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ if (status < 0) {
+ procevent_netlink_thread_error = 1;
+ break;
+ }
+ } /* while (procevent_netlink_thread_loop > 0) */
+
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ return (void *)0;
+} /* }}} void *procevent_netlink_thread */
+
+// Entry point for thread responsible for reading from
+// ring buffer and dispatching notifications
+static void *procevent_dequeue_thread(void *arg) /* {{{ */
+{
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ while (procevent_dequeue_thread_loop > 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ read_ring_buffer();
+
+ pthread_mutex_lock(&procevent_thread_lock);
+ } /* while (procevent_dequeue_thread_loop > 0) */
+
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ return (void *)0;
+} /* }}} void *procevent_dequeue_thread */
+
+static int start_netlink_thread(void) /* {{{ */
+{
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ if (procevent_netlink_thread_loop != 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return 0;
+ }
+
+ int status;
+
+ if (nl_sock == -1) {
+ status = nl_connect();
+
+ if (status != 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return status;
+ }
+
+ status = set_proc_ev_listen(true);
+ if (status == -1) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return status;
+ }
+ }
+
+ DEBUG("procevent plugin: socket created and bound");
+
+ procevent_netlink_thread_loop = 1;
+ procevent_netlink_thread_error = 0;
+
+ status = plugin_thread_create(&procevent_netlink_thread_id, /* attr = */ NULL,
+ procevent_netlink_thread,
+ /* arg = */ (void *)0, "procevent");
+ if (status != 0) {
+ procevent_netlink_thread_loop = 0;
+ ERROR("procevent plugin: Starting netlink thread failed.");
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ int status2 = close(nl_sock);
+
+ if (status2 != 0) {
+ ERROR("procevent plugin: failed to close socket %d: %d (%s)", nl_sock,
+ status2, STRERRNO);
+ }
+
+ nl_sock = -1;
+
+ return -1;
+ }
+
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ return status;
+} /* }}} int start_netlink_thread */
+
+static int start_dequeue_thread(void) /* {{{ */
+{
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ if (procevent_dequeue_thread_loop != 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return 0;
+ }
+
+ procevent_dequeue_thread_loop = 1;
+
+ int status = plugin_thread_create(&procevent_dequeue_thread_id,
+ /* attr = */ NULL, procevent_dequeue_thread,
+ /* arg = */ (void *)0, "procevent");
+ if (status != 0) {
+ procevent_dequeue_thread_loop = 0;
+ ERROR("procevent plugin: Starting dequeue thread failed.");
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ return status;
+} /* }}} int start_dequeue_thread */
+
+static int start_threads(void) /* {{{ */
+{
+ int status = start_netlink_thread();
+ int status2 = start_dequeue_thread();
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int start_threads */
+
+static int stop_netlink_thread(int shutdown) /* {{{ */
+{
+ int socket_status;
+
+ if (nl_sock != -1) {
+ socket_status = close(nl_sock);
+ if (socket_status != 0) {
+ ERROR("procevent plugin: failed to close socket %d: %d (%s)", nl_sock,
+ socket_status, strerror(errno));
+ }
+
+ nl_sock = -1;
+ } else
+ socket_status = 0;
+
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ if (procevent_netlink_thread_loop == 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return -1;
+ }
+
+ // Set thread termination status
+ procevent_netlink_thread_loop = 0;
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ // Let threads waiting on access to the data know to move
+ // on such that they'll see the thread's termination status
+ pthread_cond_broadcast(&procevent_cond);
+
+ int thread_status;
+
+ if (shutdown == 1) {
+ // Calling pthread_cancel here in
+ // the case of a shutdown just assures that the thread is
+ // gone and that the process has been fully terminated.
+
+ DEBUG("procevent plugin: Canceling netlink thread for process shutdown");
+
+ thread_status = pthread_cancel(procevent_netlink_thread_id);
+
+ if (thread_status != 0 && thread_status != ESRCH) {
+ ERROR("procevent plugin: Unable to cancel netlink thread: %d",
+ thread_status);
+ thread_status = -1;
+ } else
+ thread_status = 0;
+ } else {
+ thread_status =
+ pthread_join(procevent_netlink_thread_id, /* return = */ NULL);
+ if (thread_status != 0 && thread_status != ESRCH) {
+ ERROR("procevent plugin: Stopping netlink thread failed.");
+ thread_status = -1;
+ } else
+ thread_status = 0;
+ }
+
+ pthread_mutex_lock(&procevent_thread_lock);
+ memset(&procevent_netlink_thread_id, 0, sizeof(procevent_netlink_thread_id));
+ procevent_netlink_thread_error = 0;
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ DEBUG("procevent plugin: Finished requesting stop of netlink thread");
+
+ if (socket_status != 0)
+ return socket_status;
+ else
+ return thread_status;
+} /* }}} int stop_netlink_thread */
+
+static int stop_dequeue_thread() /* {{{ */
+{
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ if (procevent_dequeue_thread_loop == 0) {
+ pthread_mutex_unlock(&procevent_thread_lock);
+ return -1;
+ }
+
+ procevent_dequeue_thread_loop = 0;
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ pthread_cond_broadcast(&procevent_cond);
+
+ // Calling pthread_cancel here just assures that the thread is
+ // gone and that the process has been fully terminated.
+
+ DEBUG("procevent plugin: Canceling dequeue thread for process shutdown");
+
+ int status = pthread_cancel(procevent_dequeue_thread_id);
+
+ if (status != 0 && status != ESRCH) {
+ ERROR("procevent plugin: Unable to cancel dequeue thread: %d", status);
+ status = -1;
+ } else
+ status = 0;
+
+ pthread_mutex_lock(&procevent_thread_lock);
+ memset(&procevent_dequeue_thread_id, 0, sizeof(procevent_dequeue_thread_id));
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ DEBUG("procevent plugin: Finished requesting stop of dequeue thread");
+
+ return status;
+} /* }}} int stop_dequeue_thread */
+
+static int stop_threads() /* {{{ */
+{
+ int status = stop_netlink_thread(1);
+ int status2 = stop_dequeue_thread();
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int stop_threads */
+
+static int procevent_init(void) /* {{{ */
+{
+ ring.head = 0;
+ ring.tail = 0;
+ ring.maxLen = buffer_length;
+ ring.buffer = (cdtime_t **)calloc(buffer_length, sizeof(cdtime_t *));
+
+ for (int i = 0; i < buffer_length; i++) {
+ ring.buffer[i] = (cdtime_t *)calloc(PROCEVENT_FIELDS, sizeof(cdtime_t));
+ }
+
+ int status = process_map_refresh();
+
+ if (status == -1) {
+ ERROR("procevent plugin: Initial process mapping failed.");
+ return -1;
+ }
+
+ if (ignorelist == NULL) {
+ NOTICE("procevent plugin: No processes have been configured.");
+ return -1;
+ }
+
+ return start_threads();
+} /* }}} int procevent_init */
+
+static int procevent_config(const char *key, const char *value) /* {{{ */
+{
+ if (ignorelist == NULL)
+ ignorelist = ignorelist_create(/* invert = */ 1);
+
+ if (ignorelist == NULL) {
+ return -1;
+ }
+
+ if (strcasecmp(key, "BufferLength") == 0) {
+ buffer_length = atoi(value);
+ } else if (strcasecmp(key, "Process") == 0) {
+ ignorelist_add(ignorelist, value);
+ } else if (strcasecmp(key, "ProcessRegex") == 0) {
+#if HAVE_REGEX_H
+ int status = ignorelist_add(ignorelist, value);
+
+ if (status != 0) {
+ ERROR("procevent plugin: invalid regular expression: %s", value);
+ return 1;
+ }
+#else
+ WARNING("procevent plugin: The plugin has been compiled without support "
+ "for the \"ProcessRegex\" option.");
+#endif
+ } else {
+ return -1;
+ }
+
+ return 0;
+} /* }}} int procevent_config */
+
+static int procevent_read(void) /* {{{ */
+{
+ pthread_mutex_lock(&procevent_thread_lock);
+
+ if (procevent_netlink_thread_error != 0) {
+
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ ERROR("procevent plugin: The netlink thread had a problem. Restarting it.");
+
+ stop_netlink_thread(0);
+
+ start_netlink_thread();
+
+ return -1;
+ } /* if (procevent_netlink_thread_error != 0) */
+
+ pthread_mutex_unlock(&procevent_thread_lock);
+
+ return 0;
+} /* }}} int procevent_read */
+
+static int procevent_shutdown(void) /* {{{ */
+{
+ DEBUG("procevent plugin: Shutting down threads.");
+
+ int status = stop_threads();
+
+ for (int i = 0; i < buffer_length; i++) {
+ free(ring.buffer[i]);
+ }
+
+ free(ring.buffer);
+
+ processlist_t *pl = processlist_head;
+ while (pl != NULL) {
+ processlist_t *pl_next;
+
+ pl_next = pl->next;
+
+ sfree(pl->process);
+ sfree(pl);
+
+ pl = pl_next;
+ }
+
+ ignorelist_free(ignorelist);
+
+ return status;
+} /* }}} int procevent_shutdown */
+
+void module_register(void) {
+ plugin_register_config("procevent", procevent_config, config_keys,
+ config_keys_num);
+ plugin_register_init("procevent", procevent_init);
+ plugin_register_read("procevent", procevent_read);
+ plugin_register_shutdown("procevent", procevent_shutdown);
+} /* void module_register */
* Global variables
*/
static const char *config_keys[] = {
- "Value", "IgnoreSelected",
+ "Value",
+ "IgnoreSelected",
};
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
if (values_list != NULL) {
char match_name[2 * DATA_MAX_NAME_LEN];
- snprintf(match_name, sizeof(match_name), "%s:%s", key_buffer,
- key_fields[i]);
+ ssnprintf(match_name, sizeof(match_name), "%s:%s", key_buffer,
+ key_fields[i]);
if (ignorelist_match(values_list, match_name))
continue;
PyObject *mod = NULL;
if (name != NULL) {
- snprintf(buf, size, "python.%s", name);
+ ssnprintf(buf, size, "python.%s", name);
return;
}
module = cpy_unicode_or_bytes_to_string(&mod);
if (module != NULL) {
- snprintf(buf, size, "python.%s", module);
+ ssnprintf(buf, size, "python.%s", module);
Py_XDECREF(mod);
PyErr_Clear();
return;
}
Py_XDECREF(mod);
- snprintf(buf, size, "python.%p", callback);
+ ssnprintf(buf, size, "python.%p", callback);
PyErr_Clear();
}
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);
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);
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));
redis_have_instances = true;
char cb_name[sizeof("redis/") + DATA_MAX_NAME_LEN];
- snprintf(cb_name, sizeof(cb_name), "redis/%s", rn->name);
+ ssnprintf(cb_name, sizeof(cb_name), "redis/%s", rn->name);
return plugin_register_complex_read(
/* group = */ "redis",
/* callback = */ redis_read,
/* interval = */ 0,
&(user_data_t){
- .data = rn, .free_func = redis_node_free,
+ .data = rn,
+ .free_func = redis_node_free,
});
} /* }}} */
char *str;
int i;
- snprintf(field_name, sizeof(field_name), "db%d:keys=", db);
+ ssnprintf(field_name, sizeof(field_name), "db%d:keys=", db);
str = strstr(info_line, field_name);
if (!str)
return -1;
}
- snprintf(db_id, sizeof(db_id), "%d", db);
+ ssnprintf(db_id, sizeof(db_id), "%d", db);
redis_submit(node, "records", db_id, val);
}
return 0;
const char *type_instance, derive_t rx, derive_t tx) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
vl.values = values;
name = "default";
/*** RX ***/
- snprintf(type_instance, sizeof(type_instance), "%s-%s-rx", r->interface,
- name);
+ ssnprintf(type_instance, sizeof(type_instance), "%s-%s-rx", r->interface,
+ name);
cr_submit_gauge(rd, "bitrate", type_instance,
(gauge_t)(1000000.0 * r->rx_rate));
cr_submit_gauge(rd, "signal_power", type_instance,
cr_submit_gauge(rd, "signal_quality", type_instance, (gauge_t)r->rx_ccq);
/*** TX ***/
- snprintf(type_instance, sizeof(type_instance), "%s-%s-tx", r->interface,
- name);
+ ssnprintf(type_instance, sizeof(type_instance), "%s-%s-tx", r->interface,
+ name);
cr_submit_gauge(rd, "bitrate", type_instance,
(gauge_t)(1000000.0 * r->tx_rate));
cr_submit_gauge(rd, "signal_power", type_instance,
cr_submit_gauge(rd, "signal_quality", type_instance, (gauge_t)r->tx_ccq);
/*** RX / TX ***/
- snprintf(type_instance, sizeof(type_instance), "%s-%s", r->interface, name);
+ ssnprintf(type_instance, sizeof(type_instance), "%s-%s", r->interface, name);
cr_submit_io(rd, "if_octets", type_instance, (derive_t)r->rx_bytes,
(derive_t)r->tx_bytes);
cr_submit_gauge(rd, "snr", type_instance, (gauge_t)r->signal_to_noise);
return status;
}
- snprintf(read_name, sizeof(read_name), "routeros/%s", router_data->node);
+ ssnprintf(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,
+ .data = router_data,
+ .free_func = (void *)cr_free_data,
});
} /* }}} int cr_config_router */
static char *daemon_address;
static bool config_create_files = true;
static bool config_collect_stats = true;
-static rrdcreate_config_t rrdcreate_config = {
- /* stepsize = */ 0,
- /* heartbeat = */ 0,
- /* rrarows = */ 1200,
- /* xff = */ 0.1,
-
- /* timespans = */ NULL,
- /* timespans_num = */ 0,
-
- /* consolidation_functions = */ NULL,
- /* consolidation_functions_num = */ 0,
-
- /* async = */ 0};
+static rrdcreate_config_t rrdcreate_config = {.stepsize = 0,
+ .heartbeat = 0,
+ .rrarows = 1200,
+ .xff = 0.1,
+ .timespans = NULL,
+ .timespans_num = 0,
+ .consolidation_functions = NULL,
+ .consolidation_functions_num = 0,
+ .async = 0};
/*
* Prototypes.
*/
static int rc_write(const data_set_t *ds, const value_list_t *vl,
- user_data_t __attribute__((unused)) * user_data);
+ __attribute__((unused)) user_data_t *ud);
static int rc_flush(__attribute__((unused)) cdtime_t timeout,
const char *identifier,
__attribute__((unused)) user_data_t *ud);
static int value_list_to_string(char *buffer, int buffer_len,
const data_set_t *ds, const value_list_t *vl) {
- int offset;
- int status;
- time_t t;
-
- assert(0 == strcmp(ds->type, vl->type));
+ assert(strcmp(ds->type, vl->type) == 0);
memset(buffer, '\0', buffer_len);
- t = CDTIME_T_TO_TIME_T(vl->time);
- status = snprintf(buffer, buffer_len, "%lu", (unsigned long)t);
+ int status =
+ ssnprintf(buffer, buffer_len, "%.6f", CDTIME_T_TO_DOUBLE(vl->time));
if ((status < 1) || (status >= buffer_len))
return -1;
- offset = status;
+ int offset = status;
for (size_t i = 0; i < ds->ds_num; i++) {
if ((ds->ds[i].type != DS_TYPE_COUNTER) &&
return -1;
if (ds->ds[i].type == DS_TYPE_COUNTER) {
- status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
- (uint64_t)vl->values[i].counter);
+ status = ssnprintf(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 = ssnprintf(buffer + offset, buffer_len - offset, ":%f",
+ vl->values[i].gauge);
} else if (ds->ds[i].type == DS_TYPE_DERIVE) {
- status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIi64,
- vl->values[i].derive);
+ status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIi64,
+ vl->values[i].derive);
} else /* if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */ {
- status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
- vl->values[i].absolute);
+ status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
+ vl->values[i].absolute);
}
if ((status < 1) || (status >= (buffer_len - offset)))
static int value_list_to_filename(char *buffer, size_t buffer_size,
value_list_t const *vl) {
char const suffix[] = ".rrd";
- int status;
- size_t len;
if (datadir != NULL) {
size_t datadir_len = strlen(datadir) + 1;
sstrncpy(buffer, datadir, buffer_size);
buffer[datadir_len - 1] = '/';
- buffer[datadir_len] = 0;
+ buffer[datadir_len] = '\0';
buffer += datadir_len;
buffer_size -= datadir_len;
}
- status = FORMAT_VL(buffer, buffer_size, vl);
+ int status = FORMAT_VL(buffer, buffer_size, vl);
if (status != 0)
return status;
- len = strlen(buffer);
+ size_t len = strlen(buffer);
assert(len < buffer_size);
buffer += len;
buffer_size -= len;
} /* int value_list_to_filename */
static int rc_config_get_int_positive(oconfig_item_t const *ci, int *ret) {
- int status;
int tmp = 0;
- status = cf_util_get_int(ci, &tmp);
+ int status = cf_util_get_int(ci, &tmp);
if (status != 0)
return status;
if (tmp < 0)
} /* int rc_config_get_int_positive */
static int rc_config_get_xff(oconfig_item_t const *ci, double *ret) {
- double value;
-
if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_NUMBER)) {
ERROR("rrdcached plugin: The \"%s\" needs exactly one numeric argument "
"in the range [0.0, 1.0)",
return EINVAL;
}
- value = ci->values[0].value.number;
+ double value = ci->values[0].value.number;
if ((value >= 0.0) && (value < 1.0)) {
*ret = value;
return 0;
} /* int rc_config_get_xff */
static int rc_config_add_timespan(int timespan) {
- int *tmp;
-
if (timespan <= 0)
return EINVAL;
- tmp = realloc(rrdcreate_config.timespans,
- sizeof(*rrdcreate_config.timespans) *
- (rrdcreate_config.timespans_num + 1));
+ int *tmp = realloc(rrdcreate_config.timespans,
+ sizeof(*rrdcreate_config.timespans) *
+ (rrdcreate_config.timespans_num + 1));
if (tmp == NULL)
return ENOMEM;
rrdcreate_config.timespans = tmp;
} /* int rc_config */
static int try_reconnect(void) {
- int status;
-
rrdc_disconnect();
rrd_clear_error();
- status = rrdc_connect(daemon_address);
+ int status = rrdc_connect(daemon_address);
if (status != 0) {
ERROR("rrdcached plugin: Failed to reconnect to RRDCacheD "
"at %s: %s (status=%d)",
} /* int try_reconnect */
static int rc_read(void) {
- int status;
- rrdc_stats_t *head;
- bool retried = false;
value_list_t vl = VALUE_LIST_INIT;
vl.values = &(value_t){.gauge = NAN};
sstrncpy(vl.plugin, "rrdcached", sizeof(vl.plugin));
rrd_clear_error();
- status = rrdc_connect(daemon_address);
+ int status = rrdc_connect(daemon_address);
if (status != 0) {
ERROR("rrdcached plugin: Failed to connect to RRDCacheD "
"at %s: %s (status=%d)",
return -1;
}
+ rrdc_stats_t *head;
+ bool retried = false;
+
while (42) {
/* The RRD client lib does not provide any means for checking a
* connection, hence we'll have to retry upon failed operations. */
user_data_t __attribute__((unused)) * user_data) {
char filename[PATH_MAX];
char values[512];
- char *values_array[2];
int status;
bool retried = false;
return -1;
}
- values_array[0] = values;
- values_array[1] = NULL;
-
if (config_create_files) {
struct stat statbuf;
return -1;
}
+ char *values_array[2] = {
+ [0] = values,
+ [1] = NULL,
+ };
+
while (42) {
/* The RRD client lib does not provide any means for checking a
* connection, hence we'll have to retry upon failed operations. */
static int rc_flush(__attribute__((unused)) cdtime_t timeout, /* {{{ */
const char *identifier,
__attribute__((unused)) user_data_t *ud) {
- char filename[PATH_MAX + 1];
- int status;
- bool retried = false;
-
if (identifier == NULL)
return EINVAL;
+ char filename[PATH_MAX + 1];
+
if (datadir != NULL)
- snprintf(filename, sizeof(filename), "%s/%s.rrd", datadir, identifier);
+ ssnprintf(filename, sizeof(filename), "%s/%s.rrd", datadir, identifier);
else
- snprintf(filename, sizeof(filename), "%s.rrd", identifier);
+ ssnprintf(filename, sizeof(filename), "%s.rrd", identifier);
rrd_clear_error();
- status = rrdc_connect(daemon_address);
+ int status = rrdc_connect(daemon_address);
if (status != 0) {
ERROR("rrdcached plugin: Failed to connect to RRDCacheD "
"at %s: %s (status=%d)",
return -1;
}
+ bool retried = false;
+
while (42) {
/* The RRD client lib does not provide any means for checking a
* connection, hence we'll have to retry upon failed operations. */
return status;
} /* int srrd_update */
-/* #endif HAVE_THREADSAFE_LIBRRD */
+ /* #endif HAVE_THREADSAFE_LIBRRD */
#else /* !HAVE_THREADSAFE_LIBRRD */
static int srrd_update(char *filename, char *template, int argc,
memset(buffer, '\0', buffer_len);
tt = CDTIME_T_TO_TIME_T(vl->time);
- status = snprintf(buffer, buffer_len, "%u", (unsigned int)tt);
+ status = ssnprintf(buffer, buffer_len, "%u", (unsigned int)tt);
if ((status < 1) || (status >= buffer_len))
return -1;
offset = status;
return -1;
if (ds->ds[i].type == DS_TYPE_COUNTER)
- status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
- (uint64_t)vl->values[i].counter);
+ status = ssnprintf(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);
+ status = ssnprintf(buffer + offset, buffer_len - offset, ":" GAUGE_FORMAT,
+ vl->values[i].gauge);
else if (ds->ds[i].type == DS_TYPE_DERIVE)
- status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIi64,
- vl->values[i].derive);
+ status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIi64,
+ vl->values[i].derive);
else /*if (ds->ds[i].type == DS_TYPE_ABSOLUTE) */
- status = snprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
- vl->values[i].absolute);
+ status = ssnprintf(buffer + offset, buffer_len - offset, ":%" PRIu64,
+ vl->values[i].absolute);
if ((status < 1) || (status >= (buffer_len - offset)))
return -1;
tt = CDTIME_T_TO_TIME_T(vl->time);
switch (ds->ds[0].type) {
case DS_TYPE_DERIVE:
- status = snprintf(buffer, buffer_len, "%u:%" PRIi64, (unsigned)tt,
- vl->values[0].derive);
+ status = ssnprintf(buffer, buffer_len, "%u:%" PRIi64, (unsigned)tt,
+ vl->values[0].derive);
break;
case DS_TYPE_GAUGE:
- status = snprintf(buffer, buffer_len, "%u:" GAUGE_FORMAT, (unsigned)tt,
- vl->values[0].gauge);
+ status = ssnprintf(buffer, buffer_len, "%u:" GAUGE_FORMAT, (unsigned)tt,
+ vl->values[0].gauge);
break;
case DS_TYPE_COUNTER:
- status = snprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt,
- (uint64_t)vl->values[0].counter);
+ status = ssnprintf(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,
- vl->values[0].absolute);
+ status = ssnprintf(buffer, buffer_len, "%u:%" PRIu64, (unsigned)tt,
+ vl->values[0].absolute);
break;
default:
return EINVAL;
now = cdtime();
if (datadir == NULL)
- snprintf(key, sizeof(key), "%s.rrd", identifier);
+ ssnprintf(key, sizeof(key), "%s.rrd", identifier);
else
- snprintf(key, sizeof(key), "%s/%s.rrd", datadir, identifier);
+ ssnprintf(key, sizeof(key), "%s/%s.rrd", datadir, identifier);
key[sizeof(key) - 1] = '\0';
status = c_avl_get(cache, key, (void *)&rc);
last_feature = fl;
} /* while sensors_get_all_features */
} /* while sensors_get_detected_chips */
-/* #endif SENSORS_API_VERSION < 0x400 */
+ /* #endif SENSORS_API_VERSION < 0x400 */
#elif (SENSORS_API_VERSION >= 0x400)
chip_num = 0;
sensors_submit(plugin_instance, sensor_type_name_map[fl->type],
type_instance, value);
} /* for fl = first_feature .. NULL */
-/* #endif SENSORS_API_VERSION < 0x400 */
+ /* #endif SENSORS_API_VERSION < 0x400 */
#elif (SENSORS_API_VERSION >= 0x400)
for (featurelist_t *fl = first_feature; fl != NULL; fl = fl->next) {
static void serial_submit(const char *type_instance, derive_t rx, derive_t tx) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
vl.values = values;
}
cfdev->sdi = devlist->data;
g_slist_free(devlist);
- snprintf(hwident, sizeof(hwident), "%s %s %s",
- cfdev->sdi->vendor ? cfdev->sdi->vendor : "",
- cfdev->sdi->model ? cfdev->sdi->model : "",
- cfdev->sdi->version ? cfdev->sdi->version : "");
+ ssnprintf(hwident, sizeof(hwident), "%s %s %s",
+ cfdev->sdi->vendor ? cfdev->sdi->vendor : "",
+ cfdev->sdi->model ? cfdev->sdi->model : "",
+ cfdev->sdi->version ? cfdev->sdi->version : "");
INFO("sigrok plugin: Device \"%s\" is a %s", cfdev->name, hwident);
if (sr_dev_open(cfdev->sdi) != SR_OK)
sstrncpy(notif.host, hostname_g, sizeof(notif.host));
sstrncpy(notif.plugin_instance, name, sizeof(notif.plugin_instance));
sstrncpy(notif.type_instance, a->name, sizeof(notif.type_instance));
- snprintf(notif.message, sizeof(notif.message),
- "attribute %s is below allowed threshold (%d < %d)", a->name,
- a->current_value, a->threshold);
+ ssnprintf(notif.message, sizeof(notif.message),
+ "attribute %s is below allowed threshold (%d < %d)", a->name,
+ a->current_value, a->threshold);
plugin_dispatch_notification(¬if);
}
}
c_complain_t complaint;
data_definition_t **data_list;
int data_list_len;
+ int bulk_size;
};
typedef struct host_definition_s host_definition_t;
char *oid_str_ptr[MAX_OID_LEN];
for (size_t i = 0; i < o->oid_len; i++) {
- snprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
+ ssnprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
oid_str_ptr[i] = oid_str[i];
}
/* These mean that we have not set a timeout or retry value */
hd->timeout = 0;
hd->retries = -1;
+ hd->bulk_size = 0;
for (int i = 0; i < ci->children_num; i++) {
oconfig_item_t *option = ci->children + i;
status = csnmp_config_add_host_security_level(hd, option);
else if (strcasecmp("Context", option->key) == 0)
status = cf_util_get_string(option, &hd->context);
+ else if (strcasecmp("BulkSize", option->key) == 0)
+ status = cf_util_get_int(option, &hd->bulk_size);
else {
WARNING(
"snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.",
status = -1;
break;
}
+ if (hd->bulk_size > 0 && hd->version < 2) {
+ WARNING("snmp plugin: Bulk transfers is only available for SNMP v2 and "
+ "later, host '%s' is configured as version '%d'",
+ hd->name, hd->version);
+ }
if (hd->version == 3) {
if (hd->username == NULL) {
WARNING("snmp plugin: `Username' not given for host `%s'", hd->name);
"= %i }",
hd->name, hd->address, hd->community, hd->version);
- snprintf(cb_name, sizeof(cb_name), "snmp-%s", hd->name);
+ ssnprintf(cb_name, sizeof(cb_name), "snmp-%s", hd->name);
status = plugin_register_complex_read(
/* group = */ NULL, cb_name, csnmp_read_host, interval,
&(user_data_t){
- .data = hd, .free_func = csnmp_host_definition_destroy,
+ .data = hd,
+ .free_func = csnmp_host_definition_destroy,
});
if (status != 0) {
ERROR("snmp plugin: Registering complex read function failed.");
for (size_t i = 0; i < vb->val_len; i++) {
int status;
- status = snprintf(buffer_ptr, buffer_free, (i == 0) ? "%02x" : ":%02x",
- (unsigned int)vb->val.bitstring[i]);
+ status = ssnprintf(buffer_ptr, buffer_free, (i == 0) ? "%02x" : ":%02x",
+ (unsigned int)vb->val.bitstring[i]);
assert(status >= 0);
if (((size_t)status) >= buffer_free) /* truncated */
else if (vb->type == ASN_BIT_STR)
src = (char *)vb->val.bitstring;
else if (vb->type == ASN_IPADDRESS) {
- return snprintf(dst, dst_size,
- "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "",
- (uint8_t)vb->val.string[0], (uint8_t)vb->val.string[1],
- (uint8_t)vb->val.string[2], (uint8_t)vb->val.string[3]);
+ return ssnprintf(dst, dst_size,
+ "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "",
+ (uint8_t)vb->val.string[0], (uint8_t)vb->val.string[1],
+ (uint8_t)vb->val.string[2], (uint8_t)vb->val.string[3]);
} else {
dst[0] = 0;
return EINVAL;
value_t val = csnmp_value_list_to_value(
vb, DS_TYPE_COUNTER,
/* scale = */ 1.0, /* shift = */ 0.0, hd->name, dd->name);
- snprintf(il->value, sizeof(il->value), "%" PRIu64, (uint64_t)val.counter);
+ ssnprintf(il->value, sizeof(il->value), "%" PRIu64, (uint64_t)val.counter);
}
return il;
if (data->host.prefix == NULL)
sstrncpy(vl.host, temp, sizeof(vl.host));
else
- snprintf(vl.host, sizeof(vl.host), "%s%s", data->host.prefix, temp);
+ ssnprintf(vl.host, sizeof(vl.host), "%s%s", data->host.prefix, temp);
} else {
sstrncpy(vl.host, host->name, sizeof(vl.host));
}
if (data->type_instance.prefix == NULL)
sstrncpy(vl.type_instance, temp, sizeof(vl.type_instance));
else
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
- data->type_instance.prefix, temp);
+ ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s%s",
+ data->type_instance.prefix, temp);
} else if (data->type_instance.value) {
sstrncpy(vl.type_instance, data->type_instance.value,
sizeof(vl.type_instance));
if (data->plugin_instance.prefix == NULL)
sstrncpy(vl.plugin_instance, temp, sizeof(vl.plugin_instance));
else
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s%s",
- data->plugin_instance.prefix, temp);
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s%s",
+ data->plugin_instance.prefix, temp);
} else if (data->plugin_instance.value) {
sstrncpy(vl.plugin_instance, data->plugin_instance.value,
sizeof(vl.plugin_instance));
status = 0;
while (status == 0) {
- req = snmp_pdu_create(SNMP_MSG_GETNEXT);
+ /* If SNMP v2 and later and bulk transfers enabled, use GETBULK PDU */
+ if (host->version > 1 && host->bulk_size > 0) {
+ req = snmp_pdu_create(SNMP_MSG_GETBULK);
+ req->non_repeaters = 0;
+ req->max_repetitions = host->bulk_size;
+ } else {
+ req = snmp_pdu_create(SNMP_MSG_GETNEXT);
+ }
if (req == NULL) {
ERROR("snmp plugin: snmp_pdu_create failed.");
status = -1;
break;
}
+ if (req->command == SNMP_MSG_GETBULK) {
+ /* In bulk mode the host will send 'max_repetitions' values per
+ requested variable, so we need to split it per number of variable
+ to stay 'in budget' */
+ req->max_repetitions = floor(host->bulk_size / oid_list_todo_num);
+ }
+
res = NULL;
status = snmp_sess_synch_response(host->sess_handle, req, &res);
continue;
}
- for (vb = res->variables, i = 0; (vb != NULL);
- vb = vb->next_variable, i++) {
+ size_t j;
+ for (vb = res->variables, j = 0; (vb != NULL);
+ vb = vb->next_variable, j++) {
+ i = j;
+ /* If bulk request is active convert value index of the extra value */
+ if (host->version > 1 && host->bulk_size > 0) {
+ i %= oid_list_todo_num;
+ }
/* Calculate value index from todo list */
while ((i < oid_list_len) && !oid_list_todo[i]) {
i++;
+ j++;
}
if (i >= oid_list_len) {
break;
char *oid_str_ptr[MAX_OID_LEN];
for (size_t i = 0; i < o->oid_len; i++) {
- snprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
+ ssnprintf(oid_str[i], sizeof(oid_str[i]), "%lu", (unsigned long)o->oid[i]);
oid_str_ptr[i] = oid_str[i];
}
if (index == NULL)
snmp_agent_oid_to_string(index_str, sizeof(index_str), index_oid);
else
- snprintf(index_str, sizeof(index_str), "%d", *index);
+ ssnprintf(index_str, sizeof(index_str), "%d", *index);
notification_t n = {
.severity = NOTIF_WARNING, .time = cdtime(), .plugin = PLUGIN_NAME};
sstrncpy(n.host, hostname_g, sizeof(n.host));
- snprintf(n.message, sizeof(n.message),
- "Removed data row from table %s with index %s", td->name, index_str);
+ ssnprintf(n.message, sizeof(n.message),
+ "Removed data row from table %s with index %s", td->name,
+ index_str);
DEBUG(PLUGIN_NAME ": %s", n.message);
plugin_dispatch_notification(&n);
strncat(out, tok->str, DATA_MAX_NAME_LEN - strlen(out) - 1);
if (tok->key != NULL) {
if (tok->key->type == ASN_INTEGER) {
- snprintf(str, sizeof(str), "%ld", *tok->key->val.integer);
+ ssnprintf(str, sizeof(str), "%ld", *tok->key->val.integer);
strncat(out, str, DATA_MAX_NAME_LEN - strlen(out) - 1);
} else /* OCTET_STR */
strncat(out, (char *)tok->key->val.string,
}
if (td->index_keys[i].type == ASN_INTEGER) {
- snprintf(str, sizeof(str), "%ld", *key->val.integer);
+ ssnprintf(str, sizeof(str), "%ld", *key->val.integer);
fields[source] = str;
} else /* OCTET_STR */
fields[source] = (char *)key->val.string;
case ASN_OCTET_STR:
if (type == DS_TYPE_GAUGE) {
char buf[DATA_MAX_NAME_LEN];
- snprintf(buf, sizeof(buf), "%.2f", val->gauge);
+ ssnprintf(buf, sizeof(buf), "%.2f", val->gauge);
if (*data_len < strlen(buf))
return -EINVAL;
*data_len = strlen(buf);
if (index == NULL)
snmp_agent_oid_to_string(index_str, sizeof(index_str), index_oid);
else
- snprintf(index_str, sizeof(index_str), "%d", *index);
+ ssnprintf(index_str, sizeof(index_str), "%d", *index);
notification_t n = {
.severity = NOTIF_OKAY, .time = cdtime(), .plugin = PLUGIN_NAME};
sstrncpy(n.host, hostname_g, sizeof(n.host));
- snprintf(n.message, sizeof(n.message),
- "Data added to table %s with index %s", td->name, index_str);
+ ssnprintf(n.message, sizeof(n.message),
+ "Data added to table %s with index %s", td->name, index_str);
DEBUG(PLUGIN_NAME ": %s", n.message);
plugin_dispatch_notification(&n);
return ERANGE;
}
- tmp =
- realloc(conf_timer_percentile,
- sizeof(*conf_timer_percentile) * (conf_timer_percentile_num + 1));
+ tmp = realloc(conf_timer_percentile, sizeof(*conf_timer_percentile) *
+ (conf_timer_percentile_num + 1));
if (tmp == NULL) {
ERROR("statsd plugin: realloc failed.");
return ENOMEM;
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
-#if HAVE_SYS_SYSCTL_H
+#if (defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)) || \
+ defined(__OpenBSD__)
+/* implies BSD variant */
#include <sys/sysctl.h>
#endif
#if HAVE_SYS_DKSTAT_H
{
#if KERNEL_LINUX
pagesize = (derive_t)sysconf(_SC_PAGESIZE);
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
/* getpagesize(3C) tells me this does not fail.. */
pagesize = (derive_t)getpagesize();
-/* #endif HAVE_SWAPCTL */
+ /* #endif HAVE_SWAPCTL */
#elif defined(VM_SWAPUSAGE)
/* No init stuff */
ERROR("swap plugin: kvm_openfiles failed, %s", errbuf);
return -1;
}
-/* #endif HAVE_LIBKVM_GETSWAPINFO */
+ /* #endif HAVE_LIBKVM_GETSWAPINFO */
#elif HAVE_LIBSTATGRAB
/* No init stuff */
--- /dev/null
+/**
+ * collectd - src/sysevent.c
+ *
+ * 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:
+ * Red Hat NFVPE
+ * Andrew Bays <abays at redhat.com>
+ **/
+
+#include "collectd.h"
+
+#include "plugin.h"
+#include "utils/common/common.h"
+#include "utils/ignorelist/ignorelist.h"
+#include "utils_complain.h"
+
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <yajl/yajl_common.h>
+#include <yajl/yajl_gen.h>
+
+#if HAVE_YAJL_YAJL_VERSION_H
+#include <yajl/yajl_version.h>
+#endif
+#if defined(YAJL_MAJOR) && (YAJL_MAJOR > 1)
+#include <yajl/yajl_tree.h>
+#define HAVE_YAJL_V2 1
+#endif
+
+#define SYSEVENT_DOMAIN_FIELD "domain"
+#define SYSEVENT_DOMAIN_VALUE "syslog"
+#define SYSEVENT_EVENT_ID_FIELD "eventId"
+#define SYSEVENT_EVENT_NAME_FIELD "eventName"
+#define SYSEVENT_EVENT_NAME_VALUE "syslog message"
+#define SYSEVENT_LAST_EPOCH_MICROSEC_FIELD "lastEpochMicrosec"
+#define SYSEVENT_PRIORITY_FIELD "priority"
+#define SYSEVENT_PRIORITY_VALUE_HIGH "high"
+#define SYSEVENT_PRIORITY_VALUE_LOW "low"
+#define SYSEVENT_PRIORITY_VALUE_MEDIUM "medium"
+#define SYSEVENT_PRIORITY_VALUE_NORMAL "normal"
+#define SYSEVENT_PRIORITY_VALUE_UNKNOWN "unknown"
+#define SYSEVENT_REPORTING_ENTITY_NAME_FIELD "reportingEntityName"
+#define SYSEVENT_REPORTING_ENTITY_NAME_VALUE "collectd sysevent plugin"
+#define SYSEVENT_SEQUENCE_FIELD "sequence"
+#define SYSEVENT_SEQUENCE_VALUE "0"
+#define SYSEVENT_SOURCE_NAME_FIELD "sourceName"
+#define SYSEVENT_SOURCE_NAME_VALUE "syslog"
+#define SYSEVENT_START_EPOCH_MICROSEC_FIELD "startEpochMicrosec"
+#define SYSEVENT_VERSION_FIELD "version"
+#define SYSEVENT_VERSION_VALUE "1.0"
+
+#define SYSEVENT_EVENT_SOURCE_HOST_FIELD "eventSourceHost"
+#define SYSEVENT_EVENT_SOURCE_TYPE_FIELD "eventSourceType"
+#define SYSEVENT_EVENT_SOURCE_TYPE_VALUE "host"
+#define SYSEVENT_SYSLOG_FIELDS_FIELD "syslogFields"
+#define SYSEVENT_SYSLOG_FIELDS_VERSION_FIELD "syslogFieldsVersion"
+#define SYSEVENT_SYSLOG_FIELDS_VERSION_VALUE "1.0"
+#define SYSEVENT_SYSLOG_MSG_FIELD "syslogMsg"
+#define SYSEVENT_SYSLOG_PROC_FIELD "syslogProc"
+#define SYSEVENT_SYSLOG_SEV_FIELD "syslogSev"
+#define SYSEVENT_SYSLOG_TAG_FIELD "syslogTag"
+#define SYSEVENT_SYSLOG_TAG_VALUE "NILVALUE"
+
+/*
+ * Private data types
+ */
+
+typedef struct {
+ int head;
+ int tail;
+ int maxLen;
+ char **buffer;
+ cdtime_t *timestamp;
+} circbuf_t;
+
+/*
+ * Private variables
+ */
+
+static ignorelist_t *ignorelist = NULL;
+
+static int sysevent_socket_thread_loop = 0;
+static int sysevent_socket_thread_error = 0;
+static pthread_t sysevent_socket_thread_id;
+static int sysevent_dequeue_thread_loop = 0;
+static pthread_t sysevent_dequeue_thread_id;
+static pthread_mutex_t sysevent_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t sysevent_data_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t sysevent_cond = PTHREAD_COND_INITIALIZER;
+static int sock = -1;
+static int event_id = 0;
+static circbuf_t ring;
+
+static char *listen_ip;
+static char *listen_port;
+static int listen_buffer_size = 4096;
+static int buffer_length = 10;
+
+static int monitor_all_messages = 1;
+
+#if HAVE_YAJL_V2
+static const char *rsyslog_keys[3] = {"@timestamp", "@source_host", "@message"};
+static const char *rsyslog_field_keys[5] = {
+ "facility", "severity", "severity-num", "program", "processid"};
+#endif
+
+/*
+ * Private functions
+ */
+
+static int gen_message_payload(const char *msg, char *sev, int sev_num,
+ char *process, char *host, cdtime_t timestamp,
+ char **buf) {
+ const unsigned char *buf2;
+ yajl_gen g;
+ char json_str[DATA_MAX_NAME_LEN];
+
+#if !defined(HAVE_YAJL_V2)
+ yajl_gen_config conf = {0};
+#endif
+
+#if HAVE_YAJL_V2
+ size_t len;
+ g = yajl_gen_alloc(NULL);
+ yajl_gen_config(g, yajl_gen_beautify, 0);
+#else
+ unsigned int len;
+ g = yajl_gen_alloc(&conf, NULL);
+#endif
+
+ yajl_gen_clear(g);
+
+ // *** BEGIN common event header ***
+
+ if (yajl_gen_map_open(g) != yajl_gen_status_ok)
+ goto err;
+
+ // domain
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_DOMAIN_FIELD,
+ strlen(SYSEVENT_DOMAIN_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_DOMAIN_VALUE,
+ strlen(SYSEVENT_DOMAIN_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // eventId
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_EVENT_ID_FIELD,
+ strlen(SYSEVENT_EVENT_ID_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ event_id = event_id + 1;
+ snprintf(json_str, sizeof(json_str), "%d", event_id);
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // eventName
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_EVENT_NAME_FIELD,
+ strlen(SYSEVENT_EVENT_NAME_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ snprintf(json_str, sizeof(json_str), "host %s rsyslog message", host);
+
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
+ yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // lastEpochMicrosec
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_LAST_EPOCH_MICROSEC_FIELD,
+ strlen(SYSEVENT_LAST_EPOCH_MICROSEC_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ snprintf(json_str, sizeof(json_str), "%" PRIu64, CDTIME_T_TO_US(cdtime()));
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // priority
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_PRIORITY_FIELD,
+ strlen(SYSEVENT_PRIORITY_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ switch (sev_num) {
+ case 4:
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_PRIORITY_VALUE_MEDIUM,
+ strlen(SYSEVENT_PRIORITY_VALUE_MEDIUM)) !=
+ yajl_gen_status_ok)
+ goto err;
+ break;
+ case 5:
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_PRIORITY_VALUE_NORMAL,
+ strlen(SYSEVENT_PRIORITY_VALUE_NORMAL)) !=
+ yajl_gen_status_ok)
+ goto err;
+ break;
+ case 6:
+ case 7:
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_PRIORITY_VALUE_LOW,
+ strlen(SYSEVENT_PRIORITY_VALUE_LOW)) !=
+ yajl_gen_status_ok)
+ goto err;
+ break;
+ default:
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_PRIORITY_VALUE_UNKNOWN,
+ strlen(SYSEVENT_PRIORITY_VALUE_UNKNOWN)) !=
+ yajl_gen_status_ok)
+ goto err;
+ break;
+ }
+
+ // reportingEntityName
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_REPORTING_ENTITY_NAME_FIELD,
+ strlen(SYSEVENT_REPORTING_ENTITY_NAME_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_REPORTING_ENTITY_NAME_VALUE,
+ strlen(SYSEVENT_REPORTING_ENTITY_NAME_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // sequence
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SEQUENCE_FIELD,
+ strlen(SYSEVENT_SEQUENCE_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, SYSEVENT_SEQUENCE_VALUE,
+ strlen(SYSEVENT_SEQUENCE_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // sourceName
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SOURCE_NAME_FIELD,
+ strlen(SYSEVENT_SOURCE_NAME_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SOURCE_NAME_VALUE,
+ strlen(SYSEVENT_SOURCE_NAME_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // startEpochMicrosec
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_START_EPOCH_MICROSEC_FIELD,
+ strlen(SYSEVENT_START_EPOCH_MICROSEC_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ snprintf(json_str, sizeof(json_str), "%" PRIu64, CDTIME_T_TO_US(timestamp));
+
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
+ goto err;
+ }
+
+ // version
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_VERSION_FIELD,
+ strlen(SYSEVENT_VERSION_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, SYSEVENT_VERSION_VALUE,
+ strlen(SYSEVENT_VERSION_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // *** END common event header ***
+
+ // *** BEGIN syslog fields ***
+
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SYSLOG_FIELDS_FIELD,
+ strlen(SYSEVENT_SYSLOG_FIELDS_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_map_open(g) != yajl_gen_status_ok)
+ goto err;
+
+ // eventSourceHost
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_EVENT_SOURCE_HOST_FIELD,
+ strlen(SYSEVENT_EVENT_SOURCE_HOST_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)host, strlen(host)) != yajl_gen_status_ok)
+ goto err;
+
+ // eventSourceType
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_EVENT_SOURCE_TYPE_FIELD,
+ strlen(SYSEVENT_EVENT_SOURCE_TYPE_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_EVENT_SOURCE_TYPE_VALUE,
+ strlen(SYSEVENT_EVENT_SOURCE_TYPE_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // syslogFieldsVersion
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SYSLOG_FIELDS_VERSION_FIELD,
+ strlen(SYSEVENT_SYSLOG_FIELDS_VERSION_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_number(g, SYSEVENT_SYSLOG_FIELDS_VERSION_VALUE,
+ strlen(SYSEVENT_SYSLOG_FIELDS_VERSION_VALUE)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ // syslogMsg
+ if (msg != NULL) {
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SYSLOG_MSG_FIELD,
+ strlen(SYSEVENT_SYSLOG_MSG_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)msg, strlen(msg)) != yajl_gen_status_ok)
+ goto err;
+ }
+
+ // syslogProc
+ if (process != NULL) {
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SYSLOG_PROC_FIELD,
+ strlen(SYSEVENT_SYSLOG_PROC_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)process, strlen(process)) !=
+ yajl_gen_status_ok)
+ goto err;
+ }
+
+ // syslogSev
+ if (sev != NULL) {
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SYSLOG_SEV_FIELD,
+ strlen(SYSEVENT_SYSLOG_SEV_FIELD)) !=
+ yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)sev, strlen(sev)) != yajl_gen_status_ok)
+ goto err;
+ }
+
+ // syslogTag
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SYSLOG_TAG_FIELD,
+ strlen(SYSEVENT_SYSLOG_TAG_FIELD)) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_string(g, (u_char *)SYSEVENT_SYSLOG_TAG_VALUE,
+ strlen(SYSEVENT_SYSLOG_TAG_VALUE)) != yajl_gen_status_ok)
+ goto err;
+
+ // *** END syslog fields ***
+
+ // close syslog and header fields
+ if (yajl_gen_map_close(g) != yajl_gen_status_ok ||
+ yajl_gen_map_close(g) != yajl_gen_status_ok)
+ goto err;
+
+ if (yajl_gen_get_buf(g, &buf2, &len) != yajl_gen_status_ok)
+ goto err;
+
+ *buf = strdup((char *)buf2);
+
+ if (*buf == NULL) {
+ ERROR("sysevent plugin: gen_message_payload strdup failed");
+ goto err;
+ }
+
+ yajl_gen_free(g);
+
+ return 0;
+
+err:
+ yajl_gen_free(g);
+ ERROR("sysevent plugin: gen_message_payload failed to generate JSON");
+ return -1;
+}
+
+static int read_socket() {
+ int recv_flags = MSG_DONTWAIT;
+
+ while (42) {
+ struct sockaddr_storage src_addr;
+ socklen_t src_addr_len = sizeof(src_addr);
+
+ char buffer[listen_buffer_size];
+ memset(buffer, '\0', listen_buffer_size);
+
+ ssize_t count = recvfrom(sock, buffer, sizeof(buffer), recv_flags,
+ (struct sockaddr *)&src_addr, &src_addr_len);
+
+ if (count < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ pthread_mutex_lock(&sysevent_data_lock);
+
+ // There was nothing more to receive for now, so...
+ // If ring head does not equal ring tail, there is data
+ // in the ring buffer for the dequeue thread to read, so
+ // signal it
+ if (ring.head != ring.tail)
+ pthread_cond_signal(&sysevent_cond);
+
+ pthread_mutex_unlock(&sysevent_data_lock);
+
+ // Since there was nothing to receive, set recv to block and
+ // try again
+ recv_flags = 0;
+ continue;
+ } else if (errno != EINTR) {
+ ERROR("sysevent plugin: failed to receive data: %s", STRERRNO);
+ return -1;
+ } else {
+ // Interrupt, so continue and try again
+ continue;
+ }
+ }
+
+ if (count >= sizeof(buffer)) {
+ WARNING("sysevent plugin: datagram too large for buffer: truncated");
+ }
+
+ // We successfully received a message, so don't block on the next
+ // read in case there are more (and if there aren't, it will be
+ // handled above in the EWOULDBLOCK error-checking)
+ recv_flags = MSG_DONTWAIT;
+
+ // 1. Acquire data lock
+ // 2. Push to buffer if there is room, otherwise raise warning
+ // and allow dequeue thread to take over
+
+ pthread_mutex_lock(&sysevent_data_lock);
+
+ int next = ring.head + 1;
+ if (next >= ring.maxLen)
+ next = 0;
+
+ if (next == ring.tail) {
+ // Buffer is full, signal the dequeue thread to process the buffer
+ // and clean it out, and then sleep
+ WARNING("sysevent plugin: ring buffer full");
+
+ pthread_cond_signal(&sysevent_cond);
+ pthread_mutex_unlock(&sysevent_data_lock);
+
+ usleep(1000);
+ continue;
+ } else {
+ DEBUG("sysevent plugin: writing %s", buffer);
+
+ sstrncpy(ring.buffer[ring.head], buffer, sizeof(buffer));
+ ring.timestamp[ring.head] = cdtime();
+ ring.head = next;
+ }
+
+ pthread_mutex_unlock(&sysevent_data_lock);
+ }
+}
+
+static void sysevent_dispatch_notification(const char *message,
+#if HAVE_YAJL_V2
+ yajl_val *node,
+#endif
+ cdtime_t timestamp) {
+ char *buf = NULL;
+
+ notification_t n = {
+ .severity = NOTIF_OKAY,
+ .time = cdtime(),
+ .plugin = "sysevent",
+ .type = "gauge",
+ };
+
+#if HAVE_YAJL_V2
+ if (node != NULL) {
+ // If we have a parsed-JSON node to work with, use that
+ // msg
+ const char *msg_path[] = {rsyslog_keys[2], (const char *)0};
+ yajl_val msg_v = yajl_tree_get(*node, msg_path, yajl_t_string);
+
+ char msg[listen_buffer_size];
+
+ if (msg_v != NULL) {
+ memset(msg, '\0', listen_buffer_size);
+ snprintf(msg, listen_buffer_size, "%s%c", YAJL_GET_STRING(msg_v), '\0');
+ }
+
+ // severity
+ const char *severity_path[] = {"@fields", rsyslog_field_keys[1],
+ (const char *)0};
+ yajl_val severity_v = yajl_tree_get(*node, severity_path, yajl_t_string);
+
+ char severity[listen_buffer_size];
+
+ if (severity_v != NULL) {
+ memset(severity, '\0', listen_buffer_size);
+ snprintf(severity, listen_buffer_size, "%s%c",
+ YAJL_GET_STRING(severity_v), '\0');
+ }
+
+ // sev_num
+ const char *sev_num_str_path[] = {"@fields", rsyslog_field_keys[2],
+ (const char *)0};
+ yajl_val sev_num_str_v =
+ yajl_tree_get(*node, sev_num_str_path, yajl_t_string);
+
+ char sev_num_str[listen_buffer_size];
+ int sev_num = -1;
+
+ if (sev_num_str_v != NULL) {
+ memset(sev_num_str, '\0', listen_buffer_size);
+ snprintf(sev_num_str, listen_buffer_size, "%s%c",
+ YAJL_GET_STRING(sev_num_str_v), '\0');
+
+ sev_num = atoi(sev_num_str);
+
+ if (sev_num < 4)
+ n.severity = NOTIF_FAILURE;
+ }
+
+ // process
+ const char *process_path[] = {"@fields", rsyslog_field_keys[3],
+ (const char *)0};
+ yajl_val process_v = yajl_tree_get(*node, process_path, yajl_t_string);
+
+ char process[listen_buffer_size];
+
+ if (process_v != NULL) {
+ memset(process, '\0', listen_buffer_size);
+ snprintf(process, listen_buffer_size, "%s%c", YAJL_GET_STRING(process_v),
+ '\0');
+ }
+
+ // hostname
+ const char *hostname_path[] = {rsyslog_keys[1], (const char *)0};
+ yajl_val hostname_v = yajl_tree_get(*node, hostname_path, yajl_t_string);
+
+ char hostname_str[listen_buffer_size];
+
+ if (hostname_v != NULL) {
+ memset(hostname_str, '\0', listen_buffer_size);
+ snprintf(hostname_str, listen_buffer_size, "%s%c",
+ YAJL_GET_STRING(hostname_v), '\0');
+ }
+
+ gen_message_payload(
+ (msg_v != NULL ? msg : NULL), (severity_v != NULL ? severity : NULL),
+ (sev_num_str_v != NULL ? sev_num : -1),
+ (process_v != NULL ? process : NULL),
+ (hostname_v != NULL ? hostname_str : hostname_g), timestamp, &buf);
+ } else {
+ // Data was not sent in JSON format, so just treat the whole log entry
+ // as the message (and we'll be unable to acquire certain data, so the
+ // payload
+ // generated below will be less informative)
+
+ gen_message_payload(message, NULL, -1, NULL, hostname_g, timestamp, &buf);
+ }
+#else
+ gen_message_payload(message, NULL, -1, NULL, hostname_g, timestamp, &buf);
+#endif
+
+ sstrncpy(n.host, hostname_g, sizeof(n.host));
+
+ int status = plugin_notification_meta_add_string(&n, "ves", buf);
+
+ if (status < 0) {
+ sfree(buf);
+ ERROR("sysevent plugin: unable to set notification VES metadata: %s",
+ STRERRNO);
+ return;
+ }
+
+ DEBUG("sysevent plugin: notification VES metadata: %s",
+ n.meta->nm_value.nm_string);
+
+ DEBUG("sysevent plugin: dispatching message");
+
+ plugin_dispatch_notification(&n);
+ plugin_notification_meta_free(n.meta);
+
+ // strdup'd in gen_message_payload
+ if (buf != NULL)
+ sfree(buf);
+}
+
+static void read_ring_buffer() {
+ pthread_mutex_lock(&sysevent_data_lock);
+
+ // If there's currently nothing to read from the buffer,
+ // then wait
+ if (ring.head == ring.tail)
+ pthread_cond_wait(&sysevent_cond, &sysevent_data_lock);
+
+ while (ring.head != ring.tail) {
+ int next = ring.tail + 1;
+
+ if (next >= ring.maxLen)
+ next = 0;
+
+ DEBUG("sysevent plugin: reading from ring buffer: %s",
+ ring.buffer[ring.tail]);
+
+ cdtime_t timestamp = ring.timestamp[ring.tail];
+ char *match_str = NULL;
+
+#if HAVE_YAJL_V2
+ // Try to parse JSON, and if it fails, fall back to plain string
+ char errbuf[1024];
+ errbuf[0] = 0;
+ yajl_val node = yajl_tree_parse((const char *)ring.buffer[ring.tail],
+ errbuf, sizeof(errbuf));
+
+ if (node != NULL) {
+ // JSON rsyslog data
+
+ // If we have any regex filters, we need to see if the message portion of
+ // the data matches any of them (otherwise we're not interested)
+ if (monitor_all_messages == 0) {
+ const char *path[] = {"@message", (const char *)0};
+ yajl_val v = yajl_tree_get(node, path, yajl_t_string);
+
+ char json_val[listen_buffer_size];
+ memset(json_val, '\0', listen_buffer_size);
+
+ snprintf(json_val, listen_buffer_size, "%s%c", YAJL_GET_STRING(v),
+ '\0');
+
+ match_str = (char *)&json_val;
+ }
+ } else {
+ // non-JSON rsyslog data
+
+ // If we have any regex filters, we need to see if the message data
+ // matches any of them (otherwise we're not interested)
+ if (monitor_all_messages == 0)
+ match_str = ring.buffer[ring.tail];
+ }
+#else
+ // If we have any regex filters, we need to see if the message data
+ // matches any of them (otherwise we're not interested)
+ if (monitor_all_messages == 0)
+ match_str = ring.buffer[ring.tail];
+#endif
+
+ int is_match = 1;
+
+ // If we care about matching, do that comparison here
+ if (match_str != NULL) {
+ if (ignorelist_match(ignorelist, match_str) != 0)
+ is_match = 0;
+ else
+ DEBUG("sysevent plugin: regex filter match");
+ }
+
+#if HAVE_YAJL_V2
+ if (is_match == 1 && node != NULL) {
+ sysevent_dispatch_notification(NULL, &node, timestamp);
+ yajl_tree_free(node);
+ } else if (is_match == 1)
+ sysevent_dispatch_notification(ring.buffer[ring.tail], NULL, timestamp);
+#else
+ if (is_match == 1)
+ sysevent_dispatch_notification(ring.buffer[ring.tail], timestamp);
+#endif
+
+ ring.tail = next;
+ }
+
+ pthread_mutex_unlock(&sysevent_data_lock);
+}
+
+static void *sysevent_socket_thread(void *arg) /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ while (sysevent_socket_thread_loop > 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ if (sock == -1)
+ return (void *)0;
+
+ int status = read_socket();
+
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (status < 0) {
+ WARNING("sysevent plugin: problem with socket thread (status: %d)",
+ status);
+ sysevent_socket_thread_error = 1;
+ break;
+ }
+ } /* while (sysevent_socket_thread_loop > 0) */
+
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ return (void *)0;
+} /* }}} void *sysevent_socket_thread */
+
+// Entry point for thread responsible for reading from
+// ring buffer and dispatching notifications
+static void *sysevent_dequeue_thread(void *arg) /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ while (sysevent_dequeue_thread_loop > 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ read_ring_buffer();
+
+ pthread_mutex_lock(&sysevent_thread_lock);
+ } /* while (sysevent_dequeue_thread_loop > 0) */
+
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ return (void *)0;
+} /* }}} void *sysevent_dequeue_thread */
+
+static int start_socket_thread(void) /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (sysevent_socket_thread_loop != 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+ return 0;
+ }
+
+ sysevent_socket_thread_loop = 1;
+ sysevent_socket_thread_error = 0;
+
+ DEBUG("sysevent plugin: starting socket thread");
+
+ int status = plugin_thread_create(&sysevent_socket_thread_id,
+ /* attr = */ NULL, sysevent_socket_thread,
+ /* arg = */ (void *)0, "sysevent");
+ if (status != 0) {
+ sysevent_socket_thread_loop = 0;
+ ERROR("sysevent plugin: starting socket thread failed.");
+ pthread_mutex_unlock(&sysevent_thread_lock);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ return 0;
+} /* }}} int start_socket_thread */
+
+static int start_dequeue_thread(void) /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (sysevent_dequeue_thread_loop != 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+ return 0;
+ }
+
+ sysevent_dequeue_thread_loop = 1;
+
+ int status = plugin_thread_create(&sysevent_dequeue_thread_id,
+ /* attr = */ NULL, sysevent_dequeue_thread,
+ /* arg = */ (void *)0, "ssyevent");
+ if (status != 0) {
+ sysevent_dequeue_thread_loop = 0;
+ ERROR("sysevent plugin: Starting dequeue thread failed.");
+ pthread_mutex_unlock(&sysevent_thread_lock);
+ return -1;
+ }
+
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ return status;
+} /* }}} int start_dequeue_thread */
+
+static int start_threads(void) /* {{{ */
+{
+ int status = start_socket_thread();
+ int status2 = start_dequeue_thread();
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int start_threads */
+
+static int stop_socket_thread(int shutdown) /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (sysevent_socket_thread_loop == 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+ return -1;
+ }
+
+ sysevent_socket_thread_loop = 0;
+ pthread_cond_broadcast(&sysevent_cond);
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ int status;
+
+ if (shutdown == 1) {
+ // Since the thread is blocking, calling pthread_join
+ // doesn't actually succeed in stopping it. It will stick around
+ // until a message is received on the socket (at which
+ // it will realize that "sysevent_socket_thread_loop" is 0 and will
+ // break out of the read loop and be allowed to die). This is
+ // fine when the process isn't supposed to be exiting, but in
+ // the case of a process shutdown, we don't want to have an
+ // idle thread hanging around. Calling pthread_cancel here in
+ // the case of a shutdown is just assures that the thread is
+ // gone and that the process has been fully terminated.
+
+ DEBUG("sysevent plugin: Canceling socket thread for process shutdown");
+
+ status = pthread_cancel(sysevent_socket_thread_id);
+
+ if (status != 0 && status != ESRCH) {
+ ERROR("sysevent plugin: Unable to cancel socket thread: %d (%s)", status,
+ STRERRNO);
+ status = -1;
+ } else
+ status = 0;
+ } else {
+ status = pthread_join(sysevent_socket_thread_id, /* return = */ NULL);
+ if (status != 0 && status != ESRCH) {
+ ERROR("sysevent plugin: Stopping socket thread failed.");
+ status = -1;
+ } else
+ status = 0;
+ }
+
+ pthread_mutex_lock(&sysevent_thread_lock);
+ memset(&sysevent_socket_thread_id, 0, sizeof(sysevent_socket_thread_id));
+ sysevent_socket_thread_error = 0;
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ DEBUG("sysevent plugin: Finished requesting stop of socket thread");
+
+ return status;
+} /* }}} int stop_socket_thread */
+
+static int stop_dequeue_thread() /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (sysevent_dequeue_thread_loop == 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+ return -1;
+ }
+
+ sysevent_dequeue_thread_loop = 0;
+ pthread_cond_broadcast(&sysevent_cond);
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ // Since the thread is blocking, calling pthread_join
+ // doesn't actually succeed in stopping it. It will stick around
+ // until a message is received on the socket (at which
+ // it will realize that "sysevent_dequeue_thread_loop" is 0 and will
+ // break out of the read loop and be allowed to die). Since this
+ // function is called when the processing is exiting, we don't want to
+ // have an idle thread hanging around. Calling pthread_cancel here
+ // just assures that the thread is gone and that the process has been
+ // fully terminated.
+
+ DEBUG("sysevent plugin: Canceling dequeue thread for process shutdown");
+
+ int status = pthread_cancel(sysevent_dequeue_thread_id);
+
+ if (status != 0 && status != ESRCH) {
+ ERROR("sysevent plugin: Unable to cancel dequeue thread: %d (%s)", status,
+ STRERRNO);
+ status = -1;
+ } else
+ status = 0;
+
+ pthread_mutex_lock(&sysevent_thread_lock);
+ memset(&sysevent_dequeue_thread_id, 0, sizeof(sysevent_dequeue_thread_id));
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ DEBUG("sysevent plugin: Finished requesting stop of dequeue thread");
+
+ return status;
+} /* }}} int stop_dequeue_thread */
+
+static int stop_threads() /* {{{ */
+{
+ int status = stop_socket_thread(1);
+ int status2 = stop_dequeue_thread();
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int stop_threads */
+
+static int sysevent_init(void) /* {{{ */
+{
+ ring.head = 0;
+ ring.tail = 0;
+ ring.maxLen = buffer_length;
+ ring.buffer = (char **)calloc(buffer_length, sizeof(char *));
+
+ if (ring.buffer == NULL) {
+ ERROR("sysevent plugin: sysevent_init ring buffer calloc failed");
+ return -1;
+ }
+
+ for (int i = 0; i < buffer_length; i++) {
+ ring.buffer[i] = calloc(1, listen_buffer_size);
+
+ if (ring.buffer[i] == NULL) {
+ ERROR("sysevent plugin: sysevent_init ring buffer entry calloc failed");
+ return -1;
+ }
+ }
+
+ ring.timestamp = (cdtime_t *)calloc(buffer_length, sizeof(cdtime_t));
+
+ if (ring.timestamp == NULL) {
+ ERROR("sysevent plugin: sysevent_init ring buffer timestamp calloc failed");
+ return -1;
+ }
+
+ if (sock == -1) {
+ struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_DGRAM,
+ .ai_protocol = 0,
+ .ai_flags = AI_PASSIVE | AI_ADDRCONFIG,
+ };
+ struct addrinfo *res = 0;
+
+ int err = getaddrinfo(listen_ip, listen_port, &hints, &res);
+
+ if (err != 0) {
+ ERROR("sysevent plugin: failed to resolve local socket address (err=%d)",
+ err);
+ freeaddrinfo(res);
+ return -1;
+ }
+
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (sock == -1) {
+ ERROR("sysevent plugin: failed to open socket: %s", STRERRNO);
+ freeaddrinfo(res);
+ return -1;
+ }
+
+ if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) {
+ ERROR("sysevent plugin: failed to bind socket: %s", STRERRNO);
+ freeaddrinfo(res);
+ sock = -1;
+ return -1;
+ }
+
+ freeaddrinfo(res);
+ }
+
+ DEBUG("sysevent plugin: socket created and bound");
+
+ return start_threads();
+} /* }}} int sysevent_init */
+
+static int sysevent_config_add_listen(const oconfig_item_t *ci) /* {{{ */
+{
+ if (ci->values_num != 2 || ci->values[0].type != OCONFIG_TYPE_STRING ||
+ ci->values[1].type != OCONFIG_TYPE_STRING) {
+ ERROR("sysevent plugin: The `%s' config option needs "
+ "two string arguments (ip and port).",
+ ci->key);
+ return -1;
+ }
+
+ listen_ip = strdup(ci->values[0].value.string);
+ listen_port = strdup(ci->values[1].value.string);
+
+ return 0;
+}
+
+static int sysevent_config_add_buffer_size(const oconfig_item_t *ci) /* {{{ */
+{
+ int tmp = 0;
+
+ if (cf_util_get_int(ci, &tmp) != 0)
+ return -1;
+ else if ((tmp >= 1024) && (tmp <= 65535))
+ listen_buffer_size = tmp;
+ else {
+ WARNING(
+ "sysevent plugin: The `BufferSize' must be between 1024 and 65535.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sysevent_config_add_buffer_length(const oconfig_item_t *ci) /* {{{ */
+{
+ int tmp = 0;
+
+ if (cf_util_get_int(ci, &tmp) != 0)
+ return -1;
+ else if ((tmp >= 3) && (tmp <= 4096))
+ buffer_length = tmp;
+ else {
+ WARNING("sysevent plugin: The `Bufferlength' must be between 3 and 4096.");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int sysevent_config_add_regex_filter(const oconfig_item_t *ci) /* {{{ */
+{
+ if (ci->values_num != 1 || ci->values[0].type != OCONFIG_TYPE_STRING) {
+ ERROR("sysevent plugin: The `%s' config option needs "
+ "one string argument, a regular expression.",
+ ci->key);
+ return -1;
+ }
+
+#if HAVE_REGEX_H
+ if (ignorelist == NULL)
+ ignorelist = ignorelist_create(/* invert = */ 1);
+
+ int status = ignorelist_add(ignorelist, ci->values[0].value.string);
+
+ if (status != 0) {
+ ERROR("sysevent plugin: invalid regular expression: %s",
+ ci->values[0].value.string);
+ return 1;
+ }
+
+ monitor_all_messages = 0;
+#else
+ WARNING("sysevent plugin: The plugin has been compiled without support "
+ "for the \"RegexFilter\" option.");
+#endif
+
+ return 0;
+}
+
+static int sysevent_config(oconfig_item_t *ci) /* {{{ */
+{
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp("Listen", child->key) == 0)
+ sysevent_config_add_listen(child);
+ else if (strcasecmp("BufferSize", child->key) == 0)
+ sysevent_config_add_buffer_size(child);
+ else if (strcasecmp("BufferLength", child->key) == 0)
+ sysevent_config_add_buffer_length(child);
+ else if (strcasecmp("RegexFilter", child->key) == 0)
+ sysevent_config_add_regex_filter(child);
+ else {
+ WARNING("sysevent plugin: Option `%s' is not allowed here.", child->key);
+ }
+ }
+
+ return 0;
+} /* }}} int sysevent_config */
+
+static int sysevent_read(void) /* {{{ */
+{
+ pthread_mutex_lock(&sysevent_thread_lock);
+
+ if (sysevent_socket_thread_error != 0) {
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ ERROR("sysevent plugin: The sysevent socket thread had a problem (%d). "
+ "Restarting it.",
+ sysevent_socket_thread_error);
+
+ stop_threads();
+
+ start_threads();
+
+ return -1;
+ } /* if (sysevent_socket_thread_error != 0) */
+
+ pthread_mutex_unlock(&sysevent_thread_lock);
+
+ return 0;
+} /* }}} int sysevent_read */
+
+static int sysevent_shutdown(void) /* {{{ */
+{
+ DEBUG("sysevent plugin: Shutting down thread.");
+
+ int status = stop_threads();
+ int status2 = 0;
+
+ if (sock != -1) {
+ status2 = close(sock);
+ if (status2 != 0) {
+ ERROR("sysevent plugin: failed to close socket %d: %d (%s)", sock, status,
+ STRERRNO);
+ }
+
+ sock = -1;
+ }
+
+ free(listen_ip);
+ free(listen_port);
+
+ for (int i = 0; i < buffer_length; i++) {
+ free(ring.buffer[i]);
+ }
+
+ free(ring.buffer);
+ free(ring.timestamp);
+
+ if (status != 0)
+ return status;
+ else
+ return status2;
+} /* }}} int sysevent_shutdown */
+
+void module_register(void) {
+ plugin_register_complex_config("sysevent", sysevent_config);
+ plugin_register_init("sysevent", sysevent_init);
+ plugin_register_read("sysevent", sysevent_read);
+ plugin_register_shutdown("sysevent", sysevent_shutdown);
+} /* void module_register */
static int notif_severity;
static const char *config_keys[] = {
- "LogLevel", "NotifyLevel",
+ "LogLevel",
+ "NotifyLevel",
};
static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
log_level = parse_log_severity(value);
if (log_level < 0) {
log_level = LOG_INFO;
- ERROR("syslog: invalid loglevel [%s] defaulting to 'info'", value);
- return 1;
+ WARNING("syslog: invalid loglevel [%s] defaulting to 'info'", value);
}
} else if (strcasecmp(key, "NotifyLevel") == 0) {
notif_severity = parse_notif_severity(value);
- if (notif_severity < 0)
+ if (notif_severity < 0) {
+ ERROR("syslog: invalid notification severity [%s]", value);
return 1;
+ }
}
return 0;
status = plugin_register_complex_read(
NULL, cb_name, tcsv_read, interval,
&(user_data_t){
- .data = id, .free_func = tcsv_instance_definition_destroy,
+ .data = id,
+ .free_func = tcsv_instance_definition_destroy,
});
if (status != 0) {
ERROR("tail_csv plugin: Registering complex read function failed.");
derive_t read, derive_t write) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = read}, {.derive = write},
+ {.derive = read},
+ {.derive = write},
};
vl.values = values;
#if TCP_STATE_MIN > 0
|| (state < TCP_STATE_MIN)
#endif
- ) {
+ ) {
NOTICE("tcpconns plugin: Ignoring connection with "
"unknown state 0x%02" PRIx8 ".",
state);
return 0;
} /* int conn_read_file */
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_SYSCTLBYNAME
-/* #endif HAVE_SYSCTLBYNAME */
+ /* #endif HAVE_SYSCTLBYNAME */
#elif HAVE_LIBKVM_NLIST
#endif /* HAVE_LIBKVM_NLIST */
return 0;
} /* int conn_read */
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_SYSCTLBYNAME
static int conn_read(void) {
return 0;
}
-/* int conn_read */
-/* #endif HAVE_KVM_GETFILES */
+ /* int conn_read */
+ /* #endif HAVE_KVM_GETFILES */
#elif HAVE_LIBKVM_NLIST
static int kread(u_long addr, void *buf, int size) {
return 0;
}
-/* #endif HAVE_LIBKVM_NLIST */
+ /* #endif HAVE_LIBKVM_NLIST */
#elif KERNEL_AIX
*/
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
vl.values = values;
tmp = atoi(value);
if (tmp < 0) {
- WARNING("ted plugin: Invalid retry count: %i", tmp);
+ ERROR("ted plugin: Invalid retry count: %i", tmp);
return 1;
}
conf_retries = tmp;
if ((len < 0) || ((size_t)len >= sizeof(filename)))
return -1;
- len = (ssize_t)read_file_contents(filename, data, sizeof(data));
+ len = (ssize_t)read_text_file_contents(filename, data, sizeof(data));
if ((len > 0) && ((size_t)len > sizeof(str_temp)) && (data[--len] == '\n') &&
(!strncmp(data, str_temp, sizeof(str_temp) - 1))) {
char *endptr = NULL;
n.time = vl->time;
- status = snprintf(buf, bufsize, "Host %s, plugin %s", vl->host, vl->plugin);
+ status = ssnprintf(buf, bufsize, "Host %s, plugin %s", vl->host, vl->plugin);
buf += status;
bufsize -= status;
if (vl->plugin_instance[0] != '\0') {
- status = snprintf(buf, bufsize, " (instance %s)", vl->plugin_instance);
+ status = ssnprintf(buf, bufsize, " (instance %s)", vl->plugin_instance);
buf += status;
bufsize -= status;
}
- status = snprintf(buf, bufsize, " type %s", vl->type);
+ status = ssnprintf(buf, bufsize, " type %s", vl->type);
buf += status;
bufsize -= status;
if (vl->type_instance[0] != '\0') {
- status = snprintf(buf, bufsize, " (instance %s)", vl->type_instance);
+ status = ssnprintf(buf, bufsize, " (instance %s)", vl->type_instance);
buf += status;
bufsize -= status;
}
/* Send an okay notification */
if (state == STATE_OKAY) {
if (state_old == STATE_MISSING)
- snprintf(buf, bufsize, ": Value is no longer missing.");
+ ssnprintf(buf, bufsize, ": Value is no longer missing.");
else
- snprintf(buf, bufsize, ": All data sources are within range again. "
- "Current value of \"%s\" is %f.",
- ds->ds[ds_index].name, values[ds_index]);
+ ssnprintf(buf, bufsize,
+ ": All data sources are within range again. "
+ "Current value of \"%s\" is %f.",
+ ds->ds[ds_index].name, values[ds_index]);
} else if (state == STATE_UNKNOWN) {
ERROR("ut_report_state: metric transition to UNKNOWN from a different "
"state. This shouldn't happen.");
if (th->flags & UT_FLAG_INVERT) {
if (!isnan(min) && !isnan(max)) {
- snprintf(buf, bufsize,
- ": Data source \"%s\" is currently "
- "%f. That is within the %s region of %f%s and %f%s.",
- ds->ds[ds_index].name, values[ds_index],
- (state == STATE_ERROR) ? "failure" : "warning", min,
- ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "", max,
- ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
+ ssnprintf(buf, bufsize,
+ ": Data source \"%s\" is currently "
+ "%f. That is within the %s region of %f%s and %f%s.",
+ ds->ds[ds_index].name, values[ds_index],
+ (state == STATE_ERROR) ? "failure" : "warning", min,
+ ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "", max,
+ ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
} else {
- snprintf(buf, bufsize, ": Data source \"%s\" is currently "
- "%f. That is %s the %s threshold of %f%s.",
- ds->ds[ds_index].name, values[ds_index],
- isnan(min) ? "below" : "above",
- (state == STATE_ERROR) ? "failure" : "warning",
- isnan(min) ? max : min,
- ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
+ ssnprintf(buf, bufsize,
+ ": Data source \"%s\" is currently "
+ "%f. That is %s the %s threshold of %f%s.",
+ ds->ds[ds_index].name, values[ds_index],
+ isnan(min) ? "below" : "above",
+ (state == STATE_ERROR) ? "failure" : "warning",
+ isnan(min) ? max : min,
+ ((th->flags & UT_FLAG_PERCENTAGE) != 0) ? "%" : "");
}
} else if (th->flags & UT_FLAG_PERCENTAGE) {
gauge_t value;
else
value = 100.0 * values[ds_index] / sum;
- snprintf(buf, bufsize,
- ": Data source \"%s\" is currently "
- "%g (%.2f%%). That is %s the %s threshold of %.2f%%.",
- ds->ds[ds_index].name, values[ds_index], value,
- (value < min) ? "below" : "above",
- (state == STATE_ERROR) ? "failure" : "warning",
- (value < min) ? min : max);
+ ssnprintf(buf, bufsize,
+ ": Data source \"%s\" is currently "
+ "%g (%.2f%%). That is %s the %s threshold of %.2f%%.",
+ ds->ds[ds_index].name, values[ds_index], value,
+ (value < min) ? "below" : "above",
+ (state == STATE_ERROR) ? "failure" : "warning",
+ (value < min) ? min : max);
} else /* is not inverted */
{
- snprintf(buf, bufsize, ": Data source \"%s\" is currently "
- "%f. That is %s the %s threshold of %f.",
- ds->ds[ds_index].name, values[ds_index],
- (values[ds_index] < min) ? "below" : "above",
- (state == STATE_ERROR) ? "failure" : "warning",
- (values[ds_index] < min) ? min : max);
+ ssnprintf(buf, bufsize,
+ ": Data source \"%s\" is currently "
+ "%f. That is %s the %s threshold of %f.",
+ ds->ds[ds_index].name, values[ds_index],
+ (values[ds_index] < min) ? "below" : "above",
+ (state == STATE_ERROR) ? "failure" : "warning",
+ (values[ds_index] < min) ? min : max);
}
}
FORMAT_VL(identifier, sizeof(identifier), vl);
NOTIFICATION_INIT_VL(&n, vl);
- snprintf(n.message, sizeof(n.message),
- "%s has not been updated for %.3f seconds.", identifier,
- CDTIME_T_TO_DOUBLE(missing_time));
+ ssnprintf(n.message, sizeof(n.message),
+ "%s has not been updated for %.3f seconds.", identifier,
+ CDTIME_T_TO_DOUBLE(missing_time));
n.time = now;
plugin_dispatch_notification(&n);
/* Ivy Bridge */
case 0x3A: /* IVB */
case 0x3E: /* IVB Xeon */
+ case 0x55: /* SKX,CLX Xeon */
+ case 0x6A: /* ICX Xeon */
do_smi = true;
do_core_cstate = (1 << 3) | (1 << 6) | (1 << 7);
do_pkg_cstate = (1 << 2) | (1 << 3) | (1 << 6) | (1 << 7);
break;
case 0x2D: /* SNB Xeon */
case 0x3E: /* IVB Xeon */
+ case 0x55: /* SKX,CLX Xeon */
+ case 0x6A: /* ICX Xeon */
do_rapl = RAPL_PKG | RAPL_CORES | RAPL_DRAM;
do_power_fields = TURBO_PLATFORM | PSTATES_PLATFORM;
break;
parse_int_file(const char *fmt, ...) {
va_list args;
char path[PATH_MAX];
+ char buf[256];
int len;
+ value_t v;
+ char *c;
+ FILE *fp;
va_start(args, fmt);
len = vsnprintf(path, sizeof(path), fmt, args);
return -1;
}
- value_t v;
- if (parse_value_file(path, &v, DS_TYPE_DERIVE) != 0) {
+ fp = fopen(path, "r");
+ if (fp == NULL) {
+ ERROR("turbostat plugin: unable to open: '%s': %s", path, strerror(errno));
+ return -1;
+ }
+
+ if (fgets(buf, sizeof(buf), fp) == NULL) {
+ ERROR("turbostat plugin: unable to read: '%s': %s", path, strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+ fclose(fp);
+
+ /* We only care about the first integer in the range */
+ c = strchr(buf, '-');
+ if (c != NULL)
+ *c = '\0';
+ c = strchr(buf, ',');
+ if (c != NULL)
+ *c = '\0';
+ strstripnewline(buf);
+
+ if (parse_value(buf, &v, DS_TYPE_DERIVE) != 0) {
ERROR("turbostat plugin: Parsing \"%s\" failed.", path);
return -1;
}
package_delta = NULL;
}
-/**********************
- * Collectd functions *
- **********************/
+ /**********************
+ * Collectd functions *
+ **********************/
#define DO_OR_GOTO_ERR(something) \
do { \
return ret;
}
-int save_affinity(void) {
+static int save_affinity(void) {
if (affinity_policy == policy_restore_affinity) {
/* Try to save the scheduling affinity, as it will be modified by
* get_counters().
return 0;
}
-void restore_affinity(void) {
+static void restore_affinity(void) {
/* Let's restore the affinity to the value saved in save_affinity */
if (affinity_policy == policy_restore_affinity)
(void)sched_setaffinity(0, cpu_saved_affinity_setsize,
df_complex value:GAUGE:0:U
df_inodes value:GAUGE:0:U
dilution_of_precision value:GAUGE:0:U
+disk_allocation value:GAUGE:0:U
+disk_capacity value:GAUGE:0:U
disk_error value:GAUGE:0:U
disk_io_time io_time:DERIVE:0:U, weighted_io_time:DERIVE:0:U
disk_latency read:GAUGE:0:U, write:GAUGE:0:U
disk_octets read:DERIVE:0:U, write:DERIVE:0:U
disk_ops read:DERIVE:0:U, write:DERIVE:0:U
disk_ops_complex value:DERIVE:0:U
+disk_physical value:GAUGE:0:U
disk_time read:DERIVE:0:U, write:DERIVE:0:U
dns_answer value:DERIVE:0:U
dns_notify value:DERIVE:0:U
spl value:GAUGE:U:U
swap value:GAUGE:0:1099511627776
swap_io value:DERIVE:0:U
+sysevent value:GAUGE:0:1
tcp_connections value:GAUGE:0:4294967295
tdp value:GAUGE:U:U
temperature value:GAUGE:U:U
}
result = (time_t)info.uptime;
-/* #endif KERNEL_LINUX */
+ /* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
kstat_t *ksp;
}
result = time(NULL) - (time_t)knp->value.ui32;
-/* #endif HAVE_LIBKSTAT */
+ /* #endif HAVE_LIBKSTAT */
#elif HAVE_SYS_SYSCTL_H
struct timeval boottv = {0};
}
result = time(NULL) - boottv.tv_sec;
-/* #endif HAVE_SYS_SYSCTL_H */
+ /* #endif HAVE_SYS_SYSCTL_H */
#elif HAVE_PERFSTAT
int status;
endutxent();
users_submit(users);
-/* #endif HAVE_GETUTXENT */
+ /* #endif HAVE_GETUTXENT */
#elif HAVE_GETUTENT
unsigned int users = 0;
endutent();
users_submit(users);
-/* #endif HAVE_GETUTENT */
+ /* #endif HAVE_GETUTENT */
#elif HAVE_LIBSTATGRAB
sg_user_stats *us;
#else
us->num_entries);
#endif
-/* #endif HAVE_LIBSTATGRAB */
+ /* #endif HAVE_LIBSTATGRAB */
#else
#error "No applicable input method."
* Sebastian 'tokkee' Harl <sh at tokkee.org>
**/
+// clang-format off
+/*
+ * Explicit order is required or _FILE_OFFSET_BITS will have definition mismatches on Solaris
+ * See Github Issue #3193 for details
+ */
+#include "utils/common/common.h"
#include "testing.h"
#include "utils/cmds/cmds.h"
-#include "utils/common/common.h"
+// clang-format on
static void error_cb(void *ud, cmd_status_t status, const char *format,
va_list ap) {
} parse_data[] = {
/* Valid FLUSH commands. */
{
- "FLUSH", NULL, CMD_OK, CMD_FLUSH,
+ "FLUSH",
+ NULL,
+ CMD_OK,
+ CMD_FLUSH,
},
{
- "FLUSH identifier=myhost/magic/MAGIC", NULL, CMD_OK, CMD_FLUSH,
+ "FLUSH identifier=myhost/magic/MAGIC",
+ NULL,
+ CMD_OK,
+ CMD_FLUSH,
},
{
- "FLUSH identifier=magic/MAGIC", &default_host_opts, CMD_OK, CMD_FLUSH,
+ "FLUSH identifier=magic/MAGIC",
+ &default_host_opts,
+ CMD_OK,
+ CMD_FLUSH,
},
{
- "FLUSH timeout=123 plugin=\"A\"", NULL, CMD_OK, CMD_FLUSH,
+ "FLUSH timeout=123 plugin=\"A\"",
+ NULL,
+ CMD_OK,
+ CMD_FLUSH,
},
/* Invalid FLUSH commands. */
{
/* Missing hostname; no default. */
- "FLUSH identifier=magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "FLUSH identifier=magic/MAGIC",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
/* Missing 'identifier' key. */
- "FLUSH myhost/magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "FLUSH myhost/magic/MAGIC",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
/* Invalid timeout. */
- "FLUSH timeout=A", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "FLUSH timeout=A",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
/* Invalid identifier. */
- "FLUSH identifier=invalid", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "FLUSH identifier=invalid",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
/* Invalid option. */
- "FLUSH invalid=option", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "FLUSH invalid=option",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
/* Valid GETVAL commands. */
{
- "GETVAL myhost/magic/MAGIC", NULL, CMD_OK, CMD_GETVAL,
+ "GETVAL myhost/magic/MAGIC",
+ NULL,
+ CMD_OK,
+ CMD_GETVAL,
},
{
- "GETVAL magic/MAGIC", &default_host_opts, CMD_OK, CMD_GETVAL,
+ "GETVAL magic/MAGIC",
+ &default_host_opts,
+ CMD_OK,
+ CMD_GETVAL,
},
/* Invalid GETVAL commands. */
{
- "GETVAL magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "GETVAL magic/MAGIC",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "GETVAL", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "GETVAL",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "GETVAL invalid", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "GETVAL invalid",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
/* Valid LISTVAL commands. */
{
- "LISTVAL", NULL, CMD_OK, CMD_LISTVAL,
+ "LISTVAL",
+ NULL,
+ CMD_OK,
+ CMD_LISTVAL,
},
/* Invalid LISTVAL commands. */
{
- "LISTVAL invalid", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "LISTVAL invalid",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
/* Valid PUTVAL commands. */
{
- "PUTVAL magic/MAGIC N:42", &default_host_opts, CMD_OK, CMD_PUTVAL,
+ "PUTVAL magic/MAGIC N:42",
+ &default_host_opts,
+ CMD_OK,
+ CMD_PUTVAL,
},
{
- "PUTVAL myhost/magic/MAGIC N:42", NULL, CMD_OK, CMD_PUTVAL,
+ "PUTVAL myhost/magic/MAGIC N:42",
+ NULL,
+ CMD_OK,
+ CMD_PUTVAL,
},
{
- "PUTVAL myhost/magic/MAGIC 1234:42", NULL, CMD_OK, CMD_PUTVAL,
+ "PUTVAL myhost/magic/MAGIC 1234:42",
+ NULL,
+ CMD_OK,
+ CMD_PUTVAL,
},
{
- "PUTVAL myhost/magic/MAGIC 1234:42 2345:23", NULL, CMD_OK, CMD_PUTVAL,
+ "PUTVAL myhost/magic/MAGIC 1234:42 2345:23",
+ NULL,
+ CMD_OK,
+ CMD_PUTVAL,
},
{
- "PUTVAL myhost/magic/MAGIC interval=2 1234:42", NULL, CMD_OK,
+ "PUTVAL myhost/magic/MAGIC interval=2 1234:42",
+ NULL,
+ CMD_OK,
CMD_PUTVAL,
},
{
- "PUTVAL myhost/magic/MAGIC interval=2 1234:42 interval=5 2345:23", NULL,
- CMD_OK, CMD_PUTVAL,
+ "PUTVAL myhost/magic/MAGIC interval=2 1234:42 interval=5 2345:23",
+ NULL,
+ CMD_OK,
+ CMD_PUTVAL,
},
/* Invalid PUTVAL commands. */
{
- "PUTVAL magic/MAGIC N:42", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "PUTVAL magic/MAGIC N:42",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "PUTVAL", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "PUTVAL",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "PUTVAL invalid N:42", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "PUTVAL invalid N:42",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "PUTVAL myhost/magic/MAGIC A:42", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "PUTVAL myhost/magic/MAGIC A:42",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "PUTVAL myhost/magic/MAGIC 1234:A", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "PUTVAL myhost/magic/MAGIC 1234:A",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "PUTVAL myhost/magic/MAGIC", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "PUTVAL myhost/magic/MAGIC",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "PUTVAL 1234:A", NULL, CMD_PARSE_ERROR, CMD_UNKNOWN,
+ "PUTVAL 1234:A",
+ NULL,
+ CMD_PARSE_ERROR,
+ CMD_UNKNOWN,
},
{
- "PUTVAL myhost/magic/UNKNOWN 1234:42", NULL, CMD_PARSE_ERROR,
+ "PUTVAL myhost/magic/UNKNOWN 1234:42",
+ NULL,
+ CMD_PARSE_ERROR,
CMD_UNKNOWN,
},
/*
/* Invalid commands. */
{
- "INVALID", NULL, CMD_UNKNOWN_COMMAND, CMD_UNKNOWN,
+ "INVALID",
+ NULL,
+ CMD_UNKNOWN_COMMAND,
+ CMD_UNKNOWN,
},
{
- "INVALID interval=2", NULL, CMD_UNKNOWN_COMMAND, CMD_UNKNOWN,
+ "INVALID interval=2",
+ NULL,
+ CMD_UNKNOWN_COMMAND,
+ CMD_UNKNOWN,
},
};
memset(&cmd, 0, sizeof(cmd));
status = cmd_parse(input, &cmd, parse_data[i].opts, &err);
- snprintf(description, sizeof(description), "cmd_parse (\"%s\", opts=%p) = "
- "%d (type=%d [%s]); want %d "
- "(type=%d [%s])",
- parse_data[i].input, parse_data[i].opts, status, cmd.type,
- CMD_TO_STRING(cmd.type), parse_data[i].expected_status,
- parse_data[i].expected_type,
- CMD_TO_STRING(parse_data[i].expected_type));
+ ssnprintf(description, sizeof(description),
+ "cmd_parse (\"%s\", opts=%p) = "
+ "%d (type=%d [%s]); want %d "
+ "(type=%d [%s])",
+ parse_data[i].input, parse_data[i].opts, status, cmd.type,
+ CMD_TO_STRING(cmd.type), parse_data[i].expected_status,
+ parse_data[i].expected_type,
+ CMD_TO_STRING(parse_data[i].expected_type));
result = (status == parse_data[i].expected_status) &&
(cmd.type == parse_data[i].expected_type);
LOG(result, description);
* Niki W. Waibel <niki.waibel@gmx.net>
* Sebastian Harl <sh at tokkee.org>
* Michał Mirosław <mirq-linux at rere.qmqm.pl>
-**/
+ **/
#include "collectd.h"
return dest;
} /* char *sstrncpy */
+/* ssnprintf returns result from vsnprintf conistent with snprintf */
+int ssnprintf(char *str, size_t sz, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+
+ int ret = vsnprintf(str, sz, format, ap);
+
+ va_end(ap);
+
+ return ret;
+} /* int ssnprintf */
+
char *ssnprintf_alloc(char const *format, ...) /* {{{ */
{
char static_buffer[1024] = "";
pthread_mutex_unlock(&strerror_r_lock);
}
-/* #endif !HAVE_STRERROR_R */
+ /* #endif !HAVE_STRERROR_R */
#elif STRERROR_R_CHAR_P
{
if ((temp != NULL) && (temp != buf) && (temp[0] != '\0'))
sstrncpy(buf, temp, buflen);
else
- sstrncpy(buf, "strerror_r did not return "
- "an error message",
+ sstrncpy(buf,
+ "strerror_r did not return "
+ "an error message",
buflen);
}
}
-/* #endif STRERROR_R_CHAR_P */
+ /* #endif STRERROR_R_CHAR_P */
#else
if (strerror_r(errnum, buf, buflen) != 0) {
- snprintf(buf, buflen, "Error #%i; "
- "Additionally, strerror_r failed.",
+ snprintf(buf, buflen,
+ "Error #%i; "
+ "Additionally, strerror_r failed.",
errnum);
}
#endif /* STRERROR_R_CHAR_P */
else if (kn->data_type == KSTAT_DATA_UINT32)
retval = (long long)kn->value.ui32;
else if (kn->data_type == KSTAT_DATA_INT64)
- retval =
- (long long)kn->value.i64; /* According to ANSI C99 `long long' must hold
- at least 64 bits */
+ retval = (long long)kn->value.i64; /* According to ANSI C99 `long long' must
+ hold at least 64 bits */
else if (kn->data_type == KSTAT_DATA_UINT64)
retval = (long long)kn->value.ui64; /* XXX: Might overflow! */
else
#endif /* HAVE_HTONLL */
#if FP_LAYOUT_NEED_NOTHING
-/* Well, we need nothing.. */
-/* #endif FP_LAYOUT_NEED_NOTHING */
+ /* Well, we need nothing.. */
+ /* #endif FP_LAYOUT_NEED_NOTHING */
#elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP
#if FP_LAYOUT_NEED_ENDIANFLIP
return 0;
}
-ssize_t read_file_contents(const char *filename, char *buf, size_t bufsize) {
+ssize_t read_file_contents(const char *filename, void *buf, size_t bufsize) {
FILE *fh;
ssize_t ret;
return ret;
}
+ssize_t read_text_file_contents(const char *filename, char *buf,
+ size_t bufsize) {
+ ssize_t ret = read_file_contents(filename, buf, bufsize - 1);
+ if (ret < 0)
+ return ret;
+
+ buf[ret] = '\0';
+ return ret + 1;
+}
+
counter_t counter_diff(counter_t old_value, counter_t new_value) {
counter_t diff;
service_number = (int)ntohs(sa->sin6_port);
}
- if ((service_number > 0) && (service_number <= 65535))
+ if (service_number > 0)
break;
}
freeaddrinfo(ai_list);
- if ((service_number > 0) && (service_number <= 65535))
+ if (service_number > 0)
return service_number;
return -1;
} /* int service_name_to_port_number */
* Authors:
* Florian octo Forster <octo at collectd.org>
* Niki W. Waibel <niki.waibel@gmx.net>
-**/
+ **/
#ifndef COMMON_H
#define COMMON_H
char *sstrncpy(char *dest, const char *src, size_t n);
+__attribute__((format(printf, 3, 4))) int ssnprintf(char *str, size_t size,
+ char const *format, ...);
+
__attribute__((format(printf, 1, 2))) char *ssnprintf_alloc(char const *format,
...);
int walk_directory(const char *dir, dirwalk_callback_f callback,
void *user_data, int hidden);
/* Returns the number of bytes read or negative on error. */
-ssize_t read_file_contents(char const *filename, char *buf, size_t bufsize);
+ssize_t read_file_contents(char const *filename, void *buf, size_t bufsize);
+/* Writes the contents of the file into the buffer with a trailing NUL.
+ * Returns the number of bytes written to the buffer or negative on error. */
+ssize_t read_text_file_contents(char const *filename, char *buf,
+ size_t bufsize);
counter_t counter_diff(counter_t old_value, counter_t new_value);
* Florian octo Forster <octo at collectd.org>
*/
-#include "testing.h"
+// clang-format off
+/*
+ * Explicit order is required or _FILE_OFFSET_BITS will have definition mismatches on Solaris
+ * See Github Issue #3193 for details
+ */
#include "utils/common/common.h"
+#include "testing.h"
+// clang-format on
#if HAVE_KSTAT_H
#include <kstat.h>
};
for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
- char buffer[32];
+ char buffer[32] = {0};
- strncpy(buffer, cases[i].str, sizeof(buffer));
+ strncpy(buffer, cases[i].str, sizeof(buffer) - 1);
OK(escape_slashes(buffer, sizeof(buffer)) == 0);
EXPECT_EQ_STR(cases[i].want, buffer);
}
};
for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
- char buffer[16];
+ char buffer[16] = {0};
- strncpy(buffer, cases[i].str, sizeof(buffer));
+ strncpy(buffer, cases[i].str, sizeof(buffer) - 1);
OK(escape_string(buffer, sizeof(buffer)) == 0);
EXPECT_EQ_STR(cases[i].want, buffer);
}
}
DEF_TEST(strunescape) {
- char buffer[16];
+ char buffer[32] = {0};
int status;
- strncpy(buffer, "foo\\tbar", sizeof(buffer));
+ strncpy(buffer, "foo\\tbar", sizeof(buffer) - 1);
status = strunescape(buffer, sizeof(buffer));
OK(status == 0);
EXPECT_EQ_STR("foo\tbar", buffer);
- strncpy(buffer, "\\tfoo\\r\\n", sizeof(buffer));
+ strncpy(buffer, "\\tfoo\\r\\n", sizeof(buffer) - 1);
status = strunescape(buffer, sizeof(buffer));
OK(status == 0);
EXPECT_EQ_STR("\tfoo\r\n", buffer);
- strncpy(buffer, "With \\\"quotes\\\"", sizeof(buffer));
+ strncpy(buffer, "With \\\"quotes\\\"", sizeof(buffer) - 1);
status = strunescape(buffer, sizeof(buffer));
OK(status == 0);
EXPECT_EQ_STR("With \"quotes\"", buffer);
/* Backslash before null byte */
- strncpy(buffer, "\\tbackslash end\\", sizeof(buffer));
+ strncpy(buffer, "\\tbackslash end\\", sizeof(buffer) - 1);
status = strunescape(buffer, sizeof(buffer));
OK(status != 0);
EXPECT_EQ_STR("\tbackslash end", buffer);
return 0;
/* Backslash at buffer end */
- strncpy(buffer, "\\t3\\56", sizeof(buffer));
+ strncpy(buffer, "\\t3\\56", sizeof(buffer) - 1);
status = strunescape(buffer, 4);
OK(status != 0);
OK(buffer[0] == '\t');
for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
data_source_t dsrc = {
- .name = "value", .type = DS_TYPE_GAUGE, .min = 0.0, .max = NAN,
+ .name = "value",
+ .type = DS_TYPE_GAUGE,
+ .min = 0.0,
+ .max = NAN,
};
data_set_t ds = {
- .type = "example", .ds_num = 1, .ds = &dsrc,
+ .type = "example",
+ .ds_num = 1,
+ .ds = &dsrc,
};
value_t v = {
for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) {
cdtime_t t0 = TIME_T_TO_CDTIME_T(cases[i].t0);
value_to_rate_state_t state = {
- .last_value = cases[i].v0, .last_time = t0,
+ .last_value = cases[i].v0,
+ .last_time = t0,
};
gauge_t got;
} else {
for (size_t j = 0; j < n && cg_idx < STATIC_ARRAY_SIZE(cgroups); j++) {
char desc[DATA_MAX_NAME_LEN];
- snprintf(desc, sizeof(desc), "%u", cores[j]);
+ ssnprintf(desc, sizeof(desc), "%u", cores[j]);
cgroups[cg_idx].desc = strdup(desc);
if (cgroups[cg_idx].desc == NULL) {
for (int i = 0; i < num_cores; i++) {
char desc[DATA_MAX_NAME_LEN];
- snprintf(desc, sizeof(desc), "%d", i);
+ ssnprintf(desc, sizeof(desc), "%d", i);
cgl->cgroups[i].cores = calloc(1, sizeof(*(cgl->cgroups[i].cores)));
if (cgl->cgroups[i].cores == NULL) {
}
tmp[sizeof(tmp) - 1] = '\0';
- snprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s",
- r->instance_prefix, tmp);
+ ssnprintf(vl.type_instance, sizeof(vl.type_instance), "%s-%s",
+ r->instance_prefix, tmp);
}
}
vl.type_instance[sizeof(vl.type_instance) - 1] = '\0';
#if HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#if HAVE_ARPA_NAMESER_H
-#include <arpa/nameser.h>
-#endif
-#if HAVE_ARPA_NAMESER_COMPAT_H
-#include <arpa/nameser_compat.h>
-#endif
#if HAVE_NETDB_H
#include <netdb.h>
return 1; /* Success */
} /* int handle_ipv6 */
-/* #endif HAVE_IPV6 */
+ /* #endif HAVE_IPV6 */
#else /* if !HAVE_IPV6 */
static int handle_ipv6(__attribute__((unused)) void *pkg,
const char *qtype_str(int t) {
static char buf[32];
+ // clang-format off
+ /*
+ Built (with minor cleanup) from glibc-2.29 by
+ cat resolv/arpa/nameser.h | grep "ns_t_" | \
+ perl -ne '/ns_t_(\S+)\ =\ (\d+)/; print " case $2:\n return \"".uc($1)."\";\n";'
+ */
+ // clang-format on
switch (t) {
-#if (defined(__NAMESER)) && (__NAMESER >= 19991001)
- case ns_t_a:
+ case 1:
return "A";
- case ns_t_ns:
+ case 2:
return "NS";
- case ns_t_md:
+ case 3:
return "MD";
- case ns_t_mf:
+ case 4:
return "MF";
- case ns_t_cname:
+ case 5:
return "CNAME";
- case ns_t_soa:
+ case 6:
return "SOA";
- case ns_t_mb:
+ case 7:
return "MB";
- case ns_t_mg:
+ case 8:
return "MG";
- case ns_t_mr:
+ case 9:
return "MR";
- case ns_t_null:
+ case 10:
return "NULL";
- case ns_t_wks:
+ case 11:
return "WKS";
- case ns_t_ptr:
+ case 12:
return "PTR";
- case ns_t_hinfo:
+ case 13:
return "HINFO";
- case ns_t_minfo:
+ case 14:
return "MINFO";
- case ns_t_mx:
+ case 15:
return "MX";
- case ns_t_txt:
+ case 16:
return "TXT";
- case ns_t_rp:
+ case 17:
return "RP";
- case ns_t_afsdb:
+ case 18:
return "AFSDB";
- case ns_t_x25:
+ case 19:
return "X25";
- case ns_t_isdn:
+ case 20:
return "ISDN";
- case ns_t_rt:
+ case 21:
return "RT";
- case ns_t_nsap:
+ case 22:
return "NSAP";
- case ns_t_nsap_ptr:
+ case 23:
return "NSAP-PTR";
- case ns_t_sig:
+ case 24:
return "SIG";
- case ns_t_key:
+ case 25:
return "KEY";
- case ns_t_px:
+ case 26:
return "PX";
- case ns_t_gpos:
+ case 27:
return "GPOS";
- case ns_t_aaaa:
+ case 28:
return "AAAA";
- case ns_t_loc:
+ case 29:
return "LOC";
- case ns_t_nxt:
+ case 30:
return "NXT";
- case ns_t_eid:
+ case 31:
return "EID";
- case ns_t_nimloc:
+ case 32:
return "NIMLOC";
- case ns_t_srv:
+ case 33:
return "SRV";
- case ns_t_atma:
+ case 34:
return "ATMA";
- case ns_t_naptr:
+ case 35:
return "NAPTR";
- case ns_t_opt:
- return "OPT";
-#if __NAMESER >= 19991006
- case ns_t_kx:
+ case 36:
return "KX";
- case ns_t_cert:
+ case 37:
return "CERT";
- case ns_t_a6:
+ case 38:
return "A6";
- case ns_t_dname:
+ case 39:
return "DNAME";
- case ns_t_sink:
+ case 40:
return "SINK";
- case ns_t_tsig:
- return "TSIG";
-#endif
-#if __NAMESER >= 20090302
- case ns_t_apl:
+ case 41:
+ return "OPT";
+ case 42:
return "APL";
- case ns_t_ds:
+ case 43:
return "DS";
- case ns_t_sshfp:
+ case 44:
return "SSHFP";
- case ns_t_ipseckey:
+ case 45:
return "IPSECKEY";
- case ns_t_rrsig:
+ case 46:
return "RRSIG";
- case ns_t_nsec:
+ case 47:
return "NSEC";
- case ns_t_dnskey:
+ case 48:
return "DNSKEY";
- case ns_t_dhcid:
+ case 49:
return "DHCID";
- case ns_t_nsec3:
+ case 50:
return "NSEC3";
- case ns_t_nsec3param:
+ case 51:
return "NSEC3PARAM";
- case ns_t_hip:
+ case 52:
+ return "TLSA";
+ case 53:
+ return "SMIMEA";
+ case 55:
return "HIP";
- case ns_t_spf:
+ case 56:
+ return "NINFO";
+ case 57:
+ return "RKEY";
+ case 58:
+ return "TALINK";
+ case 59:
+ return "CDS";
+ case 60:
+ return "CDNSKEY";
+ case 61:
+ return "OPENPGPKEY";
+ case 62:
+ return "CSYNC";
+ case 99:
return "SPF";
- case ns_t_ixfr:
+ case 100:
+ return "UINFO";
+ case 101:
+ return "UID";
+ case 102:
+ return "GID";
+ case 103:
+ return "UNSPEC";
+ case 104:
+ return "NID";
+ case 105:
+ return "L32";
+ case 106:
+ return "L64";
+ case 107:
+ return "LP";
+ case 108:
+ return "EUI48";
+ case 109:
+ return "EUI64";
+ case 249:
+ return "TKEY";
+ case 250:
+ return "TSIG";
+ case 251:
return "IXFR";
-#endif
- case ns_t_axfr:
+ case 252:
return "AXFR";
- case ns_t_mailb:
+ case 253:
return "MAILB";
- case ns_t_maila:
+ case 254:
return "MAILA";
- case ns_t_any:
+ case 255:
return "ANY";
-#if __NAMESER >= 19991006
- case ns_t_zxfr:
- return "ZXFR";
-#endif
-#if __NAMESER >= 20090302
- case ns_t_dlv:
+ case 256:
+ return "URI";
+ case 257:
+ return "CAA";
+ case 258:
+ return "AVC";
+ case 32768:
+ return "TA";
+ case 32769:
return "DLV";
-#endif
-/* #endif __NAMESER >= 19991001 */
-#elif (defined(__BIND)) && (__BIND >= 19950621)
- case T_A:
- return "A"; /* 1 ... */
- case T_NS:
- return "NS";
- case T_MD:
- return "MD";
- case T_MF:
- return "MF";
- case T_CNAME:
- return "CNAME";
- case T_SOA:
- return "SOA";
- case T_MB:
- return "MB";
- case T_MG:
- return "MG";
- case T_MR:
- return "MR";
- case T_NULL:
- return "NULL";
- case T_WKS:
- return "WKS";
- case T_PTR:
- return "PTR";
- case T_HINFO:
- return "HINFO";
- case T_MINFO:
- return "MINFO";
- case T_MX:
- return "MX";
- case T_TXT:
- return "TXT";
- case T_RP:
- return "RP";
- case T_AFSDB:
- return "AFSDB";
- case T_X25:
- return "X25";
- case T_ISDN:
- return "ISDN";
- case T_RT:
- return "RT";
- case T_NSAP:
- return "NSAP";
- case T_NSAP_PTR:
- return "NSAP_PTR";
- case T_SIG:
- return "SIG";
- case T_KEY:
- return "KEY";
- case T_PX:
- return "PX";
- case T_GPOS:
- return "GPOS";
- case T_AAAA:
- return "AAAA";
- case T_LOC:
- return "LOC";
- case T_NXT:
- return "NXT";
- case T_EID:
- return "EID";
- case T_NIMLOC:
- return "NIMLOC";
- case T_SRV:
- return "SRV";
- case T_ATMA:
- return "ATMA";
- case T_NAPTR:
- return "NAPTR"; /* ... 35 */
-#if (__BIND >= 19960801)
- case T_KX:
- return "KX"; /* 36 ... */
- case T_CERT:
- return "CERT";
- case T_A6:
- return "A6";
- case T_DNAME:
- return "DNAME";
- case T_SINK:
- return "SINK";
- case T_OPT:
- return "OPT";
- case T_APL:
- return "APL";
- case T_DS:
- return "DS";
- case T_SSHFP:
- return "SSHFP";
- case T_RRSIG:
- return "RRSIG";
- case T_NSEC:
- return "NSEC";
- case T_DNSKEY:
- return "DNSKEY"; /* ... 48 */
- case T_TKEY:
- return "TKEY"; /* 249 */
-#endif /* __BIND >= 19960801 */
- case T_TSIG:
- return "TSIG"; /* 250 ... */
- case T_IXFR:
- return "IXFR";
- case T_AXFR:
- return "AXFR";
- case T_MAILB:
- return "MAILB";
- case T_MAILA:
- return "MAILA";
- case T_ANY:
- return "ANY"; /* ... 255 */
-#endif /* __BIND >= 19950621 */
default:
- snprintf(buf, sizeof(buf), "#%i", t);
+ ssnprintf(buf, sizeof(buf), "#%i", t);
return buf;
} /* switch (t) */
}
case 5:
return "Update";
default:
- snprintf(buf, sizeof(buf), "Opcode%d", o);
+ ssnprintf(buf, sizeof(buf), "Opcode%d", o);
return buf;
}
}
const char *rcode_str(int rcode) {
static char buf[32];
+ /* RFC2136 rcodes */
+ // clang-format off
+ /*
+ Built (with minor cleanup) from glibc-2.29 by
+ cat resolv/arpa/nameser.h | grep "ns_r_" | \
+ perl -ne '/ns_r_(\S+)\ =\ (\d+)/; print " case $2:\n return \"".uc($1)."\";\n";'
+
+ https://tools.ietf.org/html/rfc2671 assigns EDNS Extended RCODE "16" to "BADVERS"
+ https://tools.ietf.org/html/rfc2845 declares 0..15 as DNS RCODE and 16 is BADSIG.
+ */
+ // clang-format on
switch (rcode) {
-#if (defined(__NAMESER)) && (__NAMESER >= 19991006)
- case ns_r_noerror:
- return "NOERROR";
- case ns_r_formerr:
+ case 1:
return "FORMERR";
- case ns_r_servfail:
+ case 2:
return "SERVFAIL";
- case ns_r_nxdomain:
+ case 3:
return "NXDOMAIN";
- case ns_r_notimpl:
+ case 4:
return "NOTIMPL";
- case ns_r_refused:
+ case 5:
return "REFUSED";
- case ns_r_yxdomain:
+ case 6:
return "YXDOMAIN";
- case ns_r_yxrrset:
+ case 7:
return "YXRRSET";
- case ns_r_nxrrset:
+ case 8:
return "NXRRSET";
- case ns_r_notauth:
+ case 9:
return "NOTAUTH";
- case ns_r_notzone:
+ case 10:
return "NOTZONE";
- case ns_r_max:
+ case 11:
return "MAX";
- case ns_r_badsig:
+ case 16:
return "BADSIG";
- case ns_r_badkey:
+ case 17:
return "BADKEY";
- case ns_r_badtime:
+ case 18:
return "BADTIME";
-/* #endif __NAMESER >= 19991006 */
-#elif (defined(__BIND)) && (__BIND >= 19950621)
- case NOERROR:
- return "NOERROR";
- case FORMERR:
- return "FORMERR";
- case SERVFAIL:
- return "SERVFAIL";
- case NXDOMAIN:
- return "NXDOMAIN";
- case NOTIMP:
- return "NOTIMP";
- case REFUSED:
- return "REFUSED";
-#if defined(YXDOMAIN) && defined(NXRRSET)
- case YXDOMAIN:
- return "YXDOMAIN";
- case YXRRSET:
- return "YXRRSET";
- case NXRRSET:
- return "NXRRSET";
- case NOTAUTH:
- return "NOTAUTH";
- case NOTZONE:
- return "NOTZONE";
-#endif /* RFC2136 rcodes */
-#endif /* __BIND >= 19950621 */
default:
- snprintf(buf, sizeof(buf), "RCode%i", rcode);
+ ssnprintf(buf, sizeof(buf), "RCode%i", rcode);
return buf;
}
} /* const char *rcode_str (int rcode) */
#include "config.h"
-#include <arpa/nameser.h>
#include <stdint.h>
#if HAVE_PCAP_H
DPDK_HELPER_TRACE(phc->shm_name);
- snprintf(phc->eal_config.coremask, DATA_MAX_NAME_LEN, "%s", "0xf");
- snprintf(phc->eal_config.memory_channels, DATA_MAX_NAME_LEN, "%s", "1");
- snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, "%s",
- DPDK_DEFAULT_RTE_CONFIG);
+ ssnprintf(phc->eal_config.coremask, DATA_MAX_NAME_LEN, "%s", "0xf");
+ ssnprintf(phc->eal_config.memory_channels, DATA_MAX_NAME_LEN, "%s", "1");
+ ssnprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN, "%s",
+ DPDK_DEFAULT_RTE_CONFIG);
}
int dpdk_helper_eal_config_set(dpdk_helper_ctx_t *phc, dpdk_eal_config_t *ec) {
status = cf_util_get_string_buffer(child, prefix, sizeof(prefix));
if (status == 0) {
#if RTE_VERSION <= RTE_VERSION_NUM(18, 5, 0, 0)
- snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN,
- "/var/run/.%s_config", prefix);
+ ssnprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN,
+ "/var/run/.%s_config", prefix);
#else
- snprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN,
- "/var/run/dpdk/%s/config", prefix);
+ ssnprintf(phc->eal_config.file_prefix, DATA_MAX_NAME_LEN,
+ "/var/run/dpdk/%s/config", prefix);
#endif
DEBUG("dpdk_common: EAL:File prefix %s", phc->eal_config.file_prefix);
}
DPDK_HELPER_TRACE(name);
/* Allocate dpdk_helper_ctx_t and
- * initialize a POSIX SHared Memory (SHM) object.
- */
+ * initialize a POSIX SHared Memory (SHM) object.
+ */
int err = dpdk_shm_init(name, shm_size, (void **)&phc);
if (err != 0) {
return -errno;
/* non blocking check on helper logging pipe */
struct pollfd fds = {
- .fd = phc->pipes[0], .events = POLLIN,
+ .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,
/* Utils functions to format data sets in graphite format.
* Largely taken from write_graphite.c as it remains the same formatting */
+/* helper function for reverse_hostname */
+void reverse_string(char *r_host, int len) {
+ for (int i = 0, j = len - 1; i < j; i++, j--) {
+ char t = r_host[i];
+ r_host[i] = r_host[j];
+ r_host[j] = t;
+ }
+}
+
+void reverse_hostname(char *r_host, char const *orig_host) {
+ int len_host = strlen(orig_host);
+
+ /* put reversed hostname into working copy */
+ for (int i = 0; i < len_host; i++)
+ r_host[i] = orig_host[len_host - 1 - i];
+ r_host[len_host] = '\0';
+
+ /* reverse labels (except last) */
+ int p = 0;
+ for (int i = 0; i < len_host; i++)
+ if (r_host[i] == '.') {
+ reverse_string(&r_host[p], i - p);
+ p = i + 1;
+ }
+
+ /* reverse last label */
+ reverse_string(&r_host[p], len_host - p);
+}
+
static int gr_format_values(char *ret, size_t ret_len, int ds_num,
const data_set_t *ds, const value_list_t *vl,
gauge_t const *rates) {
if (postfix == NULL)
postfix = "";
- gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char, 1);
+ if (flags & GRAPHITE_REVERSE_HOST) {
+ char r_host[DATA_MAX_NAME_LEN];
+ reverse_hostname(r_host, vl->host);
+ gr_copy_escape_part(n_host, r_host, sizeof(n_host), escape_char, 1);
+ } else {
+ gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char, 1);
+ }
gr_copy_escape_part(n_plugin, vl->plugin, sizeof(n_plugin), escape_char, 1);
gr_copy_escape_part(n_plugin_instance, vl->plugin_instance,
sizeof(n_plugin_instance), escape_char, 1);
bool preserve_separator = (flags & GRAPHITE_PRESERVE_SEPARATOR);
- gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char,
- preserve_separator);
+ if (flags & GRAPHITE_REVERSE_HOST) {
+ char r_host[DATA_MAX_NAME_LEN];
+ reverse_hostname(r_host, vl->host);
+ gr_copy_escape_part(n_host, r_host, sizeof(n_host), escape_char,
+ preserve_separator);
+ } else {
+ gr_copy_escape_part(n_host, vl->host, sizeof(n_host), escape_char,
+ preserve_separator);
+ }
gr_copy_escape_part(n_plugin, vl->plugin, sizeof(n_plugin), escape_char,
preserve_separator);
gr_copy_escape_part(n_plugin_instance, vl->plugin_instance,
#define GRAPHITE_DROP_DUPE_FIELDS 0x08
#define GRAPHITE_PRESERVE_SEPARATOR 0x10
#define GRAPHITE_USE_TAGS 0x20
+#define GRAPHITE_REVERSE_HOST 0x40
int format_graphite(char *buffer, size_t buffer_size, const data_set_t *ds,
const value_list_t *vl, const char *prefix,
};
char want[1024];
- snprintf(want, sizeof(want), "%s 42 1480063672\r\n", cases[i].want_name);
+ ssnprintf(want, sizeof(want), "%s 42 1480063672\r\n", cases[i].want_name);
if (cases[i].plugin_instance != NULL)
sstrncpy(vl.plugin_instance, cases[i].plugin_instance,
}
JSON_ADD(g, "severity");
- JSON_ADD(g,
- (n->severity == NOTIF_FAILURE)
- ? "FAILURE"
- : (n->severity == NOTIF_WARNING)
- ? "WARNING"
- : (n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN");
+ JSON_ADD(g, (n->severity == NOTIF_FAILURE)
+ ? "FAILURE"
+ : (n->severity == NOTIF_WARNING)
+ ? "WARNING"
+ : (n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN");
JSON_ADD(g, "service");
JSON_ADD(g, "collectd");
static int expect_json_labels(char *json, label_t *labels, size_t labels_num) {
yajl_callbacks funcs = {
- .yajl_string = test_string, .yajl_map_key = test_map_key,
+ .yajl_string = test_string,
+ .yajl_map_key = test_map_key,
};
test_case_t c = {labels, labels_num, NULL};
}
case DS_TYPE_DERIVE: {
derive_t diff = v.derive - (derive_t)start_value;
- snprintf(integer, sizeof(integer), "%" PRIi64, diff);
+ ssnprintf(integer, sizeof(integer), "%" PRIi64, diff);
break;
}
case DS_TYPE_COUNTER: {
counter_t diff = counter_diff((counter_t)start_value, v.counter);
- snprintf(integer, sizeof(integer), "%llu", diff);
+ ssnprintf(integer, sizeof(integer), "%llu", diff);
break;
}
case DS_TYPE_ABSOLUTE: {
- snprintf(integer, sizeof(integer), "%" PRIu64, v.absolute);
+ ssnprintf(integer, sizeof(integer), "%" PRIu64, v.absolute);
break;
}
default: {
* "CUMULATIVE",
* "GAUGE"
* )
-*/
+ */
static int format_metric_kind(yajl_gen gen, int ds_type) {
switch (ds_type) {
case DS_TYPE_GAUGE:
* "DOUBLE",
* "INT64"
* )
-*/
+ */
static int format_value_type(yajl_gen gen, int ds_type) {
return json_string(gen, (ds_type == DS_TYPE_GAUGE) ? "DOUBLE" : "INT64");
}
#define GCM_PREFIX "custom.googleapis.com/collectd/"
if ((ds_index != 0) || strcmp("value", ds_name) != 0) {
- snprintf(buffer, buffer_size, GCM_PREFIX "%s/%s_%s", vl->plugin, vl->type,
- ds_name);
+ ssnprintf(buffer, buffer_size, GCM_PREFIX "%s/%s_%s", vl->plugin, vl->type,
+ ds_name);
} else {
- snprintf(buffer, buffer_size, GCM_PREFIX "%s/%s", vl->plugin, vl->type);
+ ssnprintf(buffer, buffer_size, GCM_PREFIX "%s/%s", vl->plugin, vl->type);
}
char const *whitelist = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}
char start_value_key[DATA_MAX_NAME_LEN];
- snprintf(start_value_key, sizeof(start_value_key),
- "stackdriver:start_value[%d]", ds_index);
+ ssnprintf(start_value_key, sizeof(start_value_key),
+ "stackdriver:start_value[%d]", ds_index);
int status =
uc_meta_data_get_signed_int(vl, start_value_key, ret_start_value);
DEF_TEST(sd_format_metric_descriptor) {
value_list_t vl = {
- .host = "example.com", .plugin = "unit-test", .type = "example",
+ .host = "example.com",
+ .plugin = "unit-test",
+ .type = "example",
};
char got[1024];
.ds_num = 1,
.ds =
&(data_source_t){
- .name = "value", .type = DS_TYPE_GAUGE, .min = NAN, .max = NAN,
+ .name = "value",
+ .type = DS_TYPE_GAUGE,
+ .min = NAN,
+ .max = NAN,
},
};
EXPECT_EQ_INT(
{
char url[1024];
- snprintf(url, sizeof(url), GCE_SCOPE_URL_FORMAT,
- (email != NULL) ? email : GCE_DEFAULT_SERVICE_ACCOUNT);
+ ssnprintf(url, sizeof(url), GCE_SCOPE_URL_FORMAT,
+ (email != NULL) ? email : GCE_DEFAULT_SERVICE_ACCOUNT);
return read_url(url);
} /* }}} char *gce_scope */
return 0;
}
- snprintf(url, sizeof(url), GCE_TOKEN_URL_FORMAT, email);
+ ssnprintf(url, sizeof(url), GCE_TOKEN_URL_FORMAT, email);
json = read_url(url);
if (json == NULL) {
pthread_mutex_unlock(&token_lock);
};
/*
-* Histogram represents the distribution of data, it has a list of "bins".
-* Each bin represents an interval and has a count (frequency) of
-* number of values fall within its interval.
-*
-* Histogram's range is determined by the number of bins and the bin width,
-* There are 1000 bins and all bins have the same width of default 1 millisecond.
-* 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 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, ...
-*
-* So, if the required bin width is 300, then new bin width will be 512 as it is
-* the next nearest power of 2.
-*/
+ * Histogram represents the distribution of data, it has a list of "bins".
+ * Each bin represents an interval and has a count (frequency) of
+ * number of values fall within its interval.
+ *
+ * Histogram's range is determined by the number of bins and the bin width,
+ * There are 1000 bins and all bins have the same width of default 1
+ * millisecond. 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 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, ...
+ *
+ * So, if the required bin width is 300, then new bin width will be 512 as it is
+ * the next nearest power of 2.
+ */
static void change_bin_width(latency_counter_t *lc, cdtime_t latency) /* {{{ */
{
/* This function is called because the new value is above histogram's range.
* Florian Forster <ff at octo.it>
**/
+#ifndef UTILS_LATENCY_LATENCY_H
+#define UTILS_LATENCY_LATENCY_H 1
+
#include "collectd.h"
#include "utils_time.h"
*/
double latency_counter_get_rate(const latency_counter_t *lc, cdtime_t lower,
cdtime_t upper, const cdtime_t now);
+
+#endif /* UTILS_LATENCY_LATENCY_H */
int latency_config_copy(latency_config_t *dst, const latency_config_t src) {
*dst = (latency_config_t){
- .percentile_num = src.percentile_num, .buckets_num = src.buckets_num,
+ .percentile_num = src.percentile_num,
+ .buckets_num = src.buckets_num,
};
dst->percentile = calloc(dst->percentile_num, sizeof(*dst->percentile));
} cases[] = {
{
// bucket 6 is zero
- DOUBLE_TO_CDTIME_T_STATIC(0.750), DOUBLE_TO_CDTIME_T_STATIC(0.875),
+ DOUBLE_TO_CDTIME_T_STATIC(0.750),
+ DOUBLE_TO_CDTIME_T_STATIC(0.875),
0.00,
},
{
// bucket 7 contains the t=1 update
- DOUBLE_TO_CDTIME_T_STATIC(0.875), DOUBLE_TO_CDTIME_T_STATIC(1.000),
+ DOUBLE_TO_CDTIME_T_STATIC(0.875),
+ DOUBLE_TO_CDTIME_T_STATIC(1.000),
1.00,
},
{
// range: bucket 7 - bucket 15; contains the t=1 and t=2 updates
- DOUBLE_TO_CDTIME_T_STATIC(0.875), DOUBLE_TO_CDTIME_T_STATIC(2.000),
+ DOUBLE_TO_CDTIME_T_STATIC(0.875),
+ DOUBLE_TO_CDTIME_T_STATIC(2.000),
2.00,
},
{
// lower bucket is only partially applied
DOUBLE_TO_CDTIME_T_STATIC(0.875 + (0.125 / 4)),
- DOUBLE_TO_CDTIME_T_STATIC(2.000), 1.75,
+ DOUBLE_TO_CDTIME_T_STATIC(2.000),
+ 1.75,
},
{
// upper bucket is only partially applied
DOUBLE_TO_CDTIME_T_STATIC(0.875),
- DOUBLE_TO_CDTIME_T_STATIC(2.000 - (0.125 / 4)), 1.75,
+ DOUBLE_TO_CDTIME_T_STATIC(2.000 - (0.125 / 4)),
+ 1.75,
},
{
// both buckets are only partially applied
DOUBLE_TO_CDTIME_T_STATIC(0.875 + (0.125 / 4)),
- DOUBLE_TO_CDTIME_T_STATIC(2.000 - (0.125 / 4)), 1.50,
+ DOUBLE_TO_CDTIME_T_STATIC(2.000 - (0.125 / 4)),
+ 1.50,
},
{
// lower bound is unspecified
- 0, DOUBLE_TO_CDTIME_T_STATIC(2.000), 2.00,
+ 0,
+ DOUBLE_TO_CDTIME_T_STATIC(2.000),
+ 2.00,
},
{
// upper bound is unspecified
- DOUBLE_TO_CDTIME_T_STATIC(125.000 - 0.125), 0, 1.00,
+ DOUBLE_TO_CDTIME_T_STATIC(125.000 - 0.125),
+ 0,
+ 1.00,
},
{
// overflow test: upper >> longest latency
- DOUBLE_TO_CDTIME_T_STATIC(1.000), DOUBLE_TO_CDTIME_T_STATIC(999999),
+ DOUBLE_TO_CDTIME_T_STATIC(1.000),
+ DOUBLE_TO_CDTIME_T_STATIC(999999),
124.00,
},
{
// overflow test: lower > longest latency
- DOUBLE_TO_CDTIME_T_STATIC(130), 0, 0.00,
+ DOUBLE_TO_CDTIME_T_STATIC(130),
+ 0,
+ 0.00,
},
{
// lower > upper => error
- DOUBLE_TO_CDTIME_T_STATIC(10), DOUBLE_TO_CDTIME_T_STATIC(9), NAN,
+ DOUBLE_TO_CDTIME_T_STATIC(10),
+ DOUBLE_TO_CDTIME_T_STATIC(9),
+ NAN,
},
{
// lower == upper => zero
- DOUBLE_TO_CDTIME_T_STATIC(9), DOUBLE_TO_CDTIME_T_STATIC(9), 0.00,
+ DOUBLE_TO_CDTIME_T_STATIC(9),
+ DOUBLE_TO_CDTIME_T_STATIC(9),
+ 0.00,
},
};
*
* Author:
* Niki W. Waibel <niki.waibel@gmx.net>
-**/
+ **/
#if HAVE_CONFIG_H
#include "config.h"
if (isdigit((int)s[-1])) {
/*
- * Note: this is a heuristic only - there is no reason
- * why these devices should live in /dev.
- * Perhaps this directory should be specifiable by option.
- * One might for example have /devlabel with links to /dev
- * for the devices that may be accessed in this way.
- * (This is useful, if the cdrom on /dev/hdc must not
- * be accessed.)
- */
+ * Note: this is a heuristic only - there is no reason
+ * why these devices should live in /dev.
+ * Perhaps this directory should be specifiable by option.
+ * One might for example have /devlabel with links to /dev
+ * for the devices that may be accessed in this way.
+ * (This is useful, if the cdrom on /dev/hdc must not
+ * be accessed.)
+ */
snprintf(device, sizeof(device), "%s/%s", DEVLABELDIR, ptname);
if (!get_label_uuid(device, &label, uuid)) {
uuidcache_addentry(sstrdup(device), label, uuid);
#elif HAVE_SEQ_GETMNTENT
#warn "This version of `getmntent' hat not yet been implemented!"
-/* #endif HAVE_SEQ_GETMNTENT */
+ /* #endif HAVE_SEQ_GETMNTENT */
#elif HAVE_GETMNTENT_R
static cu_mount_t *cu_mount_getmntent(void) {
/**
- * collectd - src/utils_mount.h
+ * collectd - src/utils/mount/mount.h
* Copyright (C) 2005,2006 Niki W. Waibel
*
* This program is free software; you can redistribute it and/
*
* Author:
* Niki W. Waibel <niki.waibel@gmx.net>
-**/
+ **/
/* See below for instructions how to use the public functions. */
/* create the claim set */
status =
- snprintf(claim, sizeof(claim), OAUTH_CLAIM_FORMAT, auth->iss, auth->scope,
- auth->aud, (unsigned long)CDTIME_T_TO_TIME_T(exp),
- (unsigned long)CDTIME_T_TO_TIME_T(iat));
+ ssnprintf(claim, sizeof(claim), OAUTH_CLAIM_FORMAT, auth->iss,
+ auth->scope, auth->aud, (unsigned long)CDTIME_T_TO_TIME_T(exp),
+ (unsigned long)CDTIME_T_TO_TIME_T(iat));
if (status < 1)
return -1;
else if ((size_t)status >= sizeof(claim))
int status;
/* Make the string to sign */
- payload_len = snprintf(payload, sizeof(payload), "%s.%s", header, claim);
+ payload_len = ssnprintf(payload, sizeof(payload), "%s.%s", header, claim);
if (payload_len < 1) {
return -1;
} else if (payload_len >= sizeof(payload)) {
if (status != 0)
return -1;
- status = snprintf(buffer, buffer_size, "%s.%s.%s", header, claim, signature);
+ status = ssnprintf(buffer, buffer_size, "%s.%s.%s", header, claim, signature);
if (status < 1)
return -1;
- else if (status >= buffer_size)
+ else if ((size_t)status >= buffer_size)
return ENOMEM;
return 0;
return -1;
}
- snprintf(post_data, sizeof(post_data), "grant_type=%s&assertion=%s",
- OAUTH_GRANT_TYPE, assertion);
+ ssnprintf(post_data, sizeof(post_data), "grant_type=%s&assertion=%s",
+ OAUTH_GRANT_TYPE, assertion);
curl = curl_easy_init();
if (curl == NULL) {
}
oauth_google_t ret = {
- .project_id = strdup(project_id), .oauth = oauth,
+ .project_id = strdup(project_id),
+ .oauth = oauth,
};
yajl_tree_free(root);
char const *home;
if ((home = getenv("HOME")) != NULL) {
char path[PATH_MAX];
- snprintf(path, sizeof(path),
- "%s/.config/gcloud/application_default_credentials.json", home);
+ ssnprintf(path, sizeof(path),
+ "%s/.config/gcloud/application_default_credentials.json", home);
oauth_google_t ret = oauth_create_google_file(path, scope);
if (ret.oauth != NULL) {
} cases[] = {
{
"{\"access_token\":\"MaeC6kaePhie1ree\",\"expires_in\":3600}",
- /* status = */ 0, "MaeC6kaePhie1ree", TIME_T_TO_CDTIME_T_STATIC(3600),
+ /* status = */ 0,
+ "MaeC6kaePhie1ree",
+ TIME_T_TO_CDTIME_T_STATIC(3600),
},
{
"{\"token_type\":\"Bearer\",\"expires_in\":1800,\"access_token\":"
"\"aeThiebee2gushuY\"}",
- /* status = */ 0, "aeThiebee2gushuY", TIME_T_TO_CDTIME_T_STATIC(1800),
+ /* status = */ 0,
+ "aeThiebee2gushuY",
+ TIME_T_TO_CDTIME_T_STATIC(1800),
},
{
"{\"ignored_key\":\"uaph5aewaeghi1Ge\",\"expires_in\":3600}",
- /* status = */ -1, NULL, 0,
+ /* status = */ -1,
+ NULL,
+ 0,
},
{
/* expires_in missing */
"{\"access_token\":\"shaephohbie9Ahch\"}",
- /* status = */ -1, NULL, 0,
+ /* status = */ -1,
+ NULL,
+ 0,
},
};
ovs_db_t *pdb = (ovs_db_t *)arg; /* pointer to OVS DB */
ovs_json_reader_t *jreader = NULL;
struct pollfd poll_fd = {
- .fd = pdb->sock, .events = POLLIN | POLLPRI, .revents = 0,
+ .fd = pdb->sock,
+ .events = POLLIN | POLLPRI,
+ .revents = 0,
};
/* create JSON reader instance */
/* generate id field */
OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "id");
uid = ovs_uid_generate();
- snprintf(uid_buff, sizeof(uid_buff), "%" PRIX64, uid);
+ ssnprintf(uid_buff, sizeof(uid_buff), "%" PRIX64, uid);
OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, uid_buff);
OVS_YAJL_CALL(yajl_gen_map_close, jgen);
OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, OVS_DB_DEFAULT_DB_NAME);
/* uid string <json-value> */
- snprintf(uid_str, sizeof(uid_str), "%" PRIX64, new_cb->uid);
+ ssnprintf(uid_str, sizeof(uid_str), "%" PRIX64, new_cb->uid);
OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, uid_str);
/* <monitor-requests> */
--- /dev/null
+/**
+ * collectd - src/utils/proc_pids/proc_pids.c
+ *
+ * Copyright(c) 2018-2019 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Starzyk, Mateusz <mateuszx.starzyk@intel.com>
+ * Wojciech Andralojc <wojciechx.andralojc@intel.com>
+ * Michał Aleksiński <michalx.aleksinski@intel.com>
+ **/
+
+#include "collectd.h"
+#include "utils/common/common.h"
+#include "utils/proc_pids/proc_pids.h"
+
+#define UTIL_NAME "utils_proc_pids"
+
+void pids_list_free(pids_list_t *list) {
+ assert(list);
+
+ sfree(list->pids);
+ sfree(list);
+}
+
+int proc_pids_is_name_valid(const char *name) {
+
+ if (name != NULL) {
+ unsigned len = strlen(name);
+ if (len > 0 && len <= MAX_PROC_NAME_LEN)
+ return 1;
+ else {
+ DEBUG(UTIL_NAME
+ ": Process name \'%s\' is too long. Max supported len is %d chars.",
+ name, MAX_PROC_NAME_LEN);
+ }
+ }
+
+ return 0;
+}
+
+int pids_list_add_pid(pids_list_t *list, const pid_t pid) {
+ assert(list);
+
+ if (list->allocated == list->size) {
+ size_t new_allocated = list->allocated + 1 + list->allocated / 10;
+ pid_t *new_pids = realloc(list->pids, sizeof(pid_t) * new_allocated);
+
+ if (NULL == new_pids) {
+ ERROR(UTIL_NAME ": Alloc error\n");
+ return -1;
+ }
+
+ list->pids = new_pids;
+ list->allocated = new_allocated;
+ }
+
+ list->pids[list->size] = pid;
+ list->size++;
+
+ return 0;
+}
+
+int pids_list_add_list(pids_list_t *dst, pids_list_t *src) {
+ assert(dst);
+ assert(src);
+
+ if (dst->allocated < dst->size + src->size) {
+ pid_t *new_pids =
+ realloc(dst->pids, sizeof(pid_t) * (dst->size + src->size));
+
+ if (NULL == new_pids) {
+ ERROR(UTIL_NAME ": Alloc error\n");
+ return -1;
+ }
+
+ dst->allocated = dst->size + src->size;
+ dst->pids = new_pids;
+ }
+
+ memcpy(dst->pids + dst->size, src->pids, src->size * sizeof(*(src->pids)));
+ dst->size += src->size;
+
+ return 0;
+}
+
+int pids_list_clear(pids_list_t *list) {
+ assert(list);
+
+ if (list->pids != NULL)
+ sfree(list->pids);
+
+ list->size = 0;
+ list->allocated = 0;
+
+ return 0;
+}
+
+int pids_list_contains_pid(pids_list_t *list, const pid_t pid) {
+ assert(list);
+
+ for (int i = 0; i < list->size; i++)
+ if (list->pids[i] == pid)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * NAME
+ * read_proc_name
+ *
+ * DESCRIPTION
+ * Reads process name from given pid directory.
+ * Strips new-line character (\n).
+ *
+ * PARAMETERS
+ * `procfs_path' Path to systems proc directory (e.g. /proc)
+ * `pid_entry' Dirent for PID directory
+ * `name' Output buffer for process name, recommended proc_comm.
+ * `out_size' Output buffer size, recommended sizeof(proc_comm)
+ *
+ * RETURN VALUE
+ * On success, the number of read bytes (includes stripped \n).
+ * -1 on file open error
+ */
+static int read_proc_name(const char *procfs_path,
+ const struct dirent *pid_entry, char *name,
+ const size_t out_size) {
+ assert(pid_entry);
+ assert(name);
+ assert(out_size);
+ memset(name, 0, out_size);
+
+ const char *comm_file_name = "comm";
+
+ char *path = ssnprintf_alloc("%s/%s/%s", procfs_path, pid_entry->d_name,
+ comm_file_name);
+ if (path == NULL)
+ return -1;
+ FILE *f = fopen(path, "r");
+ if (f == NULL) {
+ ERROR(UTIL_NAME ": Failed to open comm file, error: %d\n", errno);
+ sfree(path);
+ return -1;
+ }
+ size_t read_length = fread(name, sizeof(char), out_size, f);
+ name[out_size - 1] = '\0';
+ fclose(f);
+ sfree(path);
+ /* strip new line ending */
+ char *newline = strchr(name, '\n');
+ if (newline) {
+ *newline = '\0';
+ }
+
+ return read_length;
+}
+
+/*
+ * NAME
+ * get_pid_number
+ *
+ * DESCRIPTION
+ * Gets pid number for given /proc/pid directory entry or
+ * returns error if input directory does not hold PID information.
+ *
+ * PARAMETERS
+ * `entry' Dirent for PID directory
+ * `pid' PID number to be filled
+ *
+ * RETURN VALUE
+ * 0 on success. -1 on error.
+ */
+static int get_pid_number(struct dirent *entry, pid_t *pid) {
+ char *tmp_end; /* used for strtoul error check*/
+
+ if (pid == NULL || entry == NULL)
+ return -1;
+
+ if (entry->d_type != DT_DIR)
+ return -1;
+
+ /* trying to get pid number from directory name*/
+ *pid = strtoul(entry->d_name, &tmp_end, 10);
+ if (*tmp_end != '\0') {
+ return -1; /* conversion failed, not proc-pid */
+ }
+ /* all checks passed, marking as success */
+ return 0;
+}
+
+int proc_pids_init(const char **procs_names_array,
+ const size_t procs_names_array_size,
+ proc_pids_t **proc_pids[]) {
+
+ proc_pids_t **proc_pids_array;
+ assert(proc_pids);
+ assert(NULL == *proc_pids);
+
+ /* Copy procs names to output array. Initialize pids list with NULL value. */
+ proc_pids_array = calloc(procs_names_array_size, sizeof(*proc_pids_array));
+
+ if (NULL == proc_pids_array)
+ return -1;
+
+ for (size_t i = 0; i < procs_names_array_size; ++i) {
+ proc_pids_array[i] = calloc(1, sizeof(**proc_pids_array));
+ if (NULL == proc_pids_array[i])
+ goto proc_pids_init_error;
+
+ sstrncpy(proc_pids_array[i]->process_name, procs_names_array[i],
+ STATIC_ARRAY_SIZE(proc_pids_array[i]->process_name));
+ proc_pids_array[i]->prev = NULL;
+ proc_pids_array[i]->curr = NULL;
+ }
+
+ *proc_pids = proc_pids_array;
+
+ return 0;
+proc_pids_init_error:
+ if (NULL != proc_pids_array) {
+ for (size_t i = 0; i < procs_names_array_size; ++i) {
+ free(proc_pids_array[i]);
+ }
+ free(proc_pids_array);
+ }
+ return -1;
+}
+
+static void swap_proc_pids(proc_pids_t **proc_pids, size_t proc_pids_num) {
+ for (size_t i = 0; i < proc_pids_num; i++) {
+ pids_list_t *swap = proc_pids[i]->prev;
+ proc_pids[i]->prev = proc_pids[i]->curr;
+ proc_pids[i]->curr = swap;
+ }
+}
+
+int proc_pids_update(const char *procfs_path, proc_pids_t **proc_pids,
+ size_t proc_pids_num) {
+ assert(procfs_path);
+ assert(proc_pids);
+
+ DIR *proc_dir = opendir(procfs_path);
+ if (proc_dir == NULL) {
+ ERROR(UTIL_NAME ": Could not open %s directory, error: %d", procfs_path,
+ errno);
+ return -1;
+ }
+
+ swap_proc_pids(proc_pids, proc_pids_num);
+
+ for (size_t i = 0; i < proc_pids_num; i++) {
+ if (NULL == proc_pids[i]->curr)
+ proc_pids[i]->curr = calloc(1, sizeof(*(proc_pids[i]->curr)));
+
+ if (NULL == proc_pids[i]->curr) {
+ ERROR(UTIL_NAME ": Alloc error\n");
+ goto update_error;
+ }
+
+ proc_pids[i]->curr->size = 0;
+ }
+
+ /* Go through procfs and find PIDS and their comms */
+ struct dirent *entry;
+ while ((entry = readdir(proc_dir)) != NULL) {
+ pid_t pid;
+ int pid_conversion = get_pid_number(entry, &pid);
+ if (pid_conversion < 0)
+ continue;
+
+ proc_comm_t comm;
+ int read_result =
+ read_proc_name(procfs_path, entry, comm, sizeof(proc_comm_t));
+ if (read_result <= 0)
+ continue;
+
+ /* Try to find comm in input procs array */
+ for (size_t i = 0; i < proc_pids_num; ++i) {
+ if (0 ==
+ strncmp(comm, proc_pids[i]->process_name, STATIC_ARRAY_SIZE(comm)))
+ pids_list_add_pid(proc_pids[i]->curr, pid);
+ }
+ }
+
+ int close_result = closedir(proc_dir);
+ if (0 != close_result) {
+ ERROR(UTIL_NAME ": failed to close /proc directory, error: %d", errno);
+ goto update_error;
+ }
+ return 0;
+
+update_error:
+ swap_proc_pids(proc_pids, proc_pids_num);
+ return -1;
+}
+
+int pids_list_diff(proc_pids_t *proc, pids_list_t *added,
+ pids_list_t *removed) {
+ assert(proc);
+ assert(added);
+ assert(removed);
+
+ added->size = 0;
+ removed->size = 0;
+
+ if (NULL == proc->prev || 0 == proc->prev->size) {
+ /* append all PIDs from curr to added*/
+ return pids_list_add_list(added, proc->curr);
+ } else if (NULL == proc->curr || 0 == proc->curr->size) {
+ /* append all PIDs from prev to removed*/
+ return pids_list_add_list(removed, proc->prev);
+ }
+
+ for (int i = 0; i < proc->prev->size; i++)
+ if (0 == pids_list_contains_pid(proc->curr, proc->prev->pids[i])) {
+ int add_result = pids_list_add_pid(removed, proc->prev->pids[i]);
+ if (add_result < 0)
+ return add_result;
+ }
+
+ for (int i = 0; i < proc->curr->size; i++)
+ if (0 == pids_list_contains_pid(proc->prev, proc->curr->pids[i])) {
+ int add_result = pids_list_add_pid(added, proc->curr->pids[i]);
+ if (add_result < 0)
+ return add_result;
+ }
+
+ return 0;
+}
+
+int proc_pids_free(proc_pids_t *proc_pids[], size_t proc_pids_num) {
+ for (size_t i = 0; i < proc_pids_num; i++) {
+ if (NULL != proc_pids[i]->curr)
+ pids_list_free(proc_pids[i]->curr);
+ if (NULL != proc_pids[i]->prev)
+ pids_list_free(proc_pids[i]->prev);
+ sfree(proc_pids[i]);
+ }
+ sfree(proc_pids);
+
+ return 0;
+}
--- /dev/null
+/**
+ * collectd - src/utils/proc_pids/proc_pids.h
+ *
+ * Copyright(c) 2018-2019 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Starzyk, Mateusz <mateuszx.starzyk@intel.com>
+ * Wojciech Andralojc <wojciechx.andralojc@intel.com>
+ * Michał Aleksiński <michalx.aleksinski@intel.com>
+ **/
+
+#ifndef UTILS_PROC_PIDS_PROC_PIDS_H
+#define UTILS_PROC_PIDS_PROC_PIDS_H 1
+
+#include <dirent.h>
+#include <sys/types.h>
+
+/*
+ * Process name inside comm file is limited to 16 chars.
+ * More info here: http://man7.org/linux/man-pages/man5/proc.5.html
+ */
+#define MAX_PROC_NAME_LEN 16
+
+/* Helper typedef for process name array
+ * Extra 1 char is added for string null termination.
+ */
+typedef char proc_comm_t[MAX_PROC_NAME_LEN + 1];
+
+/* List of pids. */
+typedef struct pids_list_s {
+ pid_t *pids;
+ size_t size;
+ size_t allocated;
+} pids_list_t;
+
+/* Holds process name and list of pids assigned to that name */
+typedef struct proc_pids_s {
+ proc_comm_t process_name;
+ pids_list_t *prev;
+ pids_list_t *curr;
+} proc_pids_t;
+
+/*
+ * NAME
+ * pids_list_free
+ *
+ * DESCRIPTION
+ * Free all elements of given pids list
+ *
+ * PARAMETERS
+ * `list' Head of target pids_list.
+ */
+void pids_list_free(pids_list_t *list);
+
+/*
+ * NAME
+ * pids_list_add_pid
+ *
+ * DESCRIPTION
+ * Adds pid at the end of the pids array.
+ * Reallocates memory for new pid element, it is up to user to free it.
+ *
+ * PARAMETERS
+ * `list' Target pids_list.
+ * `pid' Pid to be added.
+ *
+ * RETURN VALUE
+ * On success, returns 0.
+ * -1 on memory allocation error.
+ */
+int pids_list_add_pid(pids_list_t *list, const pid_t pid);
+
+/*
+ * NAME
+ * pids_list_clear
+ *
+ * DESCRIPTION
+ * Remove all pids from the list
+ *
+ * PARAMETERS
+ * `list' Target pids_list.
+ *
+ * RETURN VALUE
+ * On success, return 0
+ */
+int pids_list_clear(pids_list_t *list);
+
+/*
+ * NAME
+ * pids_list_add_list
+ *
+ * DESCRIPTION
+ * Adds pids list at the end of the pids list.
+ * Allocates memory for new pid elements, it is up to user to free it.
+ *
+ * PARAMETERS
+ * `dst' Target PIDs list.
+ * `src' Source PIDs list.
+ *
+ * RETURN VALUE
+ * On success, returns 0.
+ * -1 on memory allocation error.
+ */
+int pids_list_add_list(pids_list_t *dst, pids_list_t *src);
+
+/*
+ * NAME
+ * pids_list_contains_pid
+ *
+ * DESCRIPTION
+ * Tests if pids list contains specific pid.
+ *
+ * PARAMETERS
+ * `list' pids_list to check.
+ * `pid' Pid to be searched for.
+ *
+ * RETURN VALUE
+ * If PID found in list, returns 1,
+ * Otherwise returns 0.
+ */
+int pids_list_contains_pid(pids_list_t *list, const pid_t pid);
+
+/*
+ * NAME
+ * pids_list_diff
+ *
+ * DESCRIPTION
+ * Searches for differences in two given lists
+ *
+ * PARAMETERS
+ * `proc' List of pids
+ * `added' New pids which appeared
+ * `removed' Result array storing pids which disappeared
+ * RETURN VALUE
+ * 0 on success. Negative number on error.
+ */
+int pids_list_diff(proc_pids_t *proc, pids_list_t *added, pids_list_t *removed);
+
+/*
+ * NAME
+ * proc_pids_is_name_valid
+ *
+ * DESCRIPTION
+ * Checks if given string is valid process name.
+ *
+ * PARAMETERS
+ * `name' null-terminated char array
+ *
+ * RETURN VALUE
+ * If given name is a valid process name, returns 1,
+ * Otherwise returns 0.
+ */
+int proc_pids_is_name_valid(const char *name);
+
+/*
+ * NAME
+ * proc_pids_init
+ *
+ * DESCRIPTION
+ * Helper function to properly initialize array of proc_pids.
+ * Allocates memory for proc_pids structs.
+ *
+ * PARAMETERS
+ * `procs_names_array' Array of null-terminated strings with
+ * process' names to be copied to new array
+ * `procs_names_array_size' procs_names_array element count
+ * `proc_pids' Address of pointer, under which new
+ * array of proc_pids will be allocated.
+ * Must be NULL.
+ * RETURN VALUE
+ * 0 on success. Negative number on error:
+ * -1: allocation error
+ */
+int proc_pids_init(const char **procs_names_array,
+ const size_t procs_names_array_size,
+ proc_pids_t **proc_pids[]);
+
+/*
+ * NAME
+ * proc_pids_update
+ *
+ * DESCRIPTION
+ * Updates PIDs matching processes's names.
+ * Searches all PID directories in /proc fs and updates current pids_list.
+ *
+ * PARAMETERS
+ * `procfs_path' Path to systems proc directory (e.g. /proc)
+ * `proc_pids' Array of proc_pids pointers to be updated.
+ * `proc_pids_num' proc_pids element count
+ *
+ * RETURN VALUE
+ * 0 on success. -1 on error.
+ */
+int proc_pids_update(const char *procfs_path, proc_pids_t *proc_pids[],
+ size_t proc_pids_num);
+
+/*
+ * NAME
+ * proc_pids_free
+ *
+ * DESCRIPTION
+ * Releses memory allocatd for proc_pids
+ *
+ * PARAMETERS
+ * `proc_pids' Array of proc_pids
+ * `proc_pids_num' proc_pids element count
+ *
+ * RETURN VALUE
+ * 0 on success. -1 on error.
+ */
+int proc_pids_free(proc_pids_t *proc_pids[], size_t proc_pids_num);
+
+#endif /* UTILS_PROC_PIDS_PROC_PIDS_H */
--- /dev/null
+// clang-format off
+/*
+ * Explicit order is required or _FILE_OFFSET_BITS will have definition mismatches on Solaris
+ * See Github Issue #3193 for details
+ */
+#include "utils/proc_pids/proc_pids.c" /* sic */
+#include "testing.h"
+// clang-format on
+#include <sys/stat.h>
+
+/***************************************************************************
+ * helper functions
+ */
+
+typedef struct stub_proc_pid {
+ proc_comm_t comm;
+ pid_t pid;
+} stub_proc_pid_t;
+
+static const char *proc_fs = "/tmp/procfs_stub";
+
+/*
+ * NAME
+ * stub_procfs_setup
+ *
+ * DESCRIPTION
+ * Prepares testing environment by creating temporary
+ * PID/comm file structure.
+ *
+ * PARAMETERS
+ * `proc_pids_array' Array of stub_proc_pid_t structs. Represents
+ * which PIDs should hold given process name.
+ * `proc_pids_array_length' Element count of input array.
+ *
+ * RETURN VALUE
+ * 0 on success.
+ * -1 on base dir creation error.
+ * -2 on comm file creation error.
+ * -3 on comm file write error.
+ */
+int stub_procfs_setup(const stub_proc_pid_t *proc_pids_array,
+ const size_t proc_pids_array_length) {
+ if (mkdir(proc_fs, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0)
+ return -1;
+ char path[256];
+
+ for (size_t i = 0; i < proc_pids_array_length; ++i) {
+ memset(path, 0, sizeof(path));
+ snprintf(path, STATIC_ARRAY_SIZE(path), "%s/%d", proc_fs,
+ proc_pids_array[i].pid);
+ mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ strncat(path, "/comm", STATIC_ARRAY_SIZE(path) - strlen(path) - 1);
+
+ FILE *fp = fopen(path, "w");
+ if (!fp)
+ return -2;
+
+ size_t slen = strlen(proc_pids_array[i].comm);
+ size_t wlen = fwrite(proc_pids_array[i].comm, sizeof(char), slen, fp);
+ fclose(fp);
+
+ if (slen != wlen)
+ return -3;
+ }
+ return 0;
+}
+
+/*
+ * NAME
+ * stub_procfs_teardown
+ *
+ * DESCRIPTION
+ * Clears testing environment: removes stub proc files.
+ * NOTE - This function could be implemented by usage of nftw, but this
+ * would require #define _XOPEN_SOURCE 500, which
+ * messes up intel_rdt includes.
+ *
+ * RETURN VALUE
+ * system command result
+ */
+int stub_procfs_teardown() {
+ char cmd[256];
+ sstrncpy(cmd, "rm -rf ", STATIC_ARRAY_SIZE(cmd));
+ strncat(cmd, proc_fs, STATIC_ARRAY_SIZE(cmd) - strlen(cmd) - 1);
+ return system(cmd);
+}
+
+/* Max PID value. More info:
+ * http://web.archive.org/web/20111209081734/http://research.cs.wisc.edu/condor/condorg/linux_scalability.html
+ */
+#define MAX_PID 4194304
+#define MAX_PID_STR "4194304"
+
+/***************************************************************************
+ * tests
+ */
+DEF_TEST(proc_pids_init__on_nullptr) {
+ /* setup */
+ const char *procs_names_array[] = {"proc1", "proc2", "proc3"};
+ const size_t procs_names_array_size = STATIC_ARRAY_SIZE(procs_names_array);
+ proc_pids_t **proc_pids_array = NULL;
+
+ /* check */
+ int result = proc_pids_init(procs_names_array, procs_names_array_size,
+ &proc_pids_array);
+ EXPECT_EQ_INT(0, result);
+ for (size_t i = 0; i < procs_names_array_size; ++i)
+ EXPECT_EQ_STR(procs_names_array[i], proc_pids_array[i]->process_name);
+
+ /* cleanup */
+ proc_pids_free(proc_pids_array, procs_names_array_size);
+ return 0;
+}
+
+DEF_TEST(pid_list_add_pid__empty_list) {
+ /* setup */
+ pids_list_t *proc_pids_instance = calloc(1, sizeof(*proc_pids_instance));
+ pid_t pid = 1234;
+
+ /* check */
+ pids_list_add_pid(proc_pids_instance, pid);
+ EXPECT_EQ_INT(pid, proc_pids_instance->pids[0]);
+
+ /* cleanup */
+ pids_list_free(proc_pids_instance);
+ return 0;
+}
+
+DEF_TEST(pid_list_add_pid__non_empty_list) {
+ /* setup */
+ pids_list_t *proc_pids_instance = calloc(1, sizeof(*proc_pids_instance));
+ pid_t pids[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
+
+ /* check */
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i)
+ pids_list_add_pid(proc_pids_instance, pids[i]);
+
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids); ++i) {
+ EXPECT_EQ_INT(pids[i], proc_pids_instance->pids[i]);
+ }
+
+ /* cleanup */
+ pids_list_free(proc_pids_instance);
+ return 0;
+}
+
+DEF_TEST(pids_list_add_pids_list__non_empty_lists) {
+ /* setup */
+ pid_t pids_array_1[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
+ pid_t pids_array_2[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
+ pids_list_t *pids_list_1 = calloc(1, sizeof(*pids_list_1));
+ pids_list_t *pids_list_2 = calloc(1, sizeof(*pids_list_2));
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) {
+ pids_list_add_pid(pids_list_1, pids_array_1[i]);
+ pids_list_add_pid(pids_list_2, pids_array_2[i]);
+ }
+
+ /* check */
+ int result = pids_list_add_list(pids_list_1, pids_list_2);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_2) +
+ STATIC_ARRAY_SIZE(pids_array_1),
+ pids_list_1->size);
+
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_1); ++i) {
+ EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_1[i]));
+ EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array_2[i]));
+ }
+
+ /* setup */
+ pids_list_free(pids_list_1);
+ pids_list_free(pids_list_2);
+ return 0;
+}
+
+DEF_TEST(pids_list_add_pids_list__add_to_empty) {
+ /* setup */
+ pid_t pids_array[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
+ pids_list_t *pids_list_1 = calloc(1, sizeof(*pids_list_1));
+ pids_list_t *pids_list_2 = calloc(1, sizeof(*pids_list_2));
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i)
+ pids_list_add_pid(pids_list_2, pids_array[i]);
+
+ /* check */
+ int result = pids_list_add_list(pids_list_1, pids_list_2);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array), pids_list_1->size);
+
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array); ++i)
+ EXPECT_EQ_INT(1, pids_list_contains_pid(pids_list_1, pids_array[i]));
+
+ /* setup */
+ pids_list_free(pids_list_1);
+ pids_list_free(pids_list_2);
+ return 0;
+}
+
+DEF_TEST(get_pid_number__valid_dir) {
+ /* setup */
+ struct dirent d;
+ sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
+ d.d_type = DT_DIR;
+ pid_t pid = 0;
+
+ /* check */
+ int pid_conversion = get_pid_number(&d, &pid);
+
+ EXPECT_EQ_INT(0, pid_conversion);
+ EXPECT_EQ_INT(MAX_PID, pid);
+
+ /* cleanup */
+ return 0;
+}
+
+DEF_TEST(get_pid_number__invalid_dir_name) {
+ /* setup */
+ struct dirent d;
+ sstrncpy(d.d_name, "invalid", STATIC_ARRAY_SIZE(d.d_name));
+ d.d_type = DT_DIR;
+ pid_t pid = 0;
+
+ /* check */
+ int pid_conversion = get_pid_number(&d, &pid);
+
+ EXPECT_EQ_INT(-1, pid_conversion);
+ EXPECT_EQ_INT(0, pid);
+
+ /* cleanup */
+ return 0;
+}
+
+DEF_TEST(read_proc_name__valid_name) {
+ /* setup */
+ stub_proc_pid_t pp_stubs[] = {{"proc1", MAX_PID}};
+ stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
+ struct dirent d;
+ sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
+ d.d_type = DT_DIR;
+
+ /* check */
+ proc_comm_t comm;
+ int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm));
+
+ EXPECT_EQ_INT(strlen(pp_stubs[0].comm), read_result);
+ EXPECT_EQ_STR(pp_stubs[0].comm, comm);
+
+ /* cleanup */
+ stub_procfs_teardown();
+ return 0;
+}
+
+DEF_TEST(read_proc_name__invalid_name) {
+ /* setup */
+ struct dirent d;
+ sstrncpy(d.d_name, MAX_PID_STR, STATIC_ARRAY_SIZE(d.d_name));
+ d.d_type = DT_DIR;
+
+ /* check */
+ proc_comm_t comm;
+ int read_result = read_proc_name(proc_fs, &d, comm, STATIC_ARRAY_SIZE(comm));
+
+ EXPECT_EQ_INT(-1, read_result);
+
+ /* cleanup */
+ return 0;
+}
+
+DEF_TEST(proc_pids_update__one_proc_many_pid) {
+ /* setup */
+ const char *proc_names[] = {"proc1"};
+ stub_proc_pid_t pp_stubs[] = {{"proc1", 1007},
+ {"proc1", 1008},
+ {"proc1", 1009},
+ {"proc2", 1010},
+ {"proc3", 1011}};
+ proc_pids_t **proc_pids = NULL;
+ int result;
+ stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
+
+ result =
+ proc_pids_init(proc_names, STATIC_ARRAY_SIZE(proc_names), &proc_pids);
+ EXPECT_EQ_INT(0, result);
+
+ /* check */
+ result = proc_pids_update(proc_fs, proc_pids, STATIC_ARRAY_SIZE(proc_names));
+ EXPECT_EQ_INT(0, result);
+
+ /* proc name check */
+ EXPECT_EQ_STR(proc_names[0], proc_pids[0]->process_name);
+
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pp_stubs); ++i) {
+ if (0 == strcmp(pp_stubs[i].comm, proc_names[0]))
+ /* check if proc struct has correct pids */
+ EXPECT_EQ_INT(pids_list_contains_pid(proc_pids[0]->curr, pp_stubs[i].pid),
+ 1);
+ else
+ /* check if proc struct has no incorrect pids */
+ EXPECT_EQ_INT(pids_list_contains_pid(proc_pids[0]->curr, pp_stubs[i].pid),
+ 0);
+ }
+
+ /* cleanup */
+ proc_pids_free(proc_pids, STATIC_ARRAY_SIZE(proc_names));
+ stub_procfs_teardown();
+ return 0;
+}
+
+DEF_TEST(proc_pids_update__many_proc_many_pid) {
+ /* setup */
+ const char *proc_names[] = {"proc1", "proc2", "proc3"};
+ stub_proc_pid_t pp_stubs[] = {
+ {"proc1", 1007}, {"proc1", 1008}, {"proc1", 1009}, {"proc2", 2007},
+ {"proc2", 2008}, {"proc2", 2009}, {"proc3", 3007}, {"proc3", 3008},
+ {"proc3", 3009}, {"proc4", 4007}, {"proc4", 4008}, {"proc4", 4009},
+ {"proc5", 5007}, {"proc5", 5008}, {"proc5", 5009}};
+ proc_pids_t **proc_pids = NULL;
+ int result;
+ stub_procfs_setup(pp_stubs, STATIC_ARRAY_SIZE(pp_stubs));
+
+ result =
+ proc_pids_init(proc_names, STATIC_ARRAY_SIZE(proc_names), &proc_pids);
+ EXPECT_EQ_INT(0, result);
+
+ /* check */
+ result = proc_pids_update(proc_fs, proc_pids, STATIC_ARRAY_SIZE(proc_names));
+ EXPECT_EQ_INT(0, result);
+
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(proc_names); ++i) {
+
+ /* proc name check */
+ EXPECT_EQ_STR(proc_names[i], proc_pids[i]->process_name);
+
+ for (size_t j = 0; j < STATIC_ARRAY_SIZE(pp_stubs); ++j) {
+ if (0 == strcmp(pp_stubs[j].comm, proc_names[i]))
+ /* check if proc struct has correct pids */
+ EXPECT_EQ_INT(
+ pids_list_contains_pid(proc_pids[i]->curr, pp_stubs[j].pid), 1);
+ else
+ /* check if proc struct has no incorrect pids */
+ EXPECT_EQ_INT(
+ pids_list_contains_pid(proc_pids[i]->curr, pp_stubs[j].pid), 0);
+ }
+ }
+
+ /* cleanup */
+ proc_pids_free(proc_pids, STATIC_ARRAY_SIZE(proc_names));
+ stub_procfs_teardown();
+ return 0;
+}
+
+DEF_TEST(pids_list_diff__all_changed) {
+ /* setup */
+ pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
+ pid_t pids_array_after[] = {2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007};
+ proc_pids_t proc_pids;
+ pids_list_t curr;
+ pids_list_t prev;
+
+ prev.pids = pids_array_before;
+ prev.size = STATIC_ARRAY_SIZE(pids_array_before);
+ prev.allocated = prev.size;
+ curr.pids = pids_array_after;
+ curr.size = STATIC_ARRAY_SIZE(pids_array_after);
+ curr.allocated = curr.size;
+ proc_pids.curr = &curr;
+ proc_pids.prev = &prev;
+
+ pids_list_t *new_pids = calloc(1, sizeof(*new_pids));
+ pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids));
+
+ /* check */
+ int result = pids_list_diff(&proc_pids, new_pids, lost_pids);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_before), lost_pids->size);
+ EXPECT_EQ_INT(STATIC_ARRAY_SIZE(pids_array_after), new_pids->size);
+
+ for (size_t i = 0; i < STATIC_ARRAY_SIZE(pids_array_before); ++i) {
+ EXPECT_EQ_INT(1, pids_list_contains_pid(new_pids, pids_array_after[i]));
+ EXPECT_EQ_INT(1, pids_list_contains_pid(lost_pids, pids_array_before[i]));
+ }
+
+ /* cleanup */
+ pids_list_free(new_pids);
+ pids_list_free(lost_pids);
+
+ return 0;
+}
+
+DEF_TEST(pids_list_diff__nothing_changed) {
+ /* setup */
+ pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
+ proc_pids_t proc_pids;
+ pids_list_t curr;
+ pids_list_t prev;
+
+ prev.pids = pids_array_before;
+ prev.size = STATIC_ARRAY_SIZE(pids_array_before);
+ prev.allocated = prev.size;
+ curr.pids = pids_array_before;
+ curr.size = STATIC_ARRAY_SIZE(pids_array_before);
+ curr.allocated = curr.size;
+ proc_pids.curr = &curr;
+ proc_pids.prev = &prev;
+
+ pids_list_t *new_pids = calloc(1, sizeof(*new_pids));
+ pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids));
+
+ /* check */
+ int result = pids_list_diff(&proc_pids, new_pids, lost_pids);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_INT(0, lost_pids->size);
+ EXPECT_EQ_INT(0, new_pids->size);
+
+ /* cleanup */
+ pids_list_free(lost_pids);
+ pids_list_free(new_pids);
+
+ return 0;
+}
+
+DEF_TEST(pids_list_diff__one_added) {
+ /* setup */
+ pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
+ pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004,
+ 1005, 1006, 1007, 1008};
+ proc_pids_t proc_pids;
+ pids_list_t curr;
+ pids_list_t prev;
+
+ prev.pids = pids_array_before;
+ prev.size = STATIC_ARRAY_SIZE(pids_array_before);
+ prev.allocated = prev.size;
+ curr.pids = pids_array_after;
+ curr.size = STATIC_ARRAY_SIZE(pids_array_after);
+ curr.allocated = curr.size;
+ proc_pids.curr = &curr;
+ proc_pids.prev = &prev;
+
+ pids_list_t *new_pids = calloc(1, sizeof(*new_pids));
+ pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids));
+
+ /* check */
+ int result = pids_list_diff(&proc_pids, new_pids, lost_pids);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_INT(0, lost_pids->size);
+ EXPECT_EQ_INT(1, new_pids->size);
+ EXPECT_EQ_INT(1008, new_pids->pids[0]);
+
+ /* cleanup */
+ pids_list_free(lost_pids);
+ pids_list_free(new_pids);
+
+ return 0;
+}
+
+DEF_TEST(pids_list_diff__one_removed) {
+ /* setup */
+ pid_t pids_array_before[] = {1000, 1001, 1002, 1003, 1004,
+ 1005, 1006, 1007, 1008};
+ pid_t pids_array_after[] = {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007};
+
+ proc_pids_t proc_pids;
+ pids_list_t curr;
+ pids_list_t prev;
+
+ prev.pids = pids_array_before;
+ prev.size = STATIC_ARRAY_SIZE(pids_array_before);
+ prev.allocated = prev.size;
+ curr.pids = pids_array_after;
+ curr.size = STATIC_ARRAY_SIZE(pids_array_after);
+ curr.allocated = curr.size;
+ proc_pids.curr = &curr;
+ proc_pids.prev = &prev;
+
+ pids_list_t *new_pids = calloc(1, sizeof(*new_pids));
+ pids_list_t *lost_pids = calloc(1, sizeof(*lost_pids));
+
+ /* check */
+ int result = pids_list_diff(&proc_pids, new_pids, lost_pids);
+ EXPECT_EQ_INT(0, result);
+ EXPECT_EQ_INT(0, new_pids->size);
+ EXPECT_EQ_INT(1, lost_pids->size);
+ EXPECT_EQ_INT(1008, lost_pids->pids[0]);
+
+ /* cleanup */
+ pids_list_free(lost_pids);
+ pids_list_free(new_pids);
+
+ return 0;
+}
+
+int main(void) {
+ stub_procfs_teardown();
+ RUN_TEST(proc_pids_init__on_nullptr);
+ RUN_TEST(pid_list_add_pid__empty_list);
+ RUN_TEST(pid_list_add_pid__non_empty_list);
+ RUN_TEST(pids_list_add_pids_list__non_empty_lists);
+ RUN_TEST(pids_list_add_pids_list__add_to_empty);
+ RUN_TEST(get_pid_number__valid_dir);
+ RUN_TEST(get_pid_number__invalid_dir_name);
+ RUN_TEST(read_proc_name__valid_name);
+ RUN_TEST(read_proc_name__invalid_name);
+ RUN_TEST(proc_pids_update__one_proc_many_pid);
+ RUN_TEST(proc_pids_update__many_proc_many_pid);
+ RUN_TEST(pids_list_diff__all_changed);
+ RUN_TEST(pids_list_diff__nothing_changed);
+ RUN_TEST(pids_list_diff__one_added);
+ RUN_TEST(pids_list_diff__one_removed);
+ stub_procfs_teardown();
+ END_TEST;
+}
if (rra_num >= rra_max)
break;
- status = snprintf(buffer, sizeof(buffer), "RRA:%s:%.10f:%u:%u",
- rra_types[j], cfg->xff, cdp_len, cdp_num);
+ status = ssnprintf(buffer, sizeof(buffer), "RRA:%s:%.10f:%u:%u",
+ rra_types[j], cfg->xff, cdp_len, cdp_num);
if ((status < 0) || ((size_t)status >= sizeof(buffer))) {
P_ERROR("rra_get: Buffer would have been truncated.");
if (isnan(d->min)) {
sstrncpy(min, "U", sizeof(min));
} else
- snprintf(min, sizeof(min), "%f", d->min);
+ ssnprintf(min, sizeof(min), "%f", d->min);
if (isnan(d->max)) {
sstrncpy(max, "U", sizeof(max));
} else
- snprintf(max, sizeof(max), "%f", d->max);
+ ssnprintf(max, sizeof(max), "%f", d->max);
- status = snprintf(
+ status = ssnprintf(
buffer, sizeof(buffer), "DS:%s:%s:%i:%s:%s", d->name, type,
(cfg->heartbeat > 0) ? cfg->heartbeat
: (int)CDTIME_T_TO_TIME_T(2 * vl->interval),
return status;
} /* }}} int srrd_create */
-/* #endif HAVE_THREADSAFE_LIBRRD */
+ /* #endif HAVE_THREADSAFE_LIBRRD */
#else /* !HAVE_THREADSAFE_LIBRRD */
static int srrd_create(const char *filename, /* {{{ */
if (last_up == 0)
last_up = time(NULL) - 10;
- snprintf(pdp_step_str, sizeof(pdp_step_str), "%lu", pdp_step);
- snprintf(last_up_str, sizeof(last_up_str), "%lu", (unsigned long)last_up);
+ ssnprintf(pdp_step_str, sizeof(pdp_step_str), "%lu", pdp_step);
+ ssnprintf(last_up_str, sizeof(last_up_str), "%lu", (unsigned long)last_up);
new_argv[0] = "create";
new_argv[1] = (void *)filename;
return 0;
}
- snprintf(tmpfile, sizeof(tmpfile), "%s.async", args->filename);
+ ssnprintf(tmpfile, sizeof(tmpfile), "%s.async", args->filename);
status = srrd_create(tmpfile, args->pdp_step, args->last_up, args->argc,
(void *)args->argv);
struct genlmsghdr *genh = mnl_nlmsg_put_extra_header(nlh, sizeof(*genh));
*genh = (struct genlmsghdr){
- .cmd = CTRL_CMD_GETFAMILY, .version = 0x01,
+ .cmd = CTRL_CMD_GETFAMILY,
+ .version = 0x01,
};
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TASKSTATS_GENL_NAME);
* regular expressions.
*/
+#ifndef UTILS_TAIL_MATCH_H
+#define UTILS_TAIL_MATCH_H 1
+
#include "utils/latency/latency_config.h"
#include "utils/match/match.h"
*
* RETURN VALUE
* Zero on success, nonzero on failure.
-*/
+ */
int tail_match_read(cu_tail_match_t *obj);
+
+#endif /* UTILS_TAIL_MATCH_H */
#include "plugin.h"
#include "utils/common/common.h"
-#if HAVE_SYS_SYSCTL_H
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME) || \
+ defined(__OpenBSD__)
+/* Implies have BSD variant */
#include <sys/sysctl.h>
#endif
if (plugin_instance == NULL)
plugin_instance = "default";
- snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s",
- plugin_instance, category);
+ ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s",
+ plugin_instance, category);
sstrncpy(vl.type, type, sizeof(vl.type));
/* callback = */ varnish_read,
/* interval = */ 0,
&(user_data_t){
- .data = conf, .free_func = varnish_config_free,
+ .data = conf,
+ .free_func = varnish_config_free,
});
return 0;
!conf->collect_mgt && !conf->collect_lck && !conf->collect_mempool &&
!conf->collect_mse
#endif
- ) {
+ ) {
WARNING("Varnish plugin: No metric has been configured for "
"instance \"%s\". Disabling this instance.",
(conf->instance == NULL) ? "localhost" : conf->instance);
return EINVAL;
}
- snprintf(callback_name, sizeof(callback_name), "varnish/%s",
- (conf->instance == NULL) ? "localhost" : conf->instance);
+ ssnprintf(callback_name, sizeof(callback_name), "varnish/%s",
+ (conf->instance == NULL) ? "localhost" : conf->instance);
plugin_register_complex_read(
/* group = */ "varnish",
/* callback = */ varnish_read,
/* interval = */ 0,
&(user_data_t){
- .data = conf, .free_func = varnish_config_free,
+ .data = conf,
+ .free_func = varnish_config_free,
});
have_instance = true;
#endif
/*
- virConnectListAllDomains() appeared in 0.10.2
- Note that LIBVIR_CHECK_VERSION appeared a year later, so
- in some systems which actually have virConnectListAllDomains()
+ virConnectListAllDomains() appeared in 0.10.2 (Sep 2012)
+ Note that LIBVIR_CHECK_VERSION appeared a year later (Dec 2013,
+ libvirt-1.2.0),
+ so in some systems which actually have virConnectListAllDomains()
we can't detect this.
*/
#if LIBVIR_CHECK_VERSION(0, 10, 2)
#define HAVE_DOM_REASON_POSTCOPY 1
#endif
+#if LIBVIR_CHECK_VERSION(4, 10, 0)
+#define HAVE_DOM_REASON_SHUTOFF_DAEMON 1
+#endif
#endif /* LIBVIR_CHECK_VERSION */
/* structure used for aggregating notification-thread data*/
bool is_active;
} virt_notif_thread_t;
-static const char *config_keys[] = {"Connection",
-
- "RefreshInterval",
-
- "Domain",
- "BlockDevice",
- "BlockDeviceFormat",
- "BlockDeviceFormatBasename",
- "InterfaceDevice",
- "IgnoreSelected",
-
- "HostnameFormat",
- "HostnameMetadataNS",
- "HostnameMetadataXPath",
- "InterfaceFormat",
-
- "PluginInstanceFormat",
-
- "Instances",
- "ExtraStats",
- "PersistentNotification",
-
- "ReportBlockDevices",
- "ReportNetworkInterfaces",
- NULL};
-
/* PersistentNotification is false by default */
static bool persistent_notification = false;
static virt_notif_thread_t notif_thread;
const char *domain_states[] = {
- [VIR_DOMAIN_NOSTATE] = "no state",
- [VIR_DOMAIN_RUNNING] = "the domain is running",
- [VIR_DOMAIN_BLOCKED] = "the domain is blocked on resource",
- [VIR_DOMAIN_PAUSED] = "the domain is paused by user",
- [VIR_DOMAIN_SHUTDOWN] = "the domain is being shut down",
- [VIR_DOMAIN_SHUTOFF] = "the domain is shut off",
- [VIR_DOMAIN_CRASHED] = "the domain is crashed",
+ [VIR_DOMAIN_NOSTATE] = "no state",
+ [VIR_DOMAIN_RUNNING] = "the domain is running",
+ [VIR_DOMAIN_BLOCKED] = "the domain is blocked on resource",
+ [VIR_DOMAIN_PAUSED] = "the domain is paused by user",
+ [VIR_DOMAIN_SHUTDOWN] = "the domain is being shut down",
+ [VIR_DOMAIN_SHUTOFF] = "the domain is shut off",
+ [VIR_DOMAIN_CRASHED] = "the domain is crashed",
#ifdef HAVE_DOM_STATE_PMSUSPENDED
- [VIR_DOMAIN_PMSUSPENDED] =
- "the domain is suspended by guest power management",
+ [VIR_DOMAIN_PMSUSPENDED] =
+ "the domain is suspended by guest power management",
#endif
};
switch (detail) {
case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: /* Guest finished shutdown
sequence */
+#ifdef LIBVIR_CHECK_VERSION
+#if LIBVIR_CHECK_VERSION(3, 4, 0)
+ case VIR_DOMAIN_EVENT_SHUTDOWN_GUEST: /* Domain finished shutting down after
+ request from the guest itself (e.g.
+ hardware-specific action) */
+ case VIR_DOMAIN_EVENT_SHUTDOWN_HOST: /* Domain finished shutting down after
+ request from the host (e.g. killed
+ by a signal) */
+#endif
+#endif
ret = VIR_DOMAIN_SHUTDOWN_USER;
break;
default:
#define DOMAIN_STATE_REASON_MAX_SIZE 20
const char *domain_reasons[][DOMAIN_STATE_REASON_MAX_SIZE] = {
- [VIR_DOMAIN_NOSTATE][VIR_DOMAIN_NOSTATE_UNKNOWN] =
- "the reason is unknown",
-
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_UNKNOWN] =
- "the reason is unknown",
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_BOOTED] =
- "normal startup from boot",
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_MIGRATED] =
- "migrated from another host",
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_RESTORED] =
- "restored from a state file",
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_FROM_SNAPSHOT] =
- "restored from snapshot",
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_UNPAUSED] =
- "returned from paused state",
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_MIGRATION_CANCELED] =
- "returned from migration",
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_SAVE_CANCELED] =
- "returned from failed save process",
+ [VIR_DOMAIN_NOSTATE][VIR_DOMAIN_NOSTATE_UNKNOWN] = "the reason is unknown",
+
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_UNKNOWN] = "the reason is unknown",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_BOOTED] =
+ "normal startup from boot",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_MIGRATED] =
+ "migrated from another host",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_RESTORED] =
+ "restored from a state file",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_FROM_SNAPSHOT] =
+ "restored from snapshot",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_UNPAUSED] =
+ "returned from paused state",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_MIGRATION_CANCELED] =
+ "returned from migration",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_SAVE_CANCELED] =
+ "returned from failed save process",
#ifdef HAVE_DOM_REASON_RUNNING_WAKEUP
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_WAKEUP] =
- "returned from pmsuspended due to wakeup event",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_WAKEUP] =
+ "returned from pmsuspended due to wakeup event",
#endif
#ifdef HAVE_DOM_REASON_CRASHED
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_CRASHED] =
- "resumed from crashed",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_CRASHED] = "resumed from crashed",
#endif
#ifdef HAVE_DOM_REASON_POSTCOPY
- [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_POSTCOPY] =
- "running in post-copy migration mode",
-#endif
- [VIR_DOMAIN_BLOCKED][VIR_DOMAIN_BLOCKED_UNKNOWN] =
- "the reason is unknown",
-
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_UNKNOWN] =
- "the reason is unknown",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_USER] = "paused on user request",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_MIGRATION] =
- "paused for offline migration",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_SAVE] = "paused for save",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_DUMP] =
- "paused for offline core dump",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_IOERROR] =
- "paused due to a disk I/O error",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_WATCHDOG] =
- "paused due to a watchdog event",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_FROM_SNAPSHOT] =
- "paused after restoring from snapshot",
+ [VIR_DOMAIN_RUNNING][VIR_DOMAIN_RUNNING_POSTCOPY] =
+ "running in post-copy migration mode",
+#endif
+ [VIR_DOMAIN_BLOCKED][VIR_DOMAIN_BLOCKED_UNKNOWN] = "the reason is unknown",
+
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_UNKNOWN] = "the reason is unknown",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_USER] = "paused on user request",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_MIGRATION] =
+ "paused for offline migration",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_SAVE] = "paused for save",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_DUMP] =
+ "paused for offline core dump",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_IOERROR] =
+ "paused due to a disk I/O error",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_WATCHDOG] =
+ "paused due to a watchdog event",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_FROM_SNAPSHOT] =
+ "paused after restoring from snapshot",
#ifdef HAVE_DOM_REASON_PAUSED_SHUTTING_DOWN
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_SHUTTING_DOWN] =
- "paused during shutdown process",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_SHUTTING_DOWN] =
+ "paused during shutdown process",
#endif
#ifdef HAVE_DOM_REASON_PAUSED_SNAPSHOT
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_SNAPSHOT] =
- "paused while creating a snapshot",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_SNAPSHOT] =
+ "paused while creating a snapshot",
#endif
#ifdef HAVE_DOM_REASON_PAUSED_CRASHED
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_CRASHED] =
- "paused due to a guest crash",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_CRASHED] =
+ "paused due to a guest crash",
#endif
#ifdef HAVE_DOM_REASON_PAUSED_STARTING_UP
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_STARTING_UP] =
- "the domain is being started",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_STARTING_UP] =
+ "the domain is being started",
#endif
#ifdef HAVE_DOM_REASON_POSTCOPY
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY] =
- "paused for post-copy migration",
- [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY_FAILED] =
- "paused after failed post-copy",
-#endif
- [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_UNKNOWN] =
- "the reason is unknown",
- [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_USER] =
- "shutting down on user request",
-
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_UNKNOWN] =
- "the reason is unknown",
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_SHUTDOWN] = "normal shutdown",
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_DESTROYED] = "forced poweroff",
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_CRASHED] = "domain crashed",
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_MIGRATED] =
- "migrated to another host",
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_SAVED] = "saved to a file",
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_FAILED] =
- "domain failed to start",
- [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT] =
- "restored from a snapshot which was taken while domain was shutoff",
-
- [VIR_DOMAIN_CRASHED][VIR_DOMAIN_CRASHED_UNKNOWN] =
- "the reason is unknown",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY] =
+ "paused for post-copy migration",
+ [VIR_DOMAIN_PAUSED][VIR_DOMAIN_PAUSED_POSTCOPY_FAILED] =
+ "paused after failed post-copy",
+#endif
+ [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_UNKNOWN] =
+ "the reason is unknown",
+ [VIR_DOMAIN_SHUTDOWN][VIR_DOMAIN_SHUTDOWN_USER] =
+ "shutting down on user request",
+
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_UNKNOWN] = "the reason is unknown",
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_SHUTDOWN] = "normal shutdown",
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_DESTROYED] = "forced poweroff",
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_CRASHED] = "domain crashed",
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_MIGRATED] =
+ "migrated to another host",
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_SAVED] = "saved to a file",
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_FAILED] = "domain failed to start",
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT] =
+ "restored from a snapshot which was taken while domain was shutoff",
+#ifdef HAVE_DOM_REASON_SHUTOFF_DAEMON
+ [VIR_DOMAIN_SHUTOFF][VIR_DOMAIN_SHUTOFF_DAEMON] =
+ "daemon decides to kill domain during reconnection processing",
+#endif
+
+ [VIR_DOMAIN_CRASHED][VIR_DOMAIN_CRASHED_UNKNOWN] = "the reason is unknown",
#ifdef VIR_DOMAIN_CRASHED_PANICKED
- [VIR_DOMAIN_CRASHED][VIR_DOMAIN_CRASHED_PANICKED] = "domain panicked",
+ [VIR_DOMAIN_CRASHED][VIR_DOMAIN_CRASHED_PANICKED] = "domain panicked",
#endif
#ifdef HAVE_DOM_STATE_PMSUSPENDED
- [VIR_DOMAIN_PMSUSPENDED][VIR_DOMAIN_PMSUSPENDED_UNKNOWN] =
- "the reason is unknown",
+ [VIR_DOMAIN_PMSUSPENDED][VIR_DOMAIN_PMSUSPENDED_UNKNOWN] =
+ "the reason is unknown",
#endif
};
#endif /* HAVE_DOM_REASON */
-#define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
#define NANOSEC_IN_SEC 1e9
#define GET_STATS(_f, _name, ...) \
struct block_device {
virDomainPtr dom; /* domain */
char *path; /* name of block device */
+ bool has_source; /* information whether source is defined or not */
};
/* Actual list of network interfaces found on last refresh. */
static void free_block_devices(struct lv_read_state *state);
static int add_block_device(struct lv_read_state *state, virDomainPtr dom,
- const char *path);
+ const char *path, bool has_source);
static void free_interface_devices(struct lv_read_state *state);
static int add_interface_device(struct lv_read_state *state, virDomainPtr dom,
ex_stats_job_stats_completed = 1 << 8,
ex_stats_job_stats_background = 1 << 9,
#endif
+ ex_stats_disk_allocation = 1 << 10,
+ ex_stats_disk_capacity = 1 << 11,
+ ex_stats_disk_physical = 1 << 12,
+ ex_stats_memory = 1 << 13,
+ ex_stats_vcpu = 1 << 14
};
static unsigned int extra_stats = ex_stats_none;
{"job_stats_completed", ex_stats_job_stats_completed},
{"job_stats_background", ex_stats_job_stats_background},
#endif
+ {"disk_allocation", ex_stats_disk_allocation},
+ {"disk_capacity", ex_stats_disk_capacity},
+ {"disk_physical", ex_stats_disk_physical},
+ {"memory", ex_stats_memory},
+ {"vcpu", ex_stats_vcpu},
{NULL, ex_stats_none},
};
static time_t last_refresh = (time_t)0;
static int refresh_lists(struct lv_read_instance *inst);
+static int register_event_impl(void);
+static int start_event_loop(virt_notif_thread_t *thread_data);
-struct lv_block_info {
+struct lv_block_stats {
virDomainBlockStatsStruct bi;
long long rd_total_times;
long long fl_total_times;
};
-static void init_block_info(struct lv_block_info *binfo) {
- if (binfo == NULL)
+static void init_block_stats(struct lv_block_stats *bstats) {
+ if (bstats == NULL)
return;
- binfo->bi.rd_req = -1;
- binfo->bi.wr_req = -1;
- binfo->bi.rd_bytes = -1;
- binfo->bi.wr_bytes = -1;
+ bstats->bi.rd_req = -1;
+ bstats->bi.wr_req = -1;
+ bstats->bi.rd_bytes = -1;
+ bstats->bi.wr_bytes = -1;
- binfo->rd_total_times = -1;
- binfo->wr_total_times = -1;
- binfo->fl_req = -1;
- binfo->fl_total_times = -1;
+ bstats->rd_total_times = -1;
+ bstats->wr_total_times = -1;
+ bstats->fl_req = -1;
+ bstats->fl_total_times = -1;
+}
+
+static void init_block_info(virDomainBlockInfoPtr binfo) {
+ binfo->allocation = -1;
+ binfo->capacity = -1;
+ binfo->physical = -1;
}
#ifdef HAVE_BLOCK_STATS_FLAGS
-#define GET_BLOCK_INFO_VALUE(NAME, FIELD) \
+#define GET_BLOCK_STATS_VALUE(NAME, FIELD) \
if (!strcmp(param[i].field, NAME)) { \
- binfo->FIELD = param[i].value.l; \
+ bstats->FIELD = param[i].value.l; \
continue; \
}
-static int get_block_info(struct lv_block_info *binfo,
- virTypedParameterPtr param, int nparams) {
- if (binfo == NULL || param == NULL)
+static int get_block_stats(struct lv_block_stats *bstats,
+ virTypedParameterPtr param, int nparams) {
+ if (bstats == NULL || param == NULL)
return -1;
for (int i = 0; i < nparams; ++i) {
/* ignore type. Everything must be LLONG anyway. */
- GET_BLOCK_INFO_VALUE("rd_operations", bi.rd_req);
- GET_BLOCK_INFO_VALUE("wr_operations", bi.wr_req);
- GET_BLOCK_INFO_VALUE("rd_bytes", bi.rd_bytes);
- GET_BLOCK_INFO_VALUE("wr_bytes", bi.wr_bytes);
- GET_BLOCK_INFO_VALUE("rd_total_times", rd_total_times);
- GET_BLOCK_INFO_VALUE("wr_total_times", wr_total_times);
- GET_BLOCK_INFO_VALUE("flush_operations", fl_req);
- GET_BLOCK_INFO_VALUE("flush_total_times", fl_total_times);
+ GET_BLOCK_STATS_VALUE("rd_operations", bi.rd_req);
+ GET_BLOCK_STATS_VALUE("wr_operations", bi.wr_req);
+ GET_BLOCK_STATS_VALUE("rd_bytes", bi.rd_bytes);
+ GET_BLOCK_STATS_VALUE("wr_bytes", bi.wr_bytes);
+ GET_BLOCK_STATS_VALUE("rd_total_times", rd_total_times);
+ GET_BLOCK_STATS_VALUE("wr_total_times", wr_total_times);
+ GET_BLOCK_STATS_VALUE("flush_operations", fl_req);
+ GET_BLOCK_STATS_VALUE("flush_total_times", fl_total_times);
}
return 0;
}
-#undef GET_BLOCK_INFO_VALUE
+#undef GET_BLOCK_STATS_VALUE
#endif /* HAVE_BLOCK_STATS_FLAGS */
ERROR(PLUGIN_NAME " plugin: %s failed: %s", (s), err->message); \
} while (0)
-char *metadata_get_hostname(virDomainPtr dom) {
+enum metadata_set_type_e { META_APPEND_HOST, META_APPEND_PLUGIN_INSTANCE };
+
+static void set_field_from_metadata(value_list_t *vl, virDomainPtr dom,
+ enum metadata_set_type_e field) {
const char *xpath_str = NULL;
if (hm_xpath == NULL)
xpath_str = "/instance/name/text()";
const char *namespace = NULL;
if (hm_ns == NULL) {
namespace = "http://openstack.org/xmlns/libvirt/nova/1.0";
- } else {
+ } // namespace =hm_ns;
+ else {
namespace = hm_ns;
}
char *metadata_str = virDomainGetMetadata(
dom, VIR_DOMAIN_METADATA_ELEMENT, namespace, VIR_DOMAIN_AFFECT_CURRENT);
if (metadata_str == NULL) {
- return NULL;
+ return;
}
- char *hostname = NULL;
+ const char *value = NULL;
xmlXPathContextPtr xpath_ctx = NULL;
xmlXPathObjectPtr xpath_obj = NULL;
xmlNodePtr xml_node = NULL;
xml_node = xpath_obj->nodesetval->nodeTab[0];
if (xml_node->type == XML_TEXT_NODE) {
- hostname = strdup((const char *)xml_node->content);
+ value = (const char *)xml_node->content;
} else if (xml_node->type == XML_ATTRIBUTE_NODE) {
- hostname = strdup((const char *)xml_node->children->content);
+ value = (const char *)xml_node->children->content;
} else {
ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) unsupported node type %d",
xpath_str, xml_node->type);
goto metadata_end;
}
- if (hostname == NULL) {
- ERROR(PLUGIN_NAME " plugin: strdup(%s) hostname failed", xpath_str);
+ if (value == NULL)
goto metadata_end;
+
+ switch (field) {
+ case META_APPEND_HOST:
+ SSTRNCAT(vl->host, value, sizeof(vl->host));
+ break;
+ case META_APPEND_PLUGIN_INSTANCE:
+ SSTRNCAT(vl->plugin_instance, value, sizeof(vl->plugin_instance));
+ break;
}
metadata_end:
if (xml_doc)
xmlFreeDoc(xml_doc);
sfree(metadata_str);
- return hostname;
}
static void init_value_list(value_list_t *vl, virDomainPtr dom) {
SSTRNCAT(vl->host, uuid, sizeof(vl->host));
break;
case hf_metadata:
- name = metadata_get_hostname(dom);
- if (name)
- SSTRNCAT(vl->host, name, sizeof(vl->host));
+ set_field_from_metadata(vl, dom, META_APPEND_HOST);
break;
}
}
SSTRNCAT(vl->plugin_instance, uuid, sizeof(vl->plugin_instance));
break;
case plginst_metadata:
- name = metadata_get_hostname(dom);
- if (name)
- SSTRNCAT(vl->plugin_instance, name, sizeof(vl->plugin_instance));
+ set_field_from_metadata(vl, dom, META_APPEND_PLUGIN_INSTANCE);
break;
}
}
-
} /* void init_value_list */
static int init_notif(notification_t *notif, const virDomainPtr domain,
static void memory_stats_submit(gauge_t value, virDomainPtr dom,
int tag_index) {
- static const char *tags[] = {"swap_in", "swap_out", "major_fault",
- "minor_fault", "unused", "available",
- "actual_balloon", "rss", "usable",
- "last_update"};
+ static const char *tags[] = {"swap_in", "swap_out", "major_fault",
+ "minor_fault", "unused", "available",
+ "actual_balloon", "rss", "usable",
+ "last_update", "disk_caches"};
if ((tag_index < 0) || (tag_index >= (int)STATIC_ARRAY_SIZE(tags))) {
- ERROR("virt plugin: Array index out of bounds: tag_index = %d", tag_index);
+ ERROR(PLUGIN_NAME " plugin: Array index out of bounds: tag_index = %d",
+ tag_index);
return;
}
static void submit_derive2(const char *type, derive_t v0, derive_t v1,
virDomainPtr dom, const char *devname) {
value_t values[] = {
- {.derive = v0}, {.derive = v1},
+ {.derive = v0},
+ {.derive = v1},
};
submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values));
}
DEBUG(PLUGIN_NAME " plugin: node_cpus=%u cpu_time_old=%" PRIu64
- " cpu_time_new=%" PRIu64 "cpu_time_diff=%" 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);
const char *type) {
char type_instance[DATA_MAX_NAME_LEN];
- snprintf(type_instance, sizeof(type_instance), "%d", vcpu_nr);
+ ssnprintf(type_instance, sizeof(type_instance), "%d", vcpu_nr);
submit(dom, type, type_instance, &(value_t){.derive = value}, 1);
}
-static void disk_submit(struct lv_block_info *binfo, virDomainPtr dom,
- const char *dev) {
+static void disk_block_stats_submit(struct lv_block_stats *bstats,
+ virDomainPtr dom, const char *dev,
+ virDomainBlockInfoPtr binfo) {
char *dev_copy = strdup(dev);
const char *type_instance = dev_copy;
}
char flush_type_instance[DATA_MAX_NAME_LEN];
- snprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s",
- type_instance);
+ ssnprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s",
+ type_instance);
- if ((binfo->bi.rd_req != -1) && (binfo->bi.wr_req != -1))
- submit_derive2("disk_ops", (derive_t)binfo->bi.rd_req,
- (derive_t)binfo->bi.wr_req, dom, type_instance);
+ if ((bstats->bi.rd_req != -1) && (bstats->bi.wr_req != -1))
+ submit_derive2("disk_ops", (derive_t)bstats->bi.rd_req,
+ (derive_t)bstats->bi.wr_req, dom, type_instance);
- if ((binfo->bi.rd_bytes != -1) && (binfo->bi.wr_bytes != -1))
- submit_derive2("disk_octets", (derive_t)binfo->bi.rd_bytes,
- (derive_t)binfo->bi.wr_bytes, dom, type_instance);
+ if ((bstats->bi.rd_bytes != -1) && (bstats->bi.wr_bytes != -1))
+ submit_derive2("disk_octets", (derive_t)bstats->bi.rd_bytes,
+ (derive_t)bstats->bi.wr_bytes, dom, type_instance);
if (extra_stats & ex_stats_disk) {
- if ((binfo->rd_total_times != -1) && (binfo->wr_total_times != -1))
- submit_derive2("disk_time", (derive_t)binfo->rd_total_times,
- (derive_t)binfo->wr_total_times, dom, type_instance);
+ if ((bstats->rd_total_times != -1) && (bstats->wr_total_times != -1))
+ submit_derive2("disk_time", (derive_t)bstats->rd_total_times,
+ (derive_t)bstats->wr_total_times, dom, type_instance);
- if (binfo->fl_req != -1)
+ if (bstats->fl_req != -1)
submit(dom, "total_requests", flush_type_instance,
- &(value_t){.derive = (derive_t)binfo->fl_req}, 1);
- if (binfo->fl_total_times != -1) {
- derive_t value = binfo->fl_total_times / 1000; // ns -> ms
+ &(value_t){.derive = (derive_t)bstats->fl_req}, 1);
+ if (bstats->fl_total_times != -1) {
+ derive_t value = bstats->fl_total_times / 1000; // ns -> ms
submit(dom, "total_time_in_ms", flush_type_instance,
&(value_t){.derive = value}, 1);
}
}
+ /* disk_allocation, disk_capacity and disk_physical are stored only
+ * if corresponding extrastats are set in collectd configuration file */
+ if ((extra_stats & ex_stats_disk_allocation) && binfo->allocation != -1)
+ submit(dom, "disk_allocation", type_instance,
+ &(value_t){.gauge = (gauge_t)binfo->allocation}, 1);
+
+ if ((extra_stats & ex_stats_disk_capacity) && binfo->capacity != -1)
+ submit(dom, "disk_capacity", type_instance,
+ &(value_t){.gauge = (gauge_t)binfo->capacity}, 1);
+
+ if ((extra_stats & ex_stats_disk_physical) && binfo->physical != -1)
+ submit(dom, "disk_physical", type_instance,
+ &(value_t){.gauge = (gauge_t)binfo->physical}, 1);
+
sfree(dev_copy);
}
-static unsigned int parse_ex_stats_flags(char **exstats, int numexstats) {
+/**
+ * Function for parsing ExtraStats configuration options.
+ * Result of parsing is stored under 'out_parsed_flags' pointer.
+ *
+ * Returns 0 in case of success and 1 in case of parsing error
+ */
+static int parse_ex_stats_flags(unsigned int *out_parsed_flags, char **exstats,
+ int numexstats) {
unsigned int ex_stats_flags = ex_stats_none;
+
+ assert(out_parsed_flags != NULL);
+
for (int i = 0; i < numexstats; i++) {
for (int j = 0; ex_stats_table[j].name != NULL; j++) {
if (strcasecmp(exstats[i], ex_stats_table[j].name) == 0) {
if (ex_stats_table[j + 1].name == NULL) {
ERROR(PLUGIN_NAME " plugin: Unmatched ExtraStats option: %s",
exstats[i]);
+ return 1;
}
}
}
- return ex_stats_flags;
+
+ *out_parsed_flags = ex_stats_flags;
+ return 0;
}
static void domain_state_submit_notif(virDomainPtr dom, int state, int reason) {
const char *reason_str = "N/A";
#endif
- snprintf(msg, sizeof(msg), "Domain state: %s. Reason: %s", state_str,
- reason_str);
+ ssnprintf(msg, sizeof(msg), "Domain state: %s. Reason: %s", state_str,
+ reason_str);
int severity;
switch (state) {
return 0;
}
-static int lv_config(const char *key, const char *value) {
- if (virInitialize() != 0)
- return 1;
-
- if (lv_init_ignorelists() != 0)
- return 1;
-
- if (strcasecmp(key, "Connection") == 0) {
- char *tmp = strdup(value);
- if (tmp == NULL) {
- ERROR(PLUGIN_NAME " plugin: Connection strdup failed.");
- return 1;
- }
- sfree(conn_string);
- conn_string = tmp;
- return 0;
- }
-
- if (strcasecmp(key, "RefreshInterval") == 0) {
- char *eptr = NULL;
- interval = strtol(value, &eptr, 10);
- if (eptr == NULL || *eptr != '\0')
- return 1;
- return 0;
+/* Validates config option that may take multiple strings arguments.
+ * Returns 0 on success, -1 otherwise */
+static int check_config_multiple_string_entry(const oconfig_item_t *ci) {
+ if (ci == NULL) {
+ ERROR(PLUGIN_NAME " plugin: ci oconfig_item can't be NULL");
+ return -1;
}
- if (strcasecmp(key, "Domain") == 0) {
- if (ignorelist_add(il_domains, value))
- return 1;
- return 0;
- }
- if (strcasecmp(key, "BlockDevice") == 0) {
- if (ignorelist_add(il_block_devices, value))
- return 1;
- return 0;
+ if (ci->values_num < 1) {
+ ERROR(PLUGIN_NAME
+ " plugin: the '%s' option requires at least one string argument",
+ ci->key);
+ return -1;
}
- if (strcasecmp(key, "BlockDeviceFormat") == 0) {
- if (strcasecmp(value, "target") == 0)
- blockdevice_format = target;
- else if (strcasecmp(value, "source") == 0)
- blockdevice_format = source;
- else {
- ERROR(PLUGIN_NAME " plugin: unknown BlockDeviceFormat: %s", value);
+ for (int i = 0; i < ci->values_num; ++i) {
+ if (ci->values[i].type != OCONFIG_TYPE_STRING) {
+ ERROR(PLUGIN_NAME
+ " plugin: one of the '%s' options is not a valid string",
+ ci->key);
return -1;
}
- return 0;
- }
- if (strcasecmp(key, "BlockDeviceFormatBasename") == 0) {
- blockdevice_format_basename = IS_TRUE(value) ? true : false;
- return 0;
- }
- if (strcasecmp(key, "InterfaceDevice") == 0) {
- if (ignorelist_add(il_interface_devices, value))
- return 1;
- return 0;
}
- if (strcasecmp(key, "IgnoreSelected") == 0) {
- if (IS_TRUE(value)) {
- ignorelist_set_invert(il_domains, 0);
- ignorelist_set_invert(il_block_devices, 0);
- ignorelist_set_invert(il_interface_devices, 0);
- } else {
- ignorelist_set_invert(il_domains, 1);
- ignorelist_set_invert(il_block_devices, 1);
- ignorelist_set_invert(il_interface_devices, 1);
- }
- return 0;
- }
+ return 0;
+}
- if (strcasecmp(key, "HostnameMetadataNS") == 0) {
- char *tmp = strdup(value);
- if (tmp == NULL) {
- ERROR(PLUGIN_NAME " plugin: HostnameMetadataNS strdup failed.");
- return 1;
- }
- sfree(hm_ns);
- hm_ns = tmp;
- return 0;
+static int lv_config(oconfig_item_t *ci) {
+ if (lv_init_ignorelists() != 0) {
+ ERROR(PLUGIN_NAME " plugin: lv_init_ignorelist failed.");
+ return -1;
}
- if (strcasecmp(key, "HostnameMetadataXPath") == 0) {
- char *tmp = strdup(value);
- if (tmp == NULL) {
- ERROR(PLUGIN_NAME " plugin: HostnameMetadataXPath strdup failed.");
- return 1;
- }
- sfree(hm_xpath);
- hm_xpath = tmp;
- return 0;
- }
+ for (int i = 0; i < ci->children_num; ++i) {
+ oconfig_item_t *c = ci->children + i;
- if (strcasecmp(key, "HostnameFormat") == 0) {
- char *value_copy = strdup(value);
- if (value_copy == NULL) {
- ERROR(PLUGIN_NAME " plugin: strdup failed.");
- return -1;
- }
+ if (strcasecmp(c->key, "Connection") == 0) {
+ if (cf_util_get_string(c, &conn_string) != 0 || conn_string == NULL)
+ return -1;
- char *fields[HF_MAX_FIELDS];
- int n = strsplit(value_copy, fields, HF_MAX_FIELDS);
- if (n < 1) {
- sfree(value_copy);
- ERROR(PLUGIN_NAME " plugin: HostnameFormat: no fields");
- return -1;
- }
+ continue;
+ } else if (strcasecmp(c->key, "RefreshInterval") == 0) {
+ if (cf_util_get_int(c, &interval) != 0)
+ return -1;
- for (int i = 0; i < n; ++i) {
- if (strcasecmp(fields[i], "hostname") == 0)
- hostname_format[i] = hf_hostname;
- else if (strcasecmp(fields[i], "name") == 0)
- hostname_format[i] = hf_name;
- else if (strcasecmp(fields[i], "uuid") == 0)
- hostname_format[i] = hf_uuid;
- else if (strcasecmp(fields[i], "metadata") == 0)
- hostname_format[i] = hf_metadata;
+ continue;
+ } else if (strcasecmp(c->key, "Domain") == 0) {
+ char *domain_name = NULL;
+ if (cf_util_get_string(c, &domain_name) != 0)
+ return -1;
+
+ if (ignorelist_add(il_domains, domain_name)) {
+ ERROR(PLUGIN_NAME " plugin: Adding '%s' to domain-ignorelist failed",
+ domain_name);
+ sfree(domain_name);
+ return -1;
+ }
+
+ sfree(domain_name);
+ continue;
+ } else if (strcasecmp(c->key, "BlockDevice") == 0) {
+ char *device_name = NULL;
+ if (cf_util_get_string(c, &device_name) != 0)
+ return -1;
+
+ if (ignorelist_add(il_block_devices, device_name) != 0) {
+ ERROR(PLUGIN_NAME
+ " plugin: Adding '%s' to block-device-ignorelist failed",
+ device_name);
+ sfree(device_name);
+ return -1;
+ }
+
+ sfree(device_name);
+ continue;
+ } else if (strcasecmp(c->key, "BlockDeviceFormat") == 0) {
+ char *device_format = NULL;
+ if (cf_util_get_string(c, &device_format) != 0)
+ return -1;
+
+ if (strcasecmp(device_format, "target") == 0)
+ blockdevice_format = target;
+ else if (strcasecmp(device_format, "source") == 0)
+ blockdevice_format = source;
else {
- ERROR(PLUGIN_NAME " plugin: unknown HostnameFormat field: %s",
- fields[i]);
- sfree(value_copy);
+ ERROR(PLUGIN_NAME " plugin: unknown BlockDeviceFormat: %s",
+ device_format);
+ sfree(device_format);
return -1;
}
- }
- sfree(value_copy);
- for (int i = n; i < HF_MAX_FIELDS; ++i)
- hostname_format[i] = hf_none;
+ sfree(device_format);
+ continue;
+ } else if (strcasecmp(c->key, "BlockDeviceFormatBasename") == 0) {
+ if (cf_util_get_boolean(c, &blockdevice_format_basename) != 0)
+ return -1;
- return 0;
- }
+ continue;
+ } else if (strcasecmp(c->key, "InterfaceDevice") == 0) {
+ char *interface_name = NULL;
+ if (cf_util_get_string(c, &interface_name) != 0)
+ return -1;
- if (strcasecmp(key, "PluginInstanceFormat") == 0) {
- char *value_copy = strdup(value);
- if (value_copy == NULL) {
- ERROR(PLUGIN_NAME " plugin: strdup failed.");
- return -1;
- }
+ if (ignorelist_add(il_interface_devices, interface_name)) {
+ ERROR(PLUGIN_NAME " plugin: Adding '%s' to interface-ignorelist failed",
+ interface_name);
+ sfree(interface_name);
+ return -1;
+ }
- char *fields[PLGINST_MAX_FIELDS];
- int n = strsplit(value_copy, fields, PLGINST_MAX_FIELDS);
- if (n < 1) {
- sfree(value_copy);
- ERROR(PLUGIN_NAME " plugin: PluginInstanceFormat: no fields");
- return -1;
- }
+ sfree(interface_name);
+ continue;
+ } else if (strcasecmp(c->key, "IgnoreSelected") == 0) {
+ bool ignore_selected = false;
+ if (cf_util_get_boolean(c, &ignore_selected) != 0)
+ return -1;
- for (int i = 0; i < n; ++i) {
- if (strcasecmp(fields[i], "none") == 0) {
- plugin_instance_format[i] = plginst_none;
- break;
- } else if (strcasecmp(fields[i], "name") == 0)
- plugin_instance_format[i] = plginst_name;
- else if (strcasecmp(fields[i], "uuid") == 0)
- plugin_instance_format[i] = plginst_uuid;
- else if (strcasecmp(fields[i], "metadata") == 0)
- plugin_instance_format[i] = plginst_metadata;
- else {
- ERROR(PLUGIN_NAME " plugin: unknown PluginInstanceFormat field: %s",
- fields[i]);
- sfree(value_copy);
+ if (ignore_selected) {
+ ignorelist_set_invert(il_domains, 0);
+ ignorelist_set_invert(il_block_devices, 0);
+ ignorelist_set_invert(il_interface_devices, 0);
+ } else {
+ ignorelist_set_invert(il_domains, 1);
+ ignorelist_set_invert(il_block_devices, 1);
+ ignorelist_set_invert(il_interface_devices, 1);
+ }
+
+ continue;
+ } else if (strcasecmp(c->key, "HostnameMetadataNS") == 0) {
+ if (cf_util_get_string(c, &hm_ns) != 0)
+ return -1;
+
+ continue;
+ } else if (strcasecmp(c->key, "HostnameMetadataXPath") == 0) {
+ if (cf_util_get_string(c, &hm_xpath) != 0)
+ return -1;
+
+ continue;
+ } else if (strcasecmp(c->key, "HostnameFormat") == 0) {
+ /* this option can take multiple strings arguments in one config line*/
+ if (check_config_multiple_string_entry(c) != 0) {
+ ERROR(PLUGIN_NAME " plugin: Could not get 'HostnameFormat' parameter");
return -1;
}
- }
- sfree(value_copy);
- for (int i = n; i < PLGINST_MAX_FIELDS; ++i)
- plugin_instance_format[i] = plginst_none;
+ const int params_num = c->values_num;
+ for (int i = 0; i < params_num; ++i) {
+ const char *param_name = c->values[i].value.string;
+ if (strcasecmp(param_name, "hostname") == 0)
+ hostname_format[i] = hf_hostname;
+ else if (strcasecmp(param_name, "name") == 0)
+ hostname_format[i] = hf_name;
+ else if (strcasecmp(param_name, "uuid") == 0)
+ hostname_format[i] = hf_uuid;
+ else if (strcasecmp(param_name, "metadata") == 0)
+ hostname_format[i] = hf_metadata;
+ else {
+ ERROR(PLUGIN_NAME " plugin: unknown HostnameFormat field: %s",
+ param_name);
+ return -1;
+ }
+ }
- return 0;
- }
+ for (int i = params_num; i < HF_MAX_FIELDS; ++i)
+ hostname_format[i] = hf_none;
- if (strcasecmp(key, "InterfaceFormat") == 0) {
- if (strcasecmp(value, "name") == 0)
- interface_format = if_name;
- else if (strcasecmp(value, "address") == 0)
- interface_format = if_address;
- else if (strcasecmp(value, "number") == 0)
- interface_format = if_number;
- else {
- ERROR(PLUGIN_NAME " plugin: unknown InterfaceFormat: %s", value);
- return -1;
- }
- return 0;
- }
+ continue;
+ } else if (strcasecmp(c->key, "PluginInstanceFormat") == 0) {
+ /* this option can handle list of string parameters in one line*/
+ if (check_config_multiple_string_entry(c) != 0) {
+ ERROR(PLUGIN_NAME
+ " plugin: Could not get 'PluginInstanceFormat' parameter");
+ return -1;
+ }
- if (strcasecmp(key, "Instances") == 0) {
- char *eptr = NULL;
- double val = strtod(value, &eptr);
+ const int params_num = c->values_num;
+ for (int i = 0; i < params_num; ++i) {
+ const char *param_name = c->values[i].value.string;
+ if (strcasecmp(param_name, "none") == 0) {
+ plugin_instance_format[i] = plginst_none;
+ break;
+ } else if (strcasecmp(param_name, "name") == 0)
+ plugin_instance_format[i] = plginst_name;
+ else if (strcasecmp(param_name, "uuid") == 0)
+ plugin_instance_format[i] = plginst_uuid;
+ else if (strcasecmp(param_name, "metadata") == 0)
+ plugin_instance_format[i] = plginst_metadata;
+ else {
+ ERROR(PLUGIN_NAME " plugin: unknown PluginInstanceFormat field: %s",
+ param_name);
+
+ return -1;
+ }
+ }
- if (*eptr != '\0') {
- ERROR(PLUGIN_NAME " plugin: Invalid value for Instances = '%s'", value);
- return 1;
- }
- if (val <= 0) {
- ERROR(PLUGIN_NAME " plugin: Instances <= 0 makes no sense.");
- return 1;
- }
- if (val > NR_INSTANCES_MAX) {
- ERROR(PLUGIN_NAME " plugin: Instances=%f > NR_INSTANCES_MAX=%i"
- " use a lower setting or recompile the plugin.",
- val, NR_INSTANCES_MAX);
- return 1;
- }
+ for (int i = params_num; i < PLGINST_MAX_FIELDS; ++i)
+ plugin_instance_format[i] = plginst_none;
- nr_instances = (int)val;
- DEBUG(PLUGIN_NAME " plugin: configured %i instances", nr_instances);
- return 0;
- }
+ continue;
+ } else if (strcasecmp(c->key, "InterfaceFormat") == 0) {
+ char *format = NULL;
+ if (cf_util_get_string(c, &format) != 0)
+ return -1;
+
+ if (strcasecmp(format, "name") == 0)
+ interface_format = if_name;
+ else if (strcasecmp(format, "address") == 0)
+ interface_format = if_address;
+ else if (strcasecmp(format, "number") == 0)
+ interface_format = if_number;
+ else {
+ ERROR(PLUGIN_NAME " plugin: unknown InterfaceFormat: %s", format);
+ sfree(format);
+ return -1;
+ }
+
+ sfree(format);
+ continue;
+ } else if (strcasecmp(c->key, "Instances") == 0) {
+ if (cf_util_get_int(c, &nr_instances) != 0)
+ return -1;
+
+ if (nr_instances <= 0) {
+ ERROR(PLUGIN_NAME " plugin: Instances <= 0 makes no sense.");
+ return -1;
+ }
+ if (nr_instances > NR_INSTANCES_MAX) {
+ ERROR(PLUGIN_NAME " plugin: Instances=%i > NR_INSTANCES_MAX=%i"
+ " use a lower setting or recompile the plugin.",
+ nr_instances, NR_INSTANCES_MAX);
+ return -1;
+ }
+
+ DEBUG(PLUGIN_NAME " plugin: configured %i instances", nr_instances);
+ continue;
+ } else if (strcasecmp(c->key, "ExtraStats") == 0) {
+ char *ex_str = NULL;
+
+ if (cf_util_get_string(c, &ex_str) != 0)
+ return -1;
- if (strcasecmp(key, "ExtraStats") == 0) {
- char *localvalue = strdup(value);
- if (localvalue != NULL) {
char *exstats[EX_STATS_MAX_FIELDS];
- int numexstats =
- strsplit(localvalue, exstats, STATIC_ARRAY_SIZE(exstats));
- extra_stats = parse_ex_stats_flags(exstats, numexstats);
- sfree(localvalue);
+ int numexstats = strsplit(ex_str, exstats, STATIC_ARRAY_SIZE(exstats));
+ int status = parse_ex_stats_flags(&extra_stats, exstats, numexstats);
+ sfree(ex_str);
+ if (status != 0) {
+ ERROR(PLUGIN_NAME " plugin: parsing 'ExtraStats' option failed");
+ return status;
+ }
#ifdef HAVE_JOB_STATS
if ((extra_stats & ex_stats_job_stats_completed) &&
ERROR(PLUGIN_NAME " plugin: Invalid job stats configuration. Only one "
"type of job statistics can be collected at the same "
"time");
- return 1;
+ return -1;
}
#endif
- }
- }
- if (strcasecmp(key, "PersistentNotification") == 0) {
- persistent_notification = IS_TRUE(value);
- return 0;
- }
+ /* ExtraStats parsed successfully */
+ continue;
+ } else if (strcasecmp(c->key, "PersistentNotification") == 0) {
+ if (cf_util_get_boolean(c, &persistent_notification) != 0)
+ return -1;
- if (strcasecmp(key, "ReportBlockDevices") == 0) {
- report_block_devices = IS_TRUE(value);
- return 0;
- }
+ continue;
+ } else if (strcasecmp(c->key, "ReportBlockDevices") == 0) {
+ if (cf_util_get_boolean(c, &report_block_devices) != 0)
+ return -1;
- if (strcasecmp(key, "ReportNetworkInterfaces") == 0) {
- report_network_interfaces = IS_TRUE(value);
- return 0;
+ continue;
+ } else if (strcasecmp(c->key, "ReportNetworkInterfaces") == 0) {
+ if (cf_util_get_boolean(c, &report_network_interfaces) != 0)
+ return -1;
+
+ continue;
+ } else {
+ /* Unrecognised option. */
+ ERROR(PLUGIN_NAME " plugin: Unrecognized option: '%s'", c->key);
+ return -1;
+ }
}
- /* Unrecognised option. */
- return -1;
+ return 0;
}
static int lv_connect(void) {
if (conn == NULL) {
+ /* event implementation must be registered before connection is opened */
+ if (!persistent_notification)
+ if (register_event_impl() != 0)
+ return -1;
+
/* `conn_string == NULL' is acceptable */
#ifdef HAVE_FS_INFO
/* virDomainGetFSInfo requires full read-write access connection */
int status = virNodeGetInfo(conn, &nodeinfo);
if (status != 0) {
ERROR(PLUGIN_NAME " plugin: virNodeGetInfo failed");
+ virConnectClose(conn);
+ conn = NULL;
return -1;
}
+
+ if (!persistent_notification)
+ if (start_event_loop(¬if_thread) != 0) {
+ virConnectClose(conn);
+ conn = NULL;
+ return -1;
+ }
}
c_release(LOG_NOTICE, &conn_complain,
PLUGIN_NAME " plugin: Connection established.");
WARNING(PLUGIN_NAME " plugin: closed connection to libvirt");
}
-static int lv_domain_block_info(virDomainPtr dom, const char *path,
- struct lv_block_info *binfo) {
+static int lv_domain_block_stats(virDomainPtr dom, const char *path,
+ struct lv_block_stats *bstats) {
#ifdef HAVE_BLOCK_STATS_FLAGS
int nparams = 0;
if (virDomainBlockStatsFlags(dom, path, NULL, &nparams, 0) < 0 ||
virTypedParameterPtr params = calloc(nparams, sizeof(*params));
if (params == NULL) {
- ERROR("virt plugin: alloc(%i) for block=%s parameters failed.", nparams,
- path);
+ ERROR(PLUGIN_NAME " plugin: alloc(%i) for block=%s parameters failed.",
+ nparams, path);
return -1;
}
if (virDomainBlockStatsFlags(dom, path, params, &nparams, 0) < 0) {
VIRT_ERROR(conn, "getting the disk params values");
} else {
- rc = get_block_info(binfo, params, nparams);
+ rc = get_block_stats(bstats, params, nparams);
}
virTypedParamsClear(params, nparams);
sfree(params);
return rc;
#else
- return virDomainBlockStats(dom, path, &(binfo->bi), sizeof(binfo->bi));
+ return virDomainBlockStats(dom, path, &(bstats->bi), sizeof(bstats->bi));
#endif /* HAVE_BLOCK_STATS_FLAGS */
}
int status =
virDomainListGetStats(domain_array, VIR_DOMAIN_STATS_PERF, &stats, 0);
if (status == -1) {
- ERROR("virt plugin: virDomainListGetStats failed with status %i.", status);
- return status;
+ ERROR(PLUGIN_NAME " plugin: virDomainListGetStats failed with status %i.",
+ status);
+
+ virErrorPtr err = virGetLastError();
+ if (err->code == VIR_ERR_NO_SUPPORT) {
+ ERROR(PLUGIN_NAME
+ " plugin: Disabled unsupported ExtraStats selector: perf");
+ extra_stats &= ~(ex_stats_perf);
+ }
+
+ return -1;
}
for (int i = 0; i < status; ++i)
char type_instance[DATA_MAX_NAME_LEN];
bool is_set = VIR_CPU_USABLE(cpu_maps, cpu_map_len, vcpu, cpu);
- snprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu, cpu);
+ ssnprintf(type_instance, sizeof(type_instance), "vcpu_%d-cpu_%d", vcpu,
+ cpu);
submit(dom, "cpu_affinity", type_instance, &(value_t){.gauge = is_set}, 1);
}
}
static int get_vcpu_stats(virDomainPtr domain, unsigned short nr_virt_cpu) {
int max_cpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
- int cpu_map_len = VIR_CPU_MAPLEN(max_cpus);
virVcpuInfoPtr vinfo = calloc(nr_virt_cpu, sizeof(*vinfo));
if (vinfo == NULL) {
return -1;
}
- unsigned char *cpumaps = calloc(nr_virt_cpu, cpu_map_len);
- if (cpumaps == NULL) {
- ERROR(PLUGIN_NAME " plugin: calloc failed.");
- sfree(vinfo);
- return -1;
+ int cpu_map_len = 0;
+ unsigned char *cpumaps = NULL;
+ if (extra_stats & ex_stats_vcpupin) {
+ cpu_map_len = VIR_CPU_MAPLEN(max_cpus);
+ cpumaps = calloc(nr_virt_cpu, cpu_map_len);
+
+ if (cpumaps == NULL) {
+ ERROR(PLUGIN_NAME " plugin: calloc failed.");
+ sfree(vinfo);
+ return -1;
+ }
}
int status =
if (status < 0) {
ERROR(PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.",
status);
+
+ virErrorPtr err = virGetLastError();
+ if (err->code == VIR_ERR_NO_SUPPORT) {
+ if (extra_stats & ex_stats_vcpu)
+ ERROR(PLUGIN_NAME
+ " plugin: Disabled unsupported ExtraStats selector: vcpu");
+ if (extra_stats & ex_stats_vcpupin)
+ ERROR(PLUGIN_NAME
+ " plugin: Disabled unsupported ExtraStats selector: vcpupin");
+ extra_stats &= ~(ex_stats_vcpu | ex_stats_vcpupin);
+ }
+
sfree(cpumaps);
sfree(vinfo);
- return status;
+ return -1;
}
for (int i = 0; i < nr_virt_cpu; ++i) {
- vcpu_submit(vinfo[i].cpuTime, domain, vinfo[i].number, "virt_vcpu");
+ if (extra_stats & ex_stats_vcpu)
+ vcpu_submit(vinfo[i].cpuTime, domain, vinfo[i].number, "virt_vcpu");
if (extra_stats & ex_stats_vcpupin)
vcpu_pin_submit(domain, max_cpus, i, cpumaps, cpu_map_len);
}
int nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0);
if (nparams < 0) {
VIRT_ERROR(conn, "getting the CPU params count");
+
+ virErrorPtr err = virGetLastError();
+ if (err->code == VIR_ERR_NO_SUPPORT) {
+ ERROR(PLUGIN_NAME
+ " plugin: Disabled unsupported ExtraStats selector: pcpu");
+ extra_stats &= ~(ex_stats_pcpu);
+ }
+
return -1;
}
#endif /* HAVE_CPU_STATS */
#ifdef HAVE_DOM_REASON
-
-static void domain_state_submit(virDomainPtr dom, int state, int reason) {
- value_t values[] = {
- {.gauge = (gauge_t)state}, {.gauge = (gauge_t)reason},
- };
-
- submit(dom, "domain_state", NULL, values, STATIC_ARRAY_SIZE(values));
-}
-
-static int get_domain_state(virDomainPtr domain) {
+static int submit_domain_state(virDomainPtr domain) {
int domain_state = 0;
int domain_reason = 0;
return status;
}
- domain_state_submit(domain, domain_state, domain_reason);
+ value_t values[] = {
+ {.gauge = (gauge_t)domain_state},
+ {.gauge = (gauge_t)domain_reason},
+ };
- return status;
+ submit(domain, "domain_state", NULL, values, STATIC_ARRAY_SIZE(values));
+
+ return 0;
}
#ifdef HAVE_LIST_ALL_DOMAINS
return status;
}
- if (persistent_notification)
- domain_state_submit_notif(domain, domain_state, domain_reason);
+ domain_state_submit_notif(domain, domain_state, domain_reason);
return status;
}
virDomainMemoryStatPtr minfo =
calloc(VIR_DOMAIN_MEMORY_STAT_NR, sizeof(*minfo));
if (minfo == NULL) {
- ERROR("virt plugin: calloc failed.");
+ ERROR(PLUGIN_NAME " plugin: calloc failed.");
return -1;
}
int mem_stats =
virDomainMemoryStats(domain, minfo, VIR_DOMAIN_MEMORY_STAT_NR, 0);
if (mem_stats < 0) {
- ERROR("virt plugin: virDomainMemoryStats failed with mem_stats %i.",
+ ERROR(PLUGIN_NAME " plugin: virDomainMemoryStats failed with mem_stats %i.",
mem_stats);
sfree(minfo);
- return mem_stats;
+
+ virErrorPtr err = virGetLastError();
+ if (err->code == VIR_ERR_NO_SUPPORT) {
+ ERROR(PLUGIN_NAME
+ " plugin: Disabled unsupported ExtraStats selector: memory");
+ extra_stats &= ~(ex_stats_memory);
+ }
+
+ return -1;
+ }
+
+ derive_t swap_in = -1;
+ derive_t swap_out = -1;
+ derive_t min_flt = -1;
+ derive_t maj_flt = -1;
+
+ for (int i = 0; i < mem_stats; i++) {
+ if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
+ swap_in = minfo[i].val;
+ else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
+ swap_out = minfo[i].val;
+ else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
+ min_flt = minfo[i].val;
+ else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
+ maj_flt = minfo[i].val;
+#ifdef LIBVIR_CHECK_VERSION
+#if LIBVIR_CHECK_VERSION(2, 1, 0)
+ else if (minfo[i].tag == VIR_DOMAIN_MEMORY_STAT_LAST_UPDATE)
+ /* Skip 'last_update' reporting as that is not memory but timestamp */
+ continue;
+#endif
+#endif
+ else
+ memory_stats_submit((gauge_t)minfo[i].val * 1024, domain, minfo[i].tag);
+ }
+
+ if (swap_in > 0 || swap_out > 0) {
+ submit(domain, "swap_io", "in", &(value_t){.gauge = swap_in}, 1);
+ submit(domain, "swap_io", "out", &(value_t){.gauge = swap_out}, 1);
}
- for (int i = 0; i < mem_stats; i++)
- memory_stats_submit((gauge_t)minfo[i].val * 1024, domain, minfo[i].tag);
+ if (min_flt > 0 || maj_flt > 0) {
+ value_t values[] = {
+ {.gauge = (gauge_t)min_flt},
+ {.gauge = (gauge_t)maj_flt},
+ };
+ submit(domain, "ps_pagefaults", NULL, values, STATIC_ARRAY_SIZE(values));
+ }
sfree(minfo);
return 0;
if (disk_err_count == -1) {
ERROR(PLUGIN_NAME
" plugin: failed to get preferred size of disk errors array");
+
+ virErrorPtr err = virGetLastError();
+
+ if (err->code == VIR_ERR_NO_SUPPORT) {
+ ERROR(PLUGIN_NAME
+ " plugin: Disabled unsupported ExtraStats selector: disk_err");
+ extra_stats &= ~(ex_stats_disk_err);
+ }
+
return -1;
}
}
#endif /* HAVE_DISK_ERR */
-static int get_block_stats(struct block_device *block_dev) {
-
+static int get_block_device_stats(struct block_device *block_dev) {
if (!block_dev) {
ERROR(PLUGIN_NAME " plugin: get_block_stats NULL pointer");
return -1;
}
- struct lv_block_info binfo;
+ virDomainBlockInfo binfo;
init_block_info(&binfo);
- if (lv_domain_block_info(block_dev->dom, block_dev->path, &binfo) < 0) {
- ERROR(PLUGIN_NAME " plugin: lv_domain_block_info failed");
+ /* Fetching block info stats only if needed*/
+ if (extra_stats & (ex_stats_disk_allocation | ex_stats_disk_capacity |
+ ex_stats_disk_physical)) {
+ /* Block info statistics can be only fetched from devices with 'source'
+ * defined */
+ if (block_dev->has_source) {
+ if (virDomainGetBlockInfo(block_dev->dom, block_dev->path, &binfo, 0) <
+ 0) {
+ ERROR(PLUGIN_NAME " plugin: virDomainGetBlockInfo failed for path: %s",
+ block_dev->path);
+
+ virErrorPtr err = virGetLastError();
+ if (err->code == VIR_ERR_NO_SUPPORT) {
+
+ if (extra_stats & ex_stats_disk_allocation)
+ ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats "
+ "selector: disk_allocation");
+ if (extra_stats & ex_stats_disk_capacity)
+ ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats "
+ "selector: disk_capacity");
+ if (extra_stats & ex_stats_disk_physical)
+ ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats "
+ "selector: disk_physical");
+
+ extra_stats &= ~(ex_stats_disk_allocation | ex_stats_disk_capacity |
+ ex_stats_disk_physical);
+ }
+
+ return -1;
+ }
+ }
+ }
+
+ struct lv_block_stats bstats;
+ init_block_stats(&bstats);
+
+ if (lv_domain_block_stats(block_dev->dom, block_dev->path, &bstats) < 0) {
+ ERROR(PLUGIN_NAME " plugin: lv_domain_block_stats failed");
return -1;
}
- disk_submit(&binfo, block_dev->dom, block_dev->path);
+ disk_block_stats_submit(&bstats, block_dev->dom, block_dev->path, &binfo);
return 0;
}
if (mount_points_cnt == -1) {
ERROR(PLUGIN_NAME " plugin: virDomainGetFSInfo failed: %d",
mount_points_cnt);
- return mount_points_cnt;
+
+ virErrorPtr err = virGetLastError();
+ if (err->code == VIR_ERR_NO_SUPPORT) {
+ ERROR(PLUGIN_NAME
+ " plugin: Disabled unsupported ExtraStats selector: fs_info");
+ extra_stats &= ~(ex_stats_fs_info);
+ }
+
+ return -1;
}
for (int i = 0; i < mount_points_cnt; ++i) {
}
static int get_job_stats(virDomainPtr domain) {
- int ret = 0;
int job_type = 0;
int nparams = 0;
virTypedParameterPtr params = NULL;
? VIR_DOMAIN_JOB_STATS_COMPLETED
: 0;
- ret = virDomainGetJobStats(domain, &job_type, ¶ms, &nparams, flags);
+ int ret = virDomainGetJobStats(domain, &job_type, ¶ms, &nparams, flags);
if (ret != 0) {
ERROR(PLUGIN_NAME " plugin: virDomainGetJobStats failed: %d", ret);
- return ret;
+
+ virErrorPtr err = virGetLastError();
+ // VIR_ERR_INVALID_ARG returned when VIR_DOMAIN_JOB_STATS_COMPLETED flag is
+ // not supported by driver
+ if (err->code == VIR_ERR_NO_SUPPORT || err->code == VIR_ERR_INVALID_ARG) {
+ if (extra_stats & ex_stats_job_stats_completed)
+ ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats selector: "
+ "job_stats_completed");
+ if (extra_stats & ex_stats_job_stats_background)
+ ERROR(PLUGIN_NAME " plugin: Disabled unsupported ExtraStats selector: "
+ "job_stats_background");
+ extra_stats &=
+ ~(ex_stats_job_stats_completed | ex_stats_job_stats_background);
+ }
+ return -1;
}
DEBUG(PLUGIN_NAME " plugin: job_type=%d nparams=%d", job_type, nparams);
}
virTypedParamsFree(params, nparams);
- return ret;
+ return 0;
}
#endif /* HAVE_JOB_STATS */
* however it doesn't provide a reason for entering particular state.
* We need to get it from virDomainGetState.
*/
- GET_STATS(get_domain_state, "domain reason", domain->ptr);
+ GET_STATS(submit_domain_state, "domain reason", domain->ptr);
#endif
}
memory_submit(domain->ptr, (gauge_t)info.memory * 1024);
- GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
- GET_STATS(get_memory_stats, "memory stats", domain->ptr);
+ if (extra_stats & (ex_stats_vcpu | ex_stats_vcpupin))
+ GET_STATS(get_vcpu_stats, "vcpu stats", domain->ptr, info.nrVirtCpu);
+ if (extra_stats & ex_stats_memory)
+ GET_STATS(get_memory_stats, "memory stats", domain->ptr);
#ifdef HAVE_PERF_STATS
if (extra_stats & ex_stats_perf)
return 0;
}
+static void virt_eventloop_timeout_cb(int timer ATTRIBUTE_UNUSED,
+ void *timer_info) {}
+
static int register_event_impl(void) {
if (virEventRegisterDefaultImpl() < 0) {
virErrorPtr err = virGetLastError();
return -1;
}
+ if (virEventAddTimeout(CDTIME_T_TO_MS(plugin_get_interval()),
+ virt_eventloop_timeout_cb, NULL, NULL) < 0) {
+ virErrorPtr err = virGetLastError();
+ ERROR(PLUGIN_NAME " plugin: virEventAddTimeout failed: %s",
+ err && err->message ? err->message : "Unknown error");
+ return -1;
+ }
+
return 0;
}
}
static int virt_notif_thread_init(virt_notif_thread_t *thread_data) {
- int ret;
-
assert(thread_data != NULL);
- ret = pthread_mutex_init(&thread_data->active_mutex, NULL);
+
+ int ret = pthread_mutex_init(&thread_data->active_mutex, NULL);
if (ret != 0) {
ERROR(PLUGIN_NAME " plugin: Failed to initialize mutex, err %u", ret);
return ret;
return -1;
}
+ DEBUG(PLUGIN_NAME " plugin: starting event loop");
+
virt_notif_thread_set_active(thread_data, 1);
if (pthread_create(&thread_data->event_loop_tid, NULL, event_loop_worker,
thread_data)) {
ERROR(PLUGIN_NAME " plugin: failed event loop thread creation");
+ virt_notif_thread_set_active(thread_data, 0);
virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
+ thread_data->domain_event_cb_id = -1;
return -1;
}
/* stop event loop thread and deregister callback */
static void stop_event_loop(virt_notif_thread_t *thread_data) {
- /* stopping loop and de-registering event handler*/
- virt_notif_thread_set_active(thread_data, 0);
- if (conn != NULL && thread_data->domain_event_cb_id != -1)
- virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
- if (pthread_join(notif_thread.event_loop_tid, NULL) != 0)
- ERROR(PLUGIN_NAME " plugin: stopping notification thread failed");
+ DEBUG(PLUGIN_NAME " plugin: stopping event loop");
+
+ /* Stopping loop */
+ if (virt_notif_thread_is_active(thread_data)) {
+ virt_notif_thread_set_active(thread_data, 0);
+ if (pthread_join(notif_thread.event_loop_tid, NULL) != 0)
+ ERROR(PLUGIN_NAME " plugin: stopping notification thread failed");
+ }
+
+ /* ... and de-registering event handler */
+ if (conn != NULL && thread_data->domain_event_cb_id != -1) {
+ virConnectDomainEventDeregisterAny(conn, thread_data->domain_event_cb_id);
+ thread_data->domain_event_cb_id = -1;
+ }
}
static int persistent_domains_state_notification(void) {
}
static int lv_read(user_data_t *ud) {
- time_t t;
- struct lv_read_instance *inst = NULL;
- struct lv_read_state *state = NULL;
-
if (ud->data == NULL) {
ERROR(PLUGIN_NAME " plugin: NULL userdata");
return -1;
}
- inst = ud->data;
- state = &inst->read_state;
-
- bool reconnect = conn == NULL ? true : false;
- /* event implementation must be registered before connection is opened */
- if (inst->id == 0) {
- if (!persistent_notification && reconnect)
- if (register_event_impl() != 0)
- return -1;
+ struct lv_read_instance *inst = ud->data;
+ struct lv_read_state *state = &inst->read_state;
+ if (inst->id == 0)
if (lv_connect() < 0)
return -1;
- if (!persistent_notification && reconnect && conn != NULL)
- if (start_event_loop(¬if_thread) != 0)
- return -1;
+ /* Wait until inst#0 establish connection */
+ if (conn == NULL) {
+ DEBUG(PLUGIN_NAME " plugin#%s: Wait until inst#0 establish connection",
+ inst->tag);
+ return 0;
}
+ int ret = virConnectIsAlive(conn);
+ if (ret == 0) { /* Connection lost */
+ if (inst->id == 0) {
+ c_complain(LOG_ERR, &conn_complain,
+ PLUGIN_NAME " plugin: Lost connection.");
+
+ if (!persistent_notification)
+ stop_event_loop(¬if_thread);
+
+ lv_disconnect();
+ last_refresh = 0;
+ }
+ return -1;
+ }
+
+ time_t t;
time(&t);
/* Need to refresh domain or device lists? */
if (dom->active)
status = get_domain_metrics(dom);
#ifdef HAVE_DOM_REASON
- else
- status = get_domain_state(dom->ptr);
+ else if (extra_stats & ex_stats_domain_state)
+ status = submit_domain_state(dom->ptr);
#endif
if (status != 0)
/* Get block device stats for each domain. */
for (int i = 0; i < state->nr_block_devices; ++i) {
- int status = get_block_stats(&state->block_devices[i]);
+ int status = get_block_device_stats(&state->block_devices[i]);
if (status != 0)
ERROR(PLUGIN_NAME
" plugin: failed to get stats for block device (%s) in domain %s",
memset(lv_ud, 0, sizeof(*lv_ud));
- snprintf(inst->tag, sizeof(inst->tag), "%s-%" PRIsz, PLUGIN_NAME, i);
+ ssnprintf(inst->tag, sizeof(inst->tag), "%s-%" PRIsz, PLUGIN_NAME, i);
inst->id = i;
user_data_t *ud = &(lv_ud->ud);
if (lv_init_ignorelists() != 0)
return -1;
- /* event implementation must be registered before connection is opened */
if (!persistent_notification)
- if (register_event_impl() != 0)
+ if (virt_notif_thread_init(¬if_thread) != 0)
return -1;
- if (lv_connect() != 0)
- return -1;
-
- DEBUG(PLUGIN_NAME " plugin: starting event loop");
-
- if (!persistent_notification) {
- virt_notif_thread_init(¬if_thread);
- if (start_event_loop(¬if_thread) != 0)
- return -1;
- }
+ lv_connect();
DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances);
goto done;
}
- snprintf(xpath_str, sizeof(xpath_str), "/domain/metadata/%s:%s/text()",
- METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_ELEMENT);
+ ssnprintf(xpath_str, sizeof(xpath_str), "/domain/metadata/%s:%s/text()",
+ METADATA_VM_PARTITION_PREFIX, METADATA_VM_PARTITION_ELEMENT);
xpath_obj = xmlXPathEvalExpression((xmlChar *)xpath_str, xpath_ctx);
if (xpath_obj == NULL) {
ERROR(PLUGIN_NAME " plugin: xmlXPathEval(%s) failed on domain %s",
static void lv_add_block_devices(struct lv_read_state *state, virDomainPtr dom,
const char *domname,
xmlXPathContextPtr xpath_ctx) {
- const char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
- if (blockdevice_format == source)
- bd_xmlpath = "/domain/devices/disk/source[@dev]";
-
xmlXPathObjectPtr xpath_obj =
- xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx);
+ xmlXPathEval((const xmlChar *)"/domain/devices/disk", xpath_ctx);
- if (xpath_obj == NULL)
+ if (xpath_obj == NULL) {
+ DEBUG(PLUGIN_NAME " plugin: no disk xpath-object found for domain %s",
+ domname);
return;
+ }
if (xpath_obj->type != XPATH_NODESET || xpath_obj->nodesetval == NULL) {
- xmlXPathFreeObject(xpath_obj);
- return;
+ DEBUG(PLUGIN_NAME " plugin: no disk node found for domain %s", domname);
+ goto cleanup;
}
- for (int j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
- xmlNodePtr node = xpath_obj->nodesetval->nodeTab[j];
- if (!node)
- continue;
+ xmlNodeSetPtr xml_block_devices = xpath_obj->nodesetval;
+ for (int i = 0; i < xml_block_devices->nodeNr; ++i) {
+ xmlNodePtr xml_device = xpath_obj->nodesetval->nodeTab[i];
+ char *path_str = NULL;
+ char *source_str = NULL;
- char *path = (char *)xmlGetProp(node, (xmlChar *)"dev");
- if (!path)
+ if (!xml_device)
continue;
- if (ignore_device_match(il_block_devices, domname, path) == 0)
- add_block_device(state, dom, path);
+ /* Fetching path and source for block device */
+ for (xmlNodePtr child = xml_device->children; child; child = child->next) {
+ if (child->type != XML_ELEMENT_NODE)
+ continue;
+
+ /* we are interested only in either "target" or "source" elements */
+ if (xmlStrEqual(child->name, (const xmlChar *)"target"))
+ path_str = (char *)xmlGetProp(child, (const xmlChar *)"dev");
+ else if (xmlStrEqual(child->name, (const xmlChar *)"source")) {
+ /* name of the source is located in "dev" or "file" element (it depends
+ * on type of source). Trying "dev" at first*/
+ source_str = (char *)xmlGetProp(child, (const xmlChar *)"dev");
+ if (!source_str)
+ source_str = (char *)xmlGetProp(child, (const xmlChar *)"file");
+ }
+ /* ignoring any other element*/
+ }
+
+ /* source_str will be interpreted as a device path if blockdevice_format
+ * param is set to 'source'. */
+ const char *device_path =
+ (blockdevice_format == source) ? source_str : path_str;
+
+ if (!device_path) {
+ /* no path found and we can't add block_device without it */
+ WARNING(PLUGIN_NAME " plugin: could not generate device path for disk in "
+ "domain %s - disk device will be ignored in reports",
+ domname);
+ goto cont;
+ }
+
+ if (ignore_device_match(il_block_devices, domname, device_path) == 0) {
+ /* we only have to store information whether 'source' exists or not */
+ bool has_source = (source_str != NULL) ? true : false;
+
+ add_block_device(state, dom, device_path, has_source);
+ }
- xmlFree(path);
+ cont:
+ if (path_str)
+ xmlFree(path_str);
+
+ if (source_str)
+ xmlFree(source_str);
}
+
+cleanup:
xmlXPathFreeObject(xpath_obj);
}
for (int j = 0; j < xml_interfaces->nodeNr; ++j) {
char *path = NULL;
char *address = NULL;
+ const int itf_number = j + 1;
xmlNodePtr xml_interface = xml_interfaces->nodeTab[j];
if (!xml_interface)
}
}
- if ((ignore_device_match(il_interface_devices, domname, path) == 0 &&
- ignore_device_match(il_interface_devices, domname, address) == 0)) {
- add_interface_device(state, dom, path, address, j + 1);
+ bool device_ignored = false;
+ switch (interface_format) {
+ case if_name:
+ if (ignore_device_match(il_interface_devices, domname, path) != 0)
+ device_ignored = true;
+ break;
+ case if_address:
+ if (ignore_device_match(il_interface_devices, domname, address) != 0)
+ device_ignored = true;
+ break;
+ case if_number: {
+ char number_string[4];
+ ssnprintf(number_string, sizeof(number_string), "%d", itf_number);
+ if (ignore_device_match(il_interface_devices, domname, number_string) !=
+ 0)
+ device_ignored = true;
+ } break;
+ default:
+ ERROR(PLUGIN_NAME " plugin: Unknown interface_format option: %d",
+ interface_format);
}
+ if (!device_ignored)
+ add_interface_device(state, dom, path, address, itf_number);
+
if (path)
xmlFree(path);
if (address)
xmlXPathFreeObject(xpath_obj);
}
+static bool is_domain_ignored(virDomainPtr dom) {
+ const char *domname = virDomainGetName(dom);
+
+ if (domname == NULL) {
+ VIRT_ERROR(conn, "virDomainGetName failed, ignoring domain");
+ return true;
+ }
+
+ if (ignorelist_match(il_domains, domname) != 0) {
+ DEBUG(PLUGIN_NAME
+ " plugin: ignoring domain '%s' because of ignorelist option",
+ domname);
+ return true;
+ }
+
+ return false;
+}
+
static int refresh_lists(struct lv_read_instance *inst) {
struct lv_read_state *state = &inst->read_state;
int n;
#ifdef HAVE_LIST_ALL_DOMAINS
for (int i = 0; i < m; ++i)
- if (add_domain(state, domains_inactive[i], 0) < 0) {
- ERROR(PLUGIN_NAME " plugin: malloc failed.");
+ if (is_domain_ignored(domains_inactive[i]) ||
+ add_domain(state, domains_inactive[i], 0) < 0) {
+ /* domain ignored or failed during adding to domains list*/
virDomainFree(domains_inactive[i]);
domains_inactive[i] = NULL;
continue;
}
#endif
- if (add_domain(state, dom, 1) < 0) {
+ if (is_domain_ignored(dom) || add_domain(state, dom, 1) < 0) {
/*
+ * domain ignored or failed during adding to domains list
+ *
* When domain is already tracked, then there is
* no problem with memory handling (will be freed
* with the rest of domains cached data)
* before adding domain to track) we have to take
* care it ourselves and call virDomainFree
*/
- ERROR(PLUGIN_NAME " plugin: malloc failed.");
virDomainFree(dom);
continue;
}
continue;
}
- if (ignorelist_match(il_domains, domname) != 0)
- continue;
-
/* Get a list of devices for this domain. */
xmlDocPtr xml_doc = NULL;
xmlXPathContextPtr xpath_ctx = NULL;
static int add_domain(struct lv_read_state *state, virDomainPtr dom,
bool active) {
-
int new_size = sizeof(state->domains[0]) * (state->nr_domains + 1);
domain_t *new_ptr = realloc(state->domains, new_size);
- if (new_ptr == NULL)
+ if (new_ptr == NULL) {
+ ERROR(PLUGIN_NAME " plugin: realloc failed in add_domain()");
return -1;
+ }
state->domains = new_ptr;
state->domains[state->nr_domains].ptr = dom;
}
static int add_block_device(struct lv_read_state *state, virDomainPtr dom,
- const char *path) {
+ const char *path, bool has_source) {
char *path_copy = strdup(path);
if (!path_copy)
state->block_devices = new_ptr;
state->block_devices[state->nr_block_devices].dom = dom;
state->block_devices[state->nr_block_devices].path = path_copy;
+ state->block_devices[state->nr_block_devices].has_source = has_source;
return state->nr_block_devices++;
}
}
char number_string[21];
- snprintf(number_string, sizeof(number_string), "interface-%u", number);
+ ssnprintf(number_string, sizeof(number_string), "interface-%u", number);
char *number_copy = strdup(number_string);
if (!number_copy) {
sfree(path_copy);
ERROR(PLUGIN_NAME " plugin: malloc failed.");
return 0;
}
- snprintf(name, n, "%s:%s", domname, devpath);
+ ssnprintf(name, n, "%s:%s", domname, devpath);
int r = ignorelist_match(il, name);
sfree(name);
return r;
lv_fini_instance(i);
}
- DEBUG(PLUGIN_NAME " plugin: stopping event loop");
-
if (!persistent_notification)
stop_event_loop(¬if_thread);
}
void module_register(void) {
- plugin_register_config(PLUGIN_NAME, lv_config, config_keys, NR_CONFIG_KEYS);
+ plugin_register_complex_config("virt", lv_config);
plugin_register_init(PLUGIN_NAME, lv_init);
plugin_register_shutdown(PLUGIN_NAME, lv_shutdown);
}
static void submit_two(const char *plugin_instance, const char *type,
const char *type_instance, derive_t c0, derive_t c1) {
value_t values[] = {
- {.derive = c0}, {.derive = c1},
+ {.derive = c0},
+ {.derive = c1},
};
submit(plugin_instance, type, type_instance, values,
derive_t tx) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.derive = rx}, {.derive = tx},
+ {.derive = rx},
+ {.derive = tx},
};
vl.values = values;
gauge_t lnum) {
value_list_t vl = VALUE_LIST_INIT;
value_t values[] = {
- {.gauge = snum}, {.gauge = mnum}, {.gauge = lnum},
+ {.gauge = snum},
+ {.gauge = mnum},
+ {.gauge = lnum},
};
vl.values = values;
* Based on the write_http plugin.
**/
-/* write_graphite plugin configuation example
+/* write_graphite plugin configuration example
*
* <Plugin write_graphite>
* <Carbon>
* LogSendErrors true
* Prefix "collectd"
* UseTags true
+ * ReverseHost false
* </Carbon>
* </Plugin>
*/
cf_util_get_flag(child, &cb->format_flags, GRAPHITE_DROP_DUPE_FIELDS);
else if (strcasecmp("UseTags", child->key) == 0)
cf_util_get_flag(child, &cb->format_flags, GRAPHITE_USE_TAGS);
+ else if (strcasecmp("ReverseHost", child->key) == 0)
+ cf_util_get_flag(child, &cb->format_flags, GRAPHITE_REVERSE_HOST);
else if (strcasecmp("EscapeCharacter", child->key) == 0)
config_set_char(&cb->escape_char, child);
else {
plugin_register_write(callback_name, wg_write,
&(user_data_t){
- .data = cb, .free_func = wg_callback_free,
+ .data = cb,
+ .free_func = wg_callback_free,
});
plugin_register_flush(callback_name, wg_flush, &(user_data_t){.data = cb});
callback_name, cb->location);
user_data_t user_data = {
- .data = cb, .free_func = wh_callback_free,
+ .data = cb,
+ .free_func = wh_callback_free,
};
if (cb->send_metrics) {
#define KAFKA_RANDOM_KEY_BUFFER \
(char[KAFKA_RANDOM_KEY_SIZE]) { "" }
static char *kafka_random_key(char buffer[static KAFKA_RANDOM_KEY_SIZE]) {
- snprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u());
+ ssnprintf(buffer, KAFKA_RANDOM_KEY_SIZE, "%08" PRIX32, cdrand_u());
return buffer;
}
rd_kafka_topic_conf_set_partitioner_cb(tctx->conf, kafka_partition);
rd_kafka_topic_conf_set_opaque(tctx->conf, tctx);
- snprintf(callback_name, sizeof(callback_name), "write_kafka/%s",
- tctx->topic_name);
+ ssnprintf(callback_name, sizeof(callback_name), "write_kafka/%s",
+ tctx->topic_name);
- status = plugin_register_write(
- callback_name, kafka_write,
- &(user_data_t){
- .data = tctx, .free_func = kafka_topic_context_free,
- });
+ status = plugin_register_write(callback_name, kafka_write,
+ &(user_data_t){
+ .data = tctx,
+ .free_func = kafka_topic_context_free,
+ });
if (status != 0) {
WARNING("write_kafka plugin: plugin_register_write (\"%s\") "
"failed with status %i.",
snprintf(cb_name, sizeof(cb_name), "write_mongodb/%s", node->name);
- status =
- plugin_register_write(cb_name, wm_write,
- &(user_data_t){
- .data = node, .free_func = wm_config_free,
- });
+ status = plugin_register_write(cb_name, wm_write,
+ &(user_data_t){
+ .data = node,
+ .free_func = wm_config_free,
+ });
INFO("write_mongodb plugin: registered write plugin %s %d", cb_name,
status);
}
#define LABEL_BUFFER_SIZE (LABEL_KEY_SIZE + LABEL_VALUE_SIZE + 4)
char *labels[3] = {
- (char[LABEL_BUFFER_SIZE]){0}, (char[LABEL_BUFFER_SIZE]){0},
+ (char[LABEL_BUFFER_SIZE]){0},
+ (char[LABEL_BUFFER_SIZE]){0},
(char[LABEL_BUFFER_SIZE]){0},
};
* know that they are sane. */
for (size_t i = 0; i < m->n_label; i++) {
char value[LABEL_VALUE_SIZE];
- snprintf(labels[i], LABEL_BUFFER_SIZE, "%s=\"%s\"", m->label[i]->name,
- escape_label_value(value, sizeof(value), m->label[i]->value));
+ ssnprintf(labels[i], LABEL_BUFFER_SIZE, "%s=\"%s\"", m->label[i]->name,
+ escape_label_value(value, sizeof(value), m->label[i]->value));
}
strjoin(buffer, buffer_size, labels, m->n_label, ",");
while (c_avl_iterator_next(iter, (void *)&unused_name, (void *)&fam) == 0) {
char line[1024]; /* 4x DATA_MAX_NAME_LEN? */
- snprintf(line, sizeof(line), "# HELP %s %s\n", fam->name, fam->help);
+ ssnprintf(line, sizeof(line), "# HELP %s %s\n", fam->name, fam->help);
buffer->append(buffer, strlen(line), (uint8_t *)line);
- snprintf(line, sizeof(line), "# TYPE %s %s\n", fam->name,
- (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE)
- ? "gauge"
- : "counter");
+ ssnprintf(line, sizeof(line), "# TYPE %s %s\n", fam->name,
+ (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE)
+ ? "gauge"
+ : "counter");
buffer->append(buffer, strlen(line), (uint8_t *)line);
for (size_t i = 0; i < fam->n_metric; i++) {
char timestamp_ms[24] = "";
if (m->has_timestamp_ms)
- snprintf(timestamp_ms, sizeof(timestamp_ms), " %" PRIi64,
- m->timestamp_ms);
+ ssnprintf(timestamp_ms, sizeof(timestamp_ms), " %" PRIi64,
+ m->timestamp_ms);
if (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__GAUGE)
- snprintf(line, sizeof(line), "%s{%s} " GAUGE_FORMAT "%s\n", fam->name,
- format_labels(labels, sizeof(labels), m), m->gauge->value,
- timestamp_ms);
+ ssnprintf(line, sizeof(line), "%s{%s} " GAUGE_FORMAT "%s\n", fam->name,
+ format_labels(labels, sizeof(labels), m), m->gauge->value,
+ timestamp_ms);
else /* if (fam->type == IO__PROMETHEUS__CLIENT__METRIC_TYPE__COUNTER) */
- snprintf(line, sizeof(line), "%s{%s} %.0f%s\n", fam->name,
- format_labels(labels, sizeof(labels), m), m->counter->value,
- timestamp_ms);
+ ssnprintf(line, sizeof(line), "%s{%s} %.0f%s\n", fam->name,
+ format_labels(labels, sizeof(labels), m), m->counter->value,
+ timestamp_ms);
buffer->append(buffer, strlen(line), (uint8_t *)line);
}
c_avl_iterator_destroy(iter);
char server[1024];
- snprintf(server, sizeof(server), "\n# collectd/write_prometheus %s at %s\n",
- PACKAGE_VERSION, hostname_g);
+ ssnprintf(server, sizeof(server), "\n# collectd/write_prometheus %s at %s\n",
+ PACKAGE_VERSION, hostname_g);
buffer->append(buffer, strlen(server), (uint8_t *)server);
pthread_mutex_unlock(&metrics_lock);
msg->name = name;
char help[1024];
- snprintf(
+ ssnprintf(
help, sizeof(help),
"write_prometheus plugin: '%s' Type: '%s', Dstype: '%s', Dsname: '%s'",
vl->plugin, vl->type, DS_TYPE_TO_STRING(ds->ds[ds_index].type),
int status = c_avl_insert(metrics, fam->name, fam);
if (status != 0) {
- ERROR("write_prometheus plugin: Adding \"%s\" failed.", name);
+ ERROR("write_prometheus plugin: Adding \"%s\" failed.", fam->name);
metric_family_destroy(fam);
return NULL;
}
static int prom_open_socket(int addrfamily) {
/* {{{ */
char service[NI_MAXSERV];
- snprintf(service, sizeof(service), "%hu", httpd_port);
+ ssnprintf(service, sizeof(service), "%hu", httpd_port);
struct addrinfo *res;
int status = getaddrinfo(httpd_host, service,
status = FORMAT_VL(ident, sizeof(ident), vl);
if (status != 0)
return status;
- snprintf(key, sizeof(key), "%s%s",
- (node->prefix != NULL) ? node->prefix : REDIS_DEFAULT_PREFIX, ident);
- snprintf(time, sizeof(time), "%.9f", CDTIME_T_TO_DOUBLE(vl->time));
+ ssnprintf(key, sizeof(key), "%s%s",
+ (node->prefix != NULL) ? node->prefix : REDIS_DEFAULT_PREFIX,
+ ident);
+ ssnprintf(time, sizeof(time), "%.9f", CDTIME_T_TO_DOUBLE(vl->time));
value_size = sizeof(value);
value_ptr = &value[0];
if (status == 0) {
char cb_name[sizeof("write_redis/") + DATA_MAX_NAME_LEN];
- snprintf(cb_name, sizeof(cb_name), "write_redis/%s", node->name);
+ ssnprintf(cb_name, sizeof(cb_name), "write_redis/%s", node->name);
- status =
- plugin_register_write(cb_name, wr_write,
- &(user_data_t){
- .data = node, .free_func = wr_config_free,
- });
+ status = plugin_register_write(cb_name, wr_write,
+ &(user_data_t){
+ .data = node,
+ .free_func = wr_config_free,
+ });
}
if (status != 0)
vl->type_instance);
if (host->always_append_ds || (ds->ds_num > 1)) {
if (host->event_service_prefix == NULL)
- snprintf(service_buffer, sizeof(service_buffer), "%s/%s", &name_buffer[1],
- ds->ds[index].name);
+ ssnprintf(service_buffer, sizeof(service_buffer), "%s/%s",
+ &name_buffer[1], ds->ds[index].name);
else
- snprintf(service_buffer, sizeof(service_buffer), "%s%s/%s",
- host->event_service_prefix, &name_buffer[1], ds->ds[index].name);
+ ssnprintf(service_buffer, sizeof(service_buffer), "%s%s/%s",
+ host->event_service_prefix, &name_buffer[1],
+ ds->ds[index].name);
} else {
if (host->event_service_prefix == NULL)
sstrncpy(service_buffer, &name_buffer[1], sizeof(service_buffer));
else
- snprintf(service_buffer, sizeof(service_buffer), "%s%s",
- host->event_service_prefix, &name_buffer[1]);
+ ssnprintf(service_buffer, sizeof(service_buffer), "%s%s",
+ host->event_service_prefix, &name_buffer[1]);
}
riemann_event_set(
if ((ds->ds[index].type != DS_TYPE_GAUGE) && (rates != NULL)) {
char ds_type[DATA_MAX_NAME_LEN];
- snprintf(ds_type, sizeof(ds_type), "%s:rate",
- DS_TYPE_TO_STRING(ds->ds[index].type));
+ ssnprintf(ds_type, sizeof(ds_type), "%s:rate",
+ DS_TYPE_TO_STRING(ds->ds[index].type));
riemann_event_string_attribute_add(event, "ds_type", ds_type);
} else {
riemann_event_string_attribute_add(event, "ds_type",
{
char ds_index[DATA_MAX_NAME_LEN];
- snprintf(ds_index, sizeof(ds_index), "%" PRIsz, index);
+ ssnprintf(ds_index, sizeof(ds_index), "%" PRIsz, index);
riemann_event_string_attribute_add(event, "ds_index", ds_index);
}
RIEMANN_EVENT_FIELD_NONE);
}
+ if (vl->meta) {
+ char **toc;
+ int n = meta_data_toc(vl->meta, &toc);
+
+ for (int i = 0; i < n; i++) {
+ char *key = toc[i];
+ char *value;
+
+ if (0 == meta_data_as_string(vl->meta, key, &value)) {
+ riemann_event_string_attribute_add(event, key, value);
+ free(value);
+ }
+ }
+
+ free(toc);
+ }
+
DEBUG("write_riemann plugin: Successfully created message for metric: "
"host = \"%s\", service = \"%s\"",
event->host, event->service);
return status;
}
- snprintf(callback_name, sizeof(callback_name), "write_riemann/%s",
- host->name);
+ ssnprintf(callback_name, sizeof(callback_name), "write_riemann/%s",
+ host->name);
user_data_t ud = {.data = host, .free_func = wrr_free};
continue;
status = add_str_to_list(&sensu_tags_arr, tmp);
+ DEBUG("write_sensu plugin: Got tag: %s", tmp);
sfree(tmp);
if (status != 0)
continue;
- DEBUG("write_sensu plugin: Got tag: %s", tmp);
} else {
WARNING("write_sensu plugin: Ignoring unknown "
"configuration option \"%s\" at top level.",
return NULL;
}
- status = snprintf(authorization_header, sizeof(authorization_header),
- "Authorization: Bearer %s", access_token);
+ status = ssnprintf(authorization_header, sizeof(authorization_header),
+ "Authorization: Bearer %s", access_token);
if ((status < 1) || ((size_t)status >= sizeof(authorization_header)))
return NULL;
if (err == NULL) {
strncpy(buffer, "Unknown error (API error is NULL)", buffer_size);
} else if (err->message == NULL) {
- snprintf(buffer, buffer_size, "API error %d", err->code);
+ ssnprintf(buffer, buffer_size, "API error %d", err->code);
} else {
- snprintf(buffer, buffer_size, "API error %d: %s", err->code, err->message);
+ ssnprintf(buffer, buffer_size, "API error %d: %s", err->code, err->message);
}
return buffer;
static int wg_call_metricdescriptor_create(wg_callback_t *cb,
char const *payload) {
char url[1024];
- snprintf(url, sizeof(url), "%s/projects/%s/metricDescriptors", cb->url,
- cb->project);
+ ssnprintf(url, sizeof(url), "%s/projects/%s/metricDescriptors", cb->url,
+ cb->project);
wg_memory_t response = {0};
int status = do_post(cb, url, payload, &response);
static int wg_call_timeseries_write(wg_callback_t *cb, char const *payload) {
char url[1024];
- snprintf(url, sizeof(url), "%s/projects/%s/timeSeries", cb->url, cb->project);
+ ssnprintf(url, sizeof(url), "%s/projects/%s/timeSeries", cb->url,
+ cb->project);
wg_memory_t response = {0};
int status = do_post(cb, url, payload, &response);
--- /dev/null
+/**
+ * collectd - src/write_syslog.c
+ * Copyright (C) 2012 Pierre-Yves Ritschard
+ * Copyright (C) 2011 Scott Sanders
+ * Copyright (C) 2009 Paul Sadauskas
+ * Copyright (C) 2009 Doug MacEachern
+ * Copyright (C) 2007-2012 Florian octo Forster
+ * Copyright (C) 2013-2014 Limelight Networks, Inc.
+ * Copyright (C) 2019 Shirly Radco
+ * 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
+ *
+ * Based on the write_graphite plugin. Authors:
+ * Florian octo Forster <octo at collectd.org>
+ * Doug MacEachern <dougm at hyperic.com>
+ * Paul Sadauskas <psadauskas at gmail.com>
+ * Scott Sanders <scott at jssjr.com>
+ * Pierre-Yves Ritschard <pyr at spootnik.org>
+ * Based on the write_tsdb plugin. Authors:
+ * Brett Hawn <bhawn at llnw.com>
+ * Kevin Bowling <kbowling@llnw.com>
+ * write_syslog. Authors:
+ * Shirly Radco <sradco@redhat.com>
+ **/
+
+/* write_syslog plugin configuration example
+ *
+ * <Plugin write_syslog>
+ * <Node>
+ * Host "localhost"
+ * Port "44514"
+ * Prefix "collectd"
+ * MessageFormat "human"
+ * HostTags "["prefix1" "example1"="example1_v"]
+ * </Node>
+ * </Plugin>
+ *
+ */
+
+#include "collectd.h"
+#include "utils/common/common.h"
+
+#include "plugin.h"
+#include "utils_cache.h"
+#include "utils_random.h"
+
+#include <netdb.h>
+
+#define WS_DEFAULT_NODE "localhost"
+
+#define WS_DEFAULT_SERVICE "44514"
+
+#define WS_DEFAULT_FORMAT "human"
+
+#define WS_DEFAULT_PREFIX "collectd"
+
+#define WS_DEFAULT_ESCAPE '.'
+
+/* Ethernet - (IPv6 + TCP) = 1500 - (40 + 32) = 1428 */
+#define WS_SEND_BUF_SIZE 1428
+
+/*
+ * Private variables
+ */
+struct ws_callback {
+ struct addrinfo *ai;
+ cdtime_t ai_last_update;
+ int sock_fd;
+
+ char *node;
+ char *service;
+ char *host_tags;
+ char *msg_format;
+ char *metrics_prefix;
+ bool store_rates;
+ bool always_append_ds;
+
+ char send_buf[WS_SEND_BUF_SIZE];
+ size_t send_buf_free;
+ size_t send_buf_fill;
+ cdtime_t send_buf_init_time;
+
+ pthread_mutex_t send_lock;
+
+ bool connect_failed_log_enabled;
+ int connect_dns_failed_attempts_remaining;
+ cdtime_t next_random_ttl;
+};
+
+static cdtime_t resolve_interval;
+static cdtime_t resolve_jitter;
+
+/*
+ * Functions
+ */
+static void ws_reset_buffer(struct ws_callback *cb) {
+ memset(cb->send_buf, 0, sizeof(cb->send_buf));
+ cb->send_buf_free = sizeof(cb->send_buf);
+ cb->send_buf_fill = 0;
+ cb->send_buf_init_time = cdtime();
+}
+
+static int ws_send_buffer(struct ws_callback *cb) {
+ ssize_t status = 0;
+
+ status = swrite(cb->sock_fd, cb->send_buf, strlen(cb->send_buf));
+ if (status != 0) {
+ ERROR("write_syslog plugin: send failed with status %zi (%s)", status,
+ STRERRNO);
+
+ if (cb->sock_fd > 0) {
+ close(cb->sock_fd);
+ cb->sock_fd = -1;
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/* NOTE: You must hold cb->send_lock when calling this function! */
+static int ws_flush_nolock(cdtime_t timeout, struct ws_callback *cb) {
+ int status;
+
+ DEBUG("write_syslog plugin: ws_flush_nolock: timeout = %.3f; "
+ "send_buf_fill = %" PRIsz ";",
+ (double)timeout, cb->send_buf_fill);
+
+ /* timeout == 0 => flush unconditionally */
+ if (timeout > 0) {
+ cdtime_t now;
+
+ now = cdtime();
+ if ((cb->send_buf_init_time + timeout) > now)
+ return 0;
+ }
+
+ if (cb->send_buf_fill == 0) {
+ cb->send_buf_init_time = cdtime();
+ return 0;
+ }
+
+ status = ws_send_buffer(cb);
+ ws_reset_buffer(cb);
+
+ return status;
+}
+
+static cdtime_t new_random_ttl(void) {
+ if (resolve_jitter == 0)
+ return 0;
+
+ return (cdtime_t)cdrand_range(0, (long)resolve_jitter);
+}
+
+static int ws_callback_init(struct ws_callback *cb) {
+ int status;
+ cdtime_t now;
+
+ const char *node = cb->node ? cb->node : WS_DEFAULT_NODE;
+ const char *service = cb->service ? cb->service : WS_DEFAULT_SERVICE;
+
+ if (cb->sock_fd > 0)
+ return 0;
+
+ now = cdtime();
+ if (cb->ai) {
+ /* When we are here, we still have the IP in cache.
+ * If we have remaining attempts without calling the DNS, we update the
+ * last_update date so we keep the info until next time.
+ * If there is no more attempts, we need to flush the cache.
+ */
+
+ if ((cb->ai_last_update + resolve_interval + cb->next_random_ttl) < now) {
+ cb->next_random_ttl = new_random_ttl();
+ if (cb->connect_dns_failed_attempts_remaining > 0) {
+ /* Warning : this is run under send_lock mutex.
+ * This is why we do not use another mutex here.
+ * */
+ cb->ai_last_update = now;
+ cb->connect_dns_failed_attempts_remaining--;
+ } else {
+ freeaddrinfo(cb->ai);
+ cb->ai = NULL;
+ }
+ }
+ }
+
+ if (cb->ai == NULL) {
+ if ((cb->ai_last_update + resolve_interval + cb->next_random_ttl) >= now) {
+ DEBUG("write_syslog plugin: too many getaddrinfo(%s, %s) failures", node,
+ service);
+ return -1;
+ }
+ cb->ai_last_update = now;
+ cb->next_random_ttl = new_random_ttl();
+
+ struct addrinfo ai_hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_ADDRCONFIG,
+ .ai_socktype = SOCK_STREAM,
+ };
+
+ status = getaddrinfo(node, service, &ai_hints, &cb->ai);
+ if (status != 0) {
+ if (cb->ai) {
+ freeaddrinfo(cb->ai);
+ cb->ai = NULL;
+ }
+ if (cb->connect_failed_log_enabled) {
+ ERROR("write_syslog plugin: getaddrinfo(%s, %s) failed: %s", node,
+ service, gai_strerror(status));
+ cb->connect_failed_log_enabled = 0;
+ }
+ return -1;
+ }
+ }
+
+ assert(cb->ai != NULL);
+ for (struct addrinfo *ai = cb->ai; ai != NULL; ai = ai->ai_next) {
+ cb->sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (cb->sock_fd < 0)
+ continue;
+
+ set_sock_opts(cb->sock_fd);
+
+ status = connect(cb->sock_fd, ai->ai_addr, ai->ai_addrlen);
+ if (status != 0) {
+ close(cb->sock_fd);
+ cb->sock_fd = -1;
+ continue;
+ }
+
+ break;
+ }
+
+ if (cb->sock_fd < 0) {
+ ERROR("write_syslog plugin: Connecting to %s:%s failed. "
+ "The last error was: %s",
+ node, service, STRERRNO);
+ return -1;
+ }
+
+ if (cb->connect_failed_log_enabled == 0) {
+ INFO("write_syslog plugin: Connecting to %s:%s succeeded.", node, service);
+ cb->connect_failed_log_enabled = 1;
+ }
+ cb->connect_dns_failed_attempts_remaining = 1;
+
+ ws_reset_buffer(cb);
+
+ return 0;
+}
+
+static void ws_callback_free(void *data) {
+ struct ws_callback *cb;
+
+ if (data == NULL)
+ return;
+
+ cb = data;
+
+ pthread_mutex_lock(&cb->send_lock);
+
+ ws_flush_nolock(0, cb);
+
+ close(cb->sock_fd);
+ cb->sock_fd = -1;
+
+ sfree(cb->node);
+ sfree(cb->service);
+ sfree(cb->host_tags);
+ sfree(cb->msg_format);
+ sfree(cb->metrics_prefix);
+
+ pthread_mutex_unlock(&cb->send_lock);
+ pthread_mutex_destroy(&cb->send_lock);
+
+ sfree(cb);
+}
+
+static int ws_flush(cdtime_t timeout,
+ const char *identifier __attribute__((unused)),
+ user_data_t *user_data) {
+ struct ws_callback *cb;
+ int status;
+
+ if (user_data == NULL)
+ return -EINVAL;
+
+ cb = user_data->data;
+
+ pthread_mutex_lock(&cb->send_lock);
+
+ if (cb->sock_fd < 0) {
+ status = ws_callback_init(cb);
+ if (status != 0) {
+ ERROR("write_syslog plugin: ws_callback_init failed.");
+ pthread_mutex_unlock(&cb->send_lock);
+ return -1;
+ }
+ }
+
+ status = ws_flush_nolock(timeout, cb);
+ pthread_mutex_unlock(&cb->send_lock);
+
+ return status;
+}
+
+static int ws_format_values(char *ret, size_t ret_len, int ds_num,
+ const data_set_t *ds, const value_list_t *vl,
+ bool store_rates) {
+ size_t offset = 0;
+ int status;
+ gauge_t *rates = NULL;
+
+ assert(strcmp(ds->type, vl->type) == 0);
+
+ memset(ret, 0, ret_len);
+
+#define BUFFER_ADD(...) \
+ do { \
+ status = snprintf(ret + offset, ret_len - offset, __VA_ARGS__); \
+ if (status < 1) { \
+ sfree(rates); \
+ return -1; \
+ } else if (((size_t)status) >= (ret_len - offset)) { \
+ sfree(rates); \
+ return -1; \
+ } else \
+ offset += ((size_t)status); \
+ } while (0)
+
+ if (ds->ds[ds_num].type == DS_TYPE_GAUGE)
+ BUFFER_ADD(GAUGE_FORMAT, vl->values[ds_num].gauge);
+ else if (store_rates) {
+ if (rates == NULL)
+ rates = uc_get_rate(ds, vl);
+ if (rates == NULL) {
+ WARNING("format_values: "
+ "uc_get_rate failed.");
+ return -1;
+ }
+ BUFFER_ADD(GAUGE_FORMAT, rates[ds_num]);
+ } else if (ds->ds[ds_num].type == DS_TYPE_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)
+ BUFFER_ADD("%" PRIu64, vl->values[ds_num].absolute);
+ else {
+ ERROR("format_values plugin: Unknown data source type: %i",
+ ds->ds[ds_num].type);
+ sfree(rates);
+ return -1;
+ }
+
+#undef BUFFER_ADD
+
+ sfree(rates);
+ return 0;
+}
+
+static int ws_format_name(char *ret, int ret_len, const value_list_t *vl,
+ const struct ws_callback *cb, const char *ds_name) {
+
+ if (ds_name != NULL) {
+ snprintf(ret, ret_len, "%s.%s", vl->type, ds_name);
+ } else { /* ds_name == NULL */
+ snprintf(ret, ret_len, "%s", vl->type);
+ }
+
+ return 0;
+}
+
+static int ws_send_message(const char *key, const char *value, cdtime_t time,
+ struct ws_callback *cb, const char *plugin,
+ const char *plugin_instance,
+ const char *type_instance, const char *type,
+ const char *ds_name, cdtime_t interval,
+ const char *host) {
+ int status;
+ size_t message_len;
+ char message[1024];
+ char rfc3339_timestamp[64];
+ const char *host_tags = cb->host_tags ? cb->host_tags : "";
+ const char *host_tags_json_prefix = "";
+ const char *metrics_prefix =
+ cb->metrics_prefix ? cb->metrics_prefix : WS_DEFAULT_PREFIX;
+ const char *msg_format = cb->msg_format ? cb->msg_format : WS_DEFAULT_FORMAT;
+ int pid;
+
+ pid = getpid();
+
+ rfc3339_local(rfc3339_timestamp, sizeof(rfc3339_timestamp), time);
+
+ /* skip if value is NaN */
+ if (value[0] == 'n')
+ return 0;
+
+ if (strcasecmp("JSON", msg_format) == 0) {
+ if (cb->host_tags) {
+ host_tags_json_prefix = ",";
+ }
+ status = snprintf(
+ /* The metric key-values are are part of the syslog msg, in json
+ format */
+ message, sizeof(message),
+ "<166>1 %s %s collectd %d - - {\"time\":%.0f, \"%s\":{ \"%s\":{ "
+ "\"%s\":%s }, "
+ "\"plugin\":\"%s\", \"plugin_instance\":\"%s\", "
+ "\"type_instance\":\"%s\","
+ " \"type\":\"%s\", \"interval\":%.0f }, \"hostname\":\"%s\" %s "
+ "%s}\n",
+ rfc3339_timestamp, host, pid, CDTIME_T_TO_DOUBLE(time), metrics_prefix,
+ plugin, key, value, plugin, plugin_instance, type_instance, type,
+ CDTIME_T_TO_DOUBLE(interval), host, host_tags_json_prefix, host_tags);
+ } else {
+ status = snprintf(
+ /* The metric key-values are part of the syslog structrude data,
+ * MessageFormat = "human" */
+ message, sizeof(message),
+ "<166>1 %s %s collectd %d - [%s value=\"%s\""
+ " plugin=\"%s\" plugin_instance=\"%s\""
+ " type_instance=\"%s\" type=\"%s\""
+ " ds_name=\"%s\" interval=\"%.0f\"] %s %s.%s=\"%s\"\n",
+ rfc3339_timestamp, host, pid, metrics_prefix, value, plugin,
+ plugin_instance, type_instance, type, ds_name,
+ CDTIME_T_TO_DOUBLE(interval), host_tags, plugin, key, value);
+ }
+ if (status < 0)
+ return -1;
+ message_len = (size_t)status;
+
+ if (message_len >= sizeof(message)) {
+ ERROR("write_syslog plugin: message buffer too small: "
+ "Need %" PRIsz " bytes.",
+ message_len + 1);
+ return -1;
+ }
+
+ pthread_mutex_lock(&cb->send_lock);
+
+ if (cb->sock_fd < 0) {
+ status = ws_callback_init(cb);
+ if (status != 0) {
+ ERROR("write_syslog plugin: ws_callback_init failed.");
+ pthread_mutex_unlock(&cb->send_lock);
+ return -1;
+ }
+ }
+
+ if (message_len >= cb->send_buf_free) {
+ status = ws_flush_nolock(0, cb);
+ if (status != 0) {
+ pthread_mutex_unlock(&cb->send_lock);
+ return status;
+ }
+ }
+
+ /* Assert that we have enough space for this message. */
+ assert(message_len < cb->send_buf_free);
+
+ /* `message_len + 1' because `message_len' does not include the
+ * trailing null byte. Neither does `send_buffer_fill'. */
+ memcpy(cb->send_buf + cb->send_buf_fill, message, message_len + 1);
+ cb->send_buf_fill += message_len;
+ cb->send_buf_free -= message_len;
+
+ DEBUG("write_syslog 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);
+
+ pthread_mutex_unlock(&cb->send_lock);
+
+ return 0;
+}
+
+static int ws_write_messages(const data_set_t *ds, const value_list_t *vl,
+ struct ws_callback *cb) {
+ char key[10 * DATA_MAX_NAME_LEN];
+ char values[512];
+
+ int status;
+
+ if (0 != strcmp(ds->type, vl->type)) {
+ ERROR("write_syslog plugin: DS type does not match "
+ "value list type");
+ return -1;
+ }
+
+ for (size_t i = 0; i < ds->ds_num; i++) {
+ const char *ds_name = NULL;
+
+ if (cb->always_append_ds || (ds->ds_num > 1))
+ ds_name = ds->ds[i].name;
+
+ /* Copy the identifier to 'key' and escape it. */
+ status = ws_format_name(key, sizeof(key), vl, cb, ds_name);
+ if (status != 0) {
+ ERROR("write_syslog plugin: error with format_name");
+ return status;
+ }
+
+ escape_string(key, sizeof(key));
+ /* Convert the values to an ASCII representation and put that into
+ * 'values'. */
+ status =
+ ws_format_values(values, sizeof(values), i, ds, vl, cb->store_rates);
+ if (status != 0) {
+ ERROR("write_syslog plugin: error with "
+ "ws_format_values");
+ return status;
+ }
+
+ /* Send the message to tcp */
+ status = ws_send_message(key, values, vl->time, cb, vl->plugin,
+ vl->plugin_instance, vl->type_instance, vl->type,
+ ds_name, vl->interval, vl->host);
+ if (status != 0) {
+ ERROR("write_syslog plugin: error with "
+ "ws_send_message");
+ return status;
+ }
+ }
+
+ return 0;
+}
+
+static int ws_write(const data_set_t *ds, const value_list_t *vl,
+ user_data_t *user_data) {
+ struct ws_callback *cb;
+ int status;
+
+ if (user_data == NULL)
+ return EINVAL;
+
+ cb = user_data->data;
+
+ status = ws_write_messages(ds, vl, cb);
+
+ return status;
+}
+
+static int ws_config_tsd(oconfig_item_t *ci) {
+ struct ws_callback *cb;
+ char callback_name[DATA_MAX_NAME_LEN];
+
+ cb = calloc(1, sizeof(*cb));
+ if (cb == NULL) {
+ ERROR("write_syslog plugin: calloc failed.");
+ return -1;
+ }
+ cb->sock_fd = -1;
+ cb->connect_failed_log_enabled = 1;
+ cb->next_random_ttl = new_random_ttl();
+
+ pthread_mutex_init(&cb->send_lock, NULL);
+
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp("Host", child->key) == 0)
+ cf_util_get_string(child, &cb->node);
+ else if (strcasecmp("Port", child->key) == 0)
+ cf_util_get_service(child, &cb->service);
+ else if (strcasecmp("MessageFormat", child->key) == 0)
+ cf_util_get_string(child, &cb->msg_format);
+ else if (strcasecmp("HostTags", child->key) == 0)
+ cf_util_get_string(child, &cb->host_tags);
+ else if (strcasecmp("StoreRates", child->key) == 0)
+ cf_util_get_boolean(child, &cb->store_rates);
+ else if (strcasecmp("AlwaysAppendDS", child->key) == 0)
+ cf_util_get_boolean(child, &cb->always_append_ds);
+ else if (strcasecmp("Prefix", child->key) == 0)
+ cf_util_get_string(child, &cb->metrics_prefix);
+ else {
+ ERROR("write_syslog plugin: Invalid configuration "
+ "option: %s.",
+ child->key);
+ return -1;
+ }
+ }
+
+ snprintf(callback_name, sizeof(callback_name), "write_syslog/%s/%s",
+ cb->node != NULL ? cb->node : WS_DEFAULT_NODE,
+ cb->service != NULL ? cb->service : WS_DEFAULT_SERVICE);
+
+ user_data_t user_data = {.data = cb, .free_func = ws_callback_free};
+
+ plugin_register_write(callback_name, ws_write, &user_data);
+
+ user_data.free_func = NULL;
+ plugin_register_flush(callback_name, ws_flush, &user_data);
+
+ return 0;
+}
+
+static int ws_config(oconfig_item_t *ci) {
+ if ((resolve_interval == 0) && (resolve_jitter == 0))
+ resolve_interval = resolve_jitter = plugin_get_interval();
+
+ for (int i = 0; i < ci->children_num; i++) {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp("Node", child->key) == 0) {
+ if (ws_config_tsd(child) < 0)
+ return -1;
+ } else if (strcasecmp("ResolveInterval", child->key) == 0)
+ cf_util_get_cdtime(child, &resolve_interval);
+ else if (strcasecmp("ResolveJitter", child->key) == 0)
+ cf_util_get_cdtime(child, &resolve_jitter);
+ else {
+ ERROR("write_syslog plugin: Invalid configuration "
+ "option: %s.",
+ child->key);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void module_register(void) {
+ plugin_register_complex_config("write_syslog", ws_config);
+}
size_t valuelen = sizeof(value);
int rv;
- snprintf(buffer, sizeof(buffer), "%s%s", zfs_arcstat, name);
+ ssnprintf(buffer, sizeof(buffer), "%s%s", zfs_arcstat, name);
rv = sysctlbyname(buffer, (void *)&value, &valuelen,
/* new value = */ NULL, /* new length = */ (size_t)0);
if (rv == 0)
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.",
- 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);
- fclose(fh);
- return (-1);
- }
-
while (fgets(buffer, sizeof(buffer), fh) != NULL) {
char *fields[3];
value_t v;
za_read_gauge(ksp, "mfu_size", "cache_size", "mfu_size");
za_read_gauge(ksp, "mru_ghost_size", "cache_size", "mru_ghost_size");
za_read_gauge(ksp, "mru_size", "cache_size", "mru_size");
- za_read_gauge(ksp, "other_size", "cache_size", "other_size");
za_read_gauge(ksp, "p", "cache_size", "p");
za_read_gauge(ksp, "size", "cache_size", "arc");
+ /* The "other_size" value was replaced by more specific values in ZFS on Linux
+ * version 0.7.0 (commit 25458cb)
+ */
+ if (za_read_gauge(ksp, "dbuf_size", "cache_size", "dbuf_size") != 0 ||
+ za_read_gauge(ksp, "dnode_size", "cache_size", "dnode_size") != 0 ||
+ za_read_gauge(ksp, "bonus_size", "cache_size", "bonus_size") != 0)
+ za_read_gauge(ksp, "other_size", "cache_size", "other_size");
+
/* The "l2_size" value has disappeared from Solaris some time in
* early 2013, and has only reappeared recently in Solaris 11.2.
* Stop trying if we ever fail to read it, so we don't spam the log.
#!/bin/sh
-DEFAULT_VERSION="5.8.1.git"
+DEFAULT_VERSION="5.9.2.git"
if [ -d .git ]; then
VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"