=head1 SYNOPSIS
- BaseDir "/path/to/data/"
- PIDFile "/path/to/pidfile/collectd.pid"
- Server "123.123.123.123" 12345
+ BaseDir "/var/lib/collectd"
+ PIDFile "/run/collectd.pid"
+ Interval 10.0
LoadPlugin cpu
LoadPlugin load
<LoadPlugin df>
Interval 3600
</LoadPlugin>
+ <Plugin df>
+ ValuesPercentage true
+ </Plugin>
LoadPlugin ping
<Plugin ping>
This config file controls how the system statistics collection daemon
B<collectd> behaves. The most significant option is B<LoadPlugin>, which
controls which plugins to load. These plugins ultimately define collectd's
-behavior.
+behavior. If the B<AutoLoadPlugin> option has been enabled, the explicit
+B<LoadPlugin> lines may be omitted for all plugins with a configuration block,
+i.e. a C<E<lt>PluginE<nbsp>...E<gt>> block.
The syntax of this config file is similar to the config file of the famous
I<Apache> webserver. Each line contains either an option (a key and a list of
The configuration is read and processed in order, i.e. from top to bottom. So
the plugins are loaded in the order listed in this config file. It is a good
idea to load any logging plugins first in order to catch messages from plugins
-during configuration. Also, the C<LoadPlugin> option B<must> occur B<before>
-the appropriate C<E<lt>Plugin ...E<gt>> block.
+during configuration. Also, unless B<AutoLoadPlugin> is enabled, the
+B<LoadPlugin> option I<must> occur I<before> the appropriate
+C<E<lt>B<Plugin> ...E<gt>> block.
=head1 GLOBAL OPTIONS
=item B<LoadPlugin> I<Plugin>
-Loads the plugin I<Plugin>. There must be at least one such line or B<collectd>
-will be mostly useless.
+Loads the plugin I<Plugin>. This is required to load plugins, unless the
+B<AutoLoadPlugin> option is enabled (see below). Without any loaded plugins,
+I<collectd> will be mostly useless.
-Starting with collectd 4.9, this may also be a block in which further options
-affecting the behavior of B<LoadPlugin> may be specified. The following
-options are allowed inside a B<LoadPlugin> block:
+Only the first B<LoadPlugin> statement or block for a given plugin name has any
+effect. This is useful when you want to split up the configuration into smaller
+files and want each file to be "self contained", i.e. it contains a B<Plugin>
+block I<and> then appropriate B<LoadPlugin> statement. The downside is that if
+you have multiple conflicting B<LoadPlugin> blocks, e.g. when they specify
+different intervals, only one of them (the first one encountered) will take
+effect and all others will be silently ignored.
- <LoadPlugin perl>
- Globals true
- Interval 10
- </LoadPlugin>
+B<LoadPlugin> may either be a simple configuration I<statement> or a I<block>
+with additional options, affecting the behavior of B<LoadPlugin>. A simple
+statement looks like this:
+
+ LoadPlugin "cpu"
+
+Options inside a B<LoadPlugin> block can override default settings and
+influence the way plugins are loaded, e.g.:
+
+ <LoadPlugin perl>
+ Globals true
+ Interval 60
+ </LoadPlugin>
+
+The following options are valid inside B<LoadPlugin> blocks:
=over 4
=back
-=item B<Include> I<Path>
+=item B<AutoLoadPlugin> B<false>|B<true>
+
+When set to B<false> (the default), each plugin needs to be loaded explicitly,
+using the B<LoadPlugin> statement documented above. If a
+B<E<lt>PluginE<nbsp>...E<gt>> block is encountered and no configuration
+handling callback for this plugin has been registered, a warning is logged and
+the block is ignored.
+
+When set to B<true>, explicit B<LoadPlugin> statements are not required. Each
+B<E<lt>PluginE<nbsp>...E<gt>> block acts as if it was immediately preceded by a
+B<LoadPlugin> statement. B<LoadPlugin> statements are still required for
+plugins that don't provide any configuration, e.g. the I<Load plugin>.
+
+=item B<Include> I<Path> [I<pattern>]
If I<Path> points to a file, includes that file. If I<Path> points to a
directory, recursively includes all files within that directory and its
default value is B<5>, but you may want to increase this if you have more than
five plugins that may take relatively long to write to.
+=item B<WriteQueueLimitHigh> I<HighNum>
+
+=item B<WriteQueueLimitLow> I<LowNum>
+
+Metrics are read by the I<read threads> and then put into a queue to be handled
+by the I<write threads>. If one of the I<write plugins> is slow (e.g. network
+timeouts, I/O saturation of the disk) this queue will grow. In order to avoid
+running into memory issues in such a case, you can limit the size of this
+queue.
+
+By default, there is no limit and memory may grow indefinitely. This is most
+likely not an issue for clients, i.e. instances that only handle the local
+metrics. For servers it is recommended to set this to a non-zero value, though.
+
+You can set the limits using B<WriteQueueLimitHigh> and B<WriteQueueLimitLow>.
+Each of them takes a numerical argument which is the number of metrics in the
+queue. If there are I<HighNum> metrics in the queue, any new metrics I<will> be
+dropped. If there are less than I<LowNum> metrics in the queue, all new metrics
+I<will> be enqueued. If the number of metrics currently in the queue is between
+I<LowNum> and I<HighNum>, the metric is dropped with a probability that is
+proportional to the number of metrics in the queue (i.e. it increases linearly
+until it reaches 100%.)
+
+If B<WriteQueueLimitHigh> is set to non-zero and B<WriteQueueLimitLow> is
+unset, the latter will default to half of B<WriteQueueLimitHigh>.
+
+If you do not want to randomly drop values when the queue size is between
+I<LowNum> and I<HighNum>, set If B<WriteQueueLimitHigh> and
+B<WriteQueueLimitLow> to same value.
+
=item B<Hostname> I<Name>
Sets the hostname that identifies a host. If you omit this setting, the
=back
+=head2 Plugin C<aquaero>
+
+This plugin collects the value of the available sensors in an
+I<AquaeroE<nbsp>5> board. AquaeroE<nbsp>5 is a water-cooling controller board,
+manufactured by Aqua Computer GmbH L<http://www.aquacomputer.de/>, with a USB2
+connection for monitoring and configuration. The board can handle multiple
+temperature sensors, fans, water pumps and water level sensors and adjust the
+output settings such as fan voltage or power used by the water pump based on
+the available inputs using a configurable controller included in the board.
+This plugin collects all the available inputs as well as some of the output
+values chosen by this controller. The plugin is based on the I<libaquaero5>
+library provided by I<aquatools-ng>.
+
+=over 4
+
+=item B<Device> I<DevicePath>
+
+Device path of the AquaeroE<nbsp>5's USB HID (human interface device), usually
+in the form C</dev/usb/hiddevX>. If this option is no set the plugin will try
+to auto-detect the Aquaero 5 USB device based on vendor-ID and product-ID.
+
+=back
+
=head2 Plugin C<ascent>
This plugin collects information about an Ascent server, a free server for the
=back
+=head2 Plugin C<cgroups>
+
+This plugin collects the CPU user/system time for each I<cgroup> by reading the
+F<cpuacct.stat> files in the first cpuacct-mountpoint (typically
+F</sys/fs/cgroup/cpu.cpuacct> on machines using systemd).
+
+=over 4
+
+=item B<CGroup> I<Directory>
+
+Select I<cgroup> based on the name. Whether only matching I<cgroups> are
+collected or if they are ignored is controlled by the B<IgnoreSelected> option;
+see below.
+
+=item B<IgnoreSelected> B<true>|B<false>
+
+Invert the selection: If set to true, all cgroups I<except> the ones that
+match any one of the criteria are collected. By default only selected
+cgroups are collected if a selection is made. If no selection is configured
+at all, B<all> cgroups are selected.
+
+=back
+
=head2 Plugin C<cpufreq>
This plugin doesn't have any options. It reads
=head2 Plugin C<curl_json>
-The B<curl_json plugin> uses B<libcurl> (L<http://curl.haxx.se/>) and
-B<libyajl> (L<http://www.lloydforge.org/projects/yajl/>) to retrieve JSON data
-via cURL. This can be used to collect values from CouchDB documents (which are
-stored JSON notation), for example.
+The B<curl_json plugin> collects values from JSON data to be parsed by
+B<libyajl> (L<http://www.lloydforge.org/projects/yajl/>) retrieved via
+either B<libcurl> (L<http://curl.haxx.se/>) or read directly from a
+unix socket. The former can be used, for example, to collect values
+from CouchDB documents (which are stored JSON notation), and the
+latter to collect values from a uWSGI stats socket.
-The following example will collect several values from the built-in `_stats'
-runtime statistics module of CouchDB
+The following example will collect several values from the built-in
+C<_stats> runtime statistics module of I<CouchDB>
(L<http://wiki.apache.org/couchdb/Runtime_Statistics>).
<Plugin curl_json>
</URL>
</Plugin>
-In the B<Plugin> block, there may be one or more B<URL> blocks, each defining
-a URL to be fetched via HTTP (using libcurl) and one or more B<Key> blocks.
-The B<Key> string argument must be in a path format, which is used to collect a
-value from a JSON map object. If a path element of B<Key> is the
-I<*>E<nbsp>wildcard, the values for all keys will be collectd.
+This example will collect data directly from a I<uWSGI> "Stats Server" socket.
+
+ <Plugin curl_json>
+ <Sock "/var/run/uwsgi.stats.sock">
+ Instance "uwsgi"
+ <Key "workers/*/requests">
+ Type "http_requests"
+ </Key>
+
+ <Key "workers/*/apps/*/requests">
+ Type "http_requests"
+ </Key>
+ </Sock>
+ </Plugin>
+
+In the B<Plugin> block, there may be one or more B<URL> blocks, each
+defining a URL to be fetched via HTTP (using libcurl) or B<Sock>
+blocks defining a unix socket to read JSON from directly. Each of
+these blocks may have one or more B<Key> blocks.
+
+The B<Key> string argument must be in a path format. Each component is
+used to match the key from a JSON map or the index of an JSON
+array. If a path component of a B<Key> is a I<*>E<nbsp>wildcard, the
+values for all map keys or array indices will be collectd.
The following options are valid within B<URL> blocks:
many small files are stored on the disk. This is a usual scenario for mail
transfer agents and web caches.
+=item B<ValuesAbsolute> B<true>|B<false>
+
+Enables or disables reporting of free, used and used disk space in 1K-blocks.
+Defaults to true.
+
+=item B<ValuesPercentage> B<true>|B<false>
+
+Enables or disables reporting of free, used and used disk space in percentage.
+Defaults to false.
+
+This is useful for deploying collectd on the cloud, where machines with
+different disk size may exist. Then it is more practical to configure thresholds
+based on relative disk size.
+
=back
=head2 Plugin C<disk>
=head2 Plugin C<memcached>
-The C<memcached plugin> connects to a memcached server and queries statistics
+The B<memcached plugin> connects to a memcached server and queries statistics
about cache utilization, memory and bandwidth used.
L<http://www.danga.com/memcached/>
=back
+=head2 Plugin C<mic>
+
+The B<mic plugin> gathers CPU statistics, memory usage and temperatures from
+Intel's Many Integrated Core (MIC) systems.
+
+B<Synopsis:>
+
+ <Plugin mic>
+ ShowCPU true
+ ShowCPUCores true
+ ShowMemory true
+
+ ShowTemperatures true
+ Temperature vddg
+ Temperature vddq
+ IgnoreSelectedTemperature true
+
+ ShowPower true
+ Power total0
+ Power total1
+ IgnoreSelectedPower true
+ </Plugin>
+
+The following options are valid inside the B<PluginE<nbsp>mic> block:
+
+=over 4
+
+=item B<ShowCPU> B<true>|B<false>
+
+If enabled (the default) a sum of the CPU usage accross all cores is reported.
+
+=item B<ShowCPUCores> B<true>|B<false>
+
+If enabled (the default) per-core CPU usage is reported.
+
+=item B<ShowMemory> B<true>|B<false>
+
+If enabled (the default) the physical memory usage of the MIC system is
+reported.
+
+=item B<ShowTemperatures> B<true>|B<false>
+
+If enabled (the default) various temperatures of the MIC system are reported.
+
+=item B<Temperature> I<Name>
+
+This option controls which temperatures are being reported. Whether matching
+temperatures are being ignored or I<only> matching temperatures are reported
+depends on the B<IgnoreSelectedTemperature> setting below. By default I<all>
+temperatures are reported.
+
+=item B<IgnoreSelectedTemperature> B<false>|B<true>
+
+Controls the behavior of the B<Temperature> setting above. If set to B<false>
+(the default) only temperatures matching a B<Temperature> option are reported
+or, if no B<Temperature> option is specified, all temperatures are reported. If
+set to B<true>, matching temperatures are I<ignored> and all other temperatures
+are reported.
+
+Known temperature names are:
+
+=over 4
+
+=item die
+
+Die of the CPU
+
+=item devmem
+
+Device Memory
+
+=item fin
+
+Fan In
+
+=item fout
+
+Fan Out
+
+=item vccp
+
+Voltage ccp
+
+=item vddg
+
+Voltage ddg
+
+=item vddq
+
+Voltage ddq
+
+=back
+
+=item B<ShowPower> B<true>|B<false>
+
+If enabled (the default) various temperatures of the MIC system are reported.
+
+=item B<Power> I<Name>
+
+This option controls which power readings are being reported. Whether matching
+power readings are being ignored or I<only> matching power readings are reported
+depends on the B<IgnoreSelectedPower> setting below. By default I<all>
+power readings are reported.
+
+=item B<IgnoreSelectedPower> B<false>|B<true>
+
+Controls the behavior of the B<Power> setting above. If set to B<false>
+(the default) only power readings matching a B<Power> option are reported
+or, if no B<Power> option is specified, all power readings are reported. If
+set to B<true>, matching power readings are I<ignored> and all other power readings
+are reported.
+
+Known power names are:
+
+=over 4
+
+=item total0
+
+Total power utilization averaged over Time Window 0 (uWatts).
+
+=item total1
+
+Total power utilization averaged over Time Window 0 (uWatts).
+
+=item inst
+
+Instantaneous power (uWatts).
+
+=item imax
+
+Max instantaneous power (uWatts).
+
+=item pcie
+
+PCI-E connector power (uWatts).
+
+=item c2x3
+
+2x3 connector power (uWatts).
+
+=item c2x4
+
+2x4 connector power (uWatts).
+
+=item vccp
+
+Core rail (uVolts).
+
+=item vddg
+
+Uncore rail (uVolts).
+
+=item vddq
+
+Memory subsystem rail (uVolts).
+
+=back
+
+=back
+
=head2 Plugin C<modbus>
The B<modbus plugin> connects to a Modbus "slave" via Modbus/TCP and reads
values), large integer values (unsigned 32E<nbsp>bit values) and floating point
values (two registers interpreted as IEEE floats in big endian notation).
-Synopsis:
+B<Synopsis:>
<Data "voltage-input-1">
RegisterBase 0
=back
+=head2 Plugin C<sigrok>
+
+The I<sigrok plugin> uses I<libsigrok> to retrieve measurements from any device
+supported by the L<sigrok|http://sigrok.org/> project.
+
+B<Synopsis>
+
+ <Plugin sigrok>
+ LogLevel 3
+ <Device "AC Voltage">
+ Driver "fluke-dmm"
+ MinimumInterval 10
+ Conn "/dev/ttyUSB2"
+ </Device>
+ <Device "Sound Level">
+ Driver "cem-dt-885x"
+ Conn "/dev/ttyUSB1"
+ </Device>
+ </Plugin>
+
+=over 4
+
+=item B<LogLevel> B<0-5>
+
+The I<sigrok> logging level to pass on to the I<collectd> log, as a number
+between B<0> and B<5> (inclusive). These levels correspond to C<None>,
+C<Errors>, C<Warnings>, C<Informational>, C<Debug >and C<Spew>, respectively.
+The default is B<2> (C<Warnings>). The I<sigrok> log messages, regardless of
+their level, are always submitted to I<collectd> at its INFO log level.
+
+=item E<lt>B<Device> I<Name>E<gt>
+
+A sigrok-supported device, uniquely identified by this section's options. The
+I<Name> is passed to I<collectd> as the I<plugin instance>.
+
+=item B<Driver> I<DriverName>
+
+The sigrok driver to use for this device.
+
+=item B<Conn> I<ConnectionSpec>
+
+If the device cannot be auto-discovered, or more than one might be discovered
+by the driver, I<ConnectionSpec> specifies the connection string to the device.
+It can be of the form of a device path (e.g.E<nbsp>C</dev/ttyUSB2>), or, in
+case of a non-serial USB-connected device, the USB I<VendorID>B<.>I<ProductID>
+separated by a period (e.g.E<nbsp>C<0403.6001>). A USB device can also be
+specified as I<Bus>B<.>I<Address> (e.g.E<nbsp>C<1.41>).
+
+=item B<SerialComm> I<SerialSpec>
+
+For serial devices with non-standard port settings, this option can be used
+to specify them in a form understood by I<sigrok>, e.g.E<nbsp>C<9600/8n1>.
+This should not be necessary; drivers know how to communicate with devices they
+support.
+
+=item B<MinimumInterval> I<Seconds>
+
+Specifies the minimum time between measurement dispatches to I<collectd>, in
+seconds. Since some I<sigrok> supported devices can acquire measurements many
+times per second, it may be necessary to throttle these. For example, the
+I<RRD plugin> cannot process writes more than once per second.
+
+The default B<MinimumInterval> is B<0>, meaning measurements received from the
+device are always dispatched to I<collectd>. When throttled, unused
+measurements are discarded.
+
+=back
+
=head2 Plugin C<snmp>
Since the configuration of the C<snmp plugin> is a little more complicated than
other plugins, its documentation has been moved to an own manpage,
L<collectd-snmp(5)>. Please see there for details.
+=head2 Plugin C<statsd>
+
+The I<statsd plugin> listens to a UDP socket, reads "events" in the statsd
+protocol and dispatches rates or other aggregates of these numbers
+periodically.
+
+The plugin implements the I<Counter>, I<Timer>, I<Gauge> and I<Set> types which
+are dispatched as the I<collectd> types C<derive>, C<latency>, C<gauge> and
+C<objects> respectively.
+
+The following configuration options are valid:
+
+=over 4
+
+=item B<Host> I<Host>
+
+Bind to the hostname / address I<Host>. By default, the plugin will bind to the
+"any" address, i.e. accept packets sent to any of the hosts addresses.
+
+=item B<Port> I<Port>
+
+UDP port to listen to. This can be either a service name or a port number.
+Defaults to C<8125>.
+
+=item B<DeleteCounters> B<false>|B<true>
+
+=item B<DeleteTimers> B<false>|B<true>
+
+=item B<DeleteGauges> B<false>|B<true>
+
+=item B<DeleteSets> B<false>|B<true>
+
+These options control what happens if metrics are not updated in an interval.
+If set to B<False>, the default, metrics are dispatched unchanged, i.e. the
+rate of counters and size of sets will be zero, timers report C<NaN> and gauges
+are unchanged. If set to B<True>, the such metrics are not dispatched and
+removed from the internal cache.
+
+=item B<TimerPercentile> I<Percent>
+
+Calculate and dispatch the configured percentile, i.e. compute the latency, so
+that I<Percent> of all reported timers are smaller than or equal to the
+computed latency. This is useful for cutting off the long tail latency, as it's
+often done in I<Service Level Agreements> (SLAs).
+
+Different percentiles can be calculated by setting this option several times.
+If none are specified, no percentiles are calculated / dispatched.
+
+=item B<TimerLower> B<false>|B<true>
+
+=item B<TimerUpper> B<false>|B<true>
+
+=item B<TimerSum> B<false>|B<true>
+
+=item B<TimerCount> B<false>|B<true>
+
+Calculate and dispatch various values out of I<Timer> metrics received during
+an interval. If set to B<False>, the default, these values aren't calculated /
+dispatched.
+
+=back
+
=head2 Plugin C<swap>
The I<Swap plugin> collects information about used and available swap space. On
Statistics about the shared memory log, a memory region to store
log messages which is flushed to disk when full. True by default.
+=item B<CollectBan> B<true>|B<false>
+
+Statistics about ban operations, such as number of bans added, retired, and
+number of objects tested against ban operations. Only available with Varnish
+3.x. False by default.
+
+=item B<CollectDirectorDNS> B<true>|B<false>
+
+DNS director lookup cache statistics. Only available with Varnish 3.x. False by
+default.
+
=item B<CollectESI> B<true>|B<false>
Edge Side Includes (ESI) parse statistics. False by default.
Inserts and look-ups in the crit bit tree based hash. Look-ups are
divided into locked and unlocked look-ups. False by default.
+=item B<CollectObjects> B<true>|B<false>
+
+Statistics on cached objects: number of objects expired, nuked (prematurely
+expired), saved, moved, etc. False by default.
+
+=item B<CollectPurge> B<true>|B<false>
+
+Statistics about purge operations, such as number of purges added, retired, and
+number of objects tested against purge operations. Only available with Varnish
+2.x. False by default.
+
+=item B<CollectSession> B<true>|B<false>
+
+Client session statistics. Number of past and current sessions, session herd and
+linger counters, etc. False by default.
+
=item B<CollectSMA> B<true>|B<false>
-malloc or umem (umem_alloc(3MALLOC) based) storage statistics.
-The umem storage component is Solaris specific. False by default.
+malloc or umem (umem_alloc(3MALLOC) based) storage statistics. The umem storage
+component is Solaris specific. Only available with Varnish 2.x. False by
+default.
=item B<CollectSMS> B<true>|B<false>
=item B<CollectSM> B<true>|B<false>
-file (memory mapped file) storage statistics. False by default.
+file (memory mapped file) storage statistics. Only available with Varnish 2.x.
+False by default.
+
+=item B<CollectStruct> B<true>|B<false>
+
+Current varnish internal state statistics. Number of current sessions, objects
+in cache store, open connections to backends (with Varnish 2.x), etc. False by
+default.
=item B<CollectTotals> B<true>|B<false>
Collects overview counters, such as the number of sessions created,
the number of requests and bytes transferred. False by default.
+=item B<CollectUptime> B<true>|B<false>
+
+Varnish uptime. False by default.
+
+=item B<CollectVCL> B<true>|B<false>
+
+Number of total (available + discarded) VCL (config files). False by default.
+
=item B<CollectWorkers> B<true>|B<false>
Collect statistics about worker threads. False by default.
The C<write_graphite> plugin writes data to I<Graphite>, an open-source metrics
storage and graphing project. The plugin connects to I<Carbon>, the data layer
-of I<Graphite>, and sends data via the "line based" protocol (per default using
-portE<nbsp>2003). The data will be sent in blocks of at most 1428 bytes to
-minimize the number of network packets.
+of I<Graphite>, via I<TCP> or I<UDP> and sends data via the "line based"
+protocol (per default using portE<nbsp>2003). The data will be sent in blocks
+of at most 1428 bytes to minimize the number of network packets.
Synopsis:
<Node "example">
Host "localhost"
Port "2003"
+ Protocol "tcp"
+ LogSendErrors true
Prefix "collectd"
</Node>
</Plugin>
Service name or port number to connect to. Defaults to C<2003>.
+=item B<Protocol> I<String>
+
+Protocol to use when connecting to I<Graphite>. Defaults to C<tcp>.
+
+=item B<LogSendErrors> B<false>|B<true>
+
+If set to B<true> (the default), logs errors when sending data to I<Graphite>.
+If set to B<false>, it will not log the errors. This is especially useful when
+using Protocol UDP since many times we want to use the "fire-and-forget"
+approach and logging errors fills syslog with unneeded messages.
+
=item B<Prefix> I<String>
When set, I<String> is added in front of the host name. Dots and whitespace are
=back
+ =head2 Plugin C<write_redis>
+
+ The I<write_redis plugin> submits values to I<Redis>, a data structure server.
+
+ Synopsis:
+
+ <Plugin "write_redis">
+ <Node "example">
+ Host "localhost"
+ Port "6379"
+ Timeout 1000
+ </Node>
+ </Plugin>
+
+ Values are submitted to I<Sorted Sets>, using the metric name as the key, and
+ the timestamp as the score. Retrieving a date range can then be done using the
+ C<ZRANGEBYSCORE> I<Redis> command. Additionnally, all the identifiers of these
+ I<Sorted Sets> are kept in a I<Set> called C<collectd/values> and can be
+ retrieved using the C<SMEMBERS> I<Redis> command. See
+ L<http://redis.io/commands#sorted_set> and L<http://redis.io/commands#set> for
+ details.
+
+ The information shown in the synopsis above is the I<default configuration>
+ which is used by the plugin if no configuration is present.
+
+ The plugin can send values to multiple instances of I<Redis> by specifying
+ one B<Node> block for each instance. Within the B<Node> blocks, the following
+ options are available:
+
+ =over 4
+
+ =item B<Node> I<Nodename>
+
+ The B<Node> block identifies a new I<Redis> node, that is a new I<Redis>
+ instance running in an specified host and port. The name for node is a
+ canonical identifier which is used as I<plugin instance>. It is limited to
+ 64E<nbsp>characters in length.
+
+ =item B<Host> I<Hostname>
+
+ The B<Host> option is the hostname or IP-address where the I<Redis> instance is
+ running on.
+
+ =item B<Port> I<Port>
+
+ The B<Port> option is the TCP port on which the Redis instance accepts
+ connections. Either a service name of a port number may be given. Please note
+ that numerical port numbers must be given as a string, too.
+
+ =item B<Timeout> I<Timeout in miliseconds>
+
+ The B<Timeout> option sets the socket connection timeout, in milliseconds.
+
+ =back
+
=head2 Plugin C<write_riemann>
The I<write_riemann plugin> will send values to I<Riemann>, a powerfull stream
Protocol UDP
StoreRates true
AlwaysAppendDS false
- Delay 10
+ TTLFactor 2.0
</Node>
Tag "foobar"
</Plugin>
identifies a metric in I<Riemann>. If set to B<false> (the default), this is
only done when there is more than one DS.
+=item B<TTLFactor> I<Factor>
+
+I<Riemann> events have a I<Time to Live> (TTL) which specifies how long each
+event is considered active. I<collectd> populates this field based on the
+metrics interval setting. This setting controls the factor with which the
+interval is multiplied to set the TTL. The default value is B<2.0>. Unless you
+know exactly what you're doing, you should only increase this setting from its
+default value.
+
=back
=item B<Tag> I<String>
#include "utils_llist.h"
#include "utils_heap.h"
#include "utils_time.h"
+#include "utils_random.h"
#if HAVE_PTHREAD_H
# include <pthread.h>
#define rf_ctx rf_super.cf_ctx
callback_func_t rf_super;
char rf_group[DATA_MAX_NAME_LEN];
- char rf_name[DATA_MAX_NAME_LEN];
+ char *rf_name;
int rf_type;
cdtime_t rf_interval;
cdtime_t rf_effective_interval;
/*
* Private variables
*/
+static c_avl_tree_t *plugins_loaded = NULL;
+
static llist_t *list_init;
static llist_t *list_write;
static llist_t *list_flush;
static write_queue_t *write_queue_head;
static write_queue_t *write_queue_tail;
+static long write_queue_length = 0;
static _Bool write_loop = 1;
static pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t write_cond = PTHREAD_COND_INITIALIZER;
static pthread_key_t plugin_ctx_key;
static _Bool plugin_ctx_key_initialized = 0;
+static long write_limit_high = 0;
+static long write_limit_low = 0;
+
/*
* Static functions
*/
ssnprintf (errbuf, sizeof (errbuf),
"lt_dlopen (\"%s\") failed: %s. "
- "The most common cause for this problem are "
+ "The most common cause for this problem is "
"missing dependencies. Use ldd(1) to check "
"the dependencies of the plugin "
"/ shared object.",
{
DEBUG ("plugin_read_thread: Destroying the `%s' "
"callback.", rf->rf_name);
+ sfree (rf->rf_name);
destroy_callback ((callback_func_t *) rf);
rf = NULL;
continue;
{
write_queue_head = q;
write_queue_tail = q;
+ write_queue_length = 1;
}
else
{
write_queue_tail->next = q;
write_queue_tail = q;
+ write_queue_length += 1;
}
pthread_cond_signal (&write_cond);
q = write_queue_head;
write_queue_head = q->next;
- if (write_queue_head == NULL)
+ write_queue_length -= 1;
+ if (write_queue_head == NULL) {
write_queue_tail = NULL;
+ assert(0 == write_queue_length);
+ }
pthread_mutex_unlock (&write_lock);
}
write_queue_head = NULL;
write_queue_tail = NULL;
+ write_queue_length = 0;
pthread_mutex_unlock (&write_lock);
if (i > 0)
}
}
+static _Bool plugin_is_loaded (char const *name)
+{
+ int status;
+
+ if (plugins_loaded == NULL)
+ plugins_loaded = c_avl_create ((void *) strcasecmp);
+ assert (plugins_loaded != NULL);
+
+ status = c_avl_get (plugins_loaded, name, /* ret_value = */ NULL);
+ return (status == 0);
+}
+
+static int plugin_mark_loaded (char const *name)
+{
+ char *name_copy;
+ int status;
+
+ name_copy = strdup (name);
+ if (name_copy == NULL)
+ return (ENOMEM);
+
+ status = c_avl_insert (plugins_loaded,
+ /* key = */ name_copy, /* value = */ NULL);
+ return (status);
+}
+
+static void plugin_free_loaded ()
+{
+ void *key;
+ void *value;
+
+ if (plugins_loaded == NULL)
+ return;
+
+ while (c_avl_pick (plugins_loaded, &key, &value) == 0)
+ {
+ sfree (key);
+ assert (value == NULL);
+ }
+
+ c_avl_destroy (plugins_loaded);
+ plugins_loaded = NULL;
+}
+
#define BUFSIZE 512
-int plugin_load (const char *type, uint32_t flags)
+int plugin_load (char const *plugin_name, uint32_t flags)
{
DIR *dh;
const char *dir;
struct dirent *de;
int status;
+ if (plugin_name == NULL)
+ return (EINVAL);
+
+ /* Check if plugin is already loaded and don't do anything in this
+ * case. */
+ if (plugin_is_loaded (plugin_name))
+ return (0);
+
dir = plugin_get_dir ();
ret = 1;
+ /*
+ * XXX: Magic at work:
+ *
+ * Some of the language bindings, for example the Python and Perl
+ * plugins, need to be able to export symbols to the scripts they run.
+ * For this to happen, the "Globals" flag needs to be set.
+ * Unfortunately, this technical detail is hard to explain to the
+ * average user and she shouldn't have to worry about this, ideally.
+ * So in order to save everyone's sanity use a different default for a
+ * handful of special plugins. --octo
+ */
+ if ((strcasecmp ("perl", plugin_name) == 0)
+ || (strcasecmp ("python", plugin_name) == 0))
+ flags |= PLUGIN_FLAGS_GLOBAL;
+
/* `cpu' should not match `cpufreq'. To solve this we add `.so' to the
* type when matching the filename */
- status = ssnprintf (typename, sizeof (typename), "%s.so", type);
+ status = ssnprintf (typename, sizeof (typename), "%s.so", plugin_name);
if ((status < 0) || ((size_t) status >= sizeof (typename)))
{
- WARNING ("plugin_load: Filename too long: \"%s.so\"", type);
+ WARNING ("plugin_load: Filename too long: \"%s.so\"", plugin_name);
return (-1);
}
typename_len = strlen (typename);
if (status == 0)
{
/* success */
+ plugin_mark_loaded (plugin_name);
ret = 0;
break;
}
else
{
ERROR ("plugin_load: Load plugin \"%s\" failed with "
- "status %i.", type, status);
+ "status %i.", plugin_name, status);
}
}
if (filename[0] == 0)
ERROR ("plugin_load: Could not find plugin \"%s\" in %s",
- type, dir);
+ plugin_name, dir);
return (ret);
}
rf->rf_udata.free_func = NULL;
rf->rf_ctx = plugin_get_ctx ();
rf->rf_group[0] = '\0';
- sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
+ rf->rf_name = strdup (name);
rf->rf_type = RF_SIMPLE;
rf->rf_interval = plugin_get_interval ();
sstrncpy (rf->rf_group, group, sizeof (rf->rf_group));
else
rf->rf_group[0] = '\0';
- sstrncpy (rf->rf_name, name, sizeof (rf->rf_name));
+ rf->rf_name = strdup (name);
rf->rf_type = RF_COMPLEX;
if (interval != NULL)
rf->rf_interval = TIMESPEC_TO_CDTIME_T (interval);
void plugin_init_all (void)
{
- const char *chain_name;
+ char const *chain_name;
+ long write_threads_num;
llentry_t *le;
int status;
chain_name = global_option_get ("PostCacheChain");
post_cache_chain = fc_chain_get_by_name (chain_name);
+ write_limit_high = global_option_get_long ("WriteQueueLimitHigh",
+ /* default = */ 0);
+ if (write_limit_high < 0)
{
- char const *tmp = global_option_get ("WriteThreads");
- int num = atoi (tmp);
+ ERROR ("WriteQueueLimitHigh must be positive or zero.");
+ write_limit_high = 0;
+ }
- if (num < 1)
- num = 5;
+ write_limit_low = global_option_get_long ("WriteQueueLimitLow",
+ /* default = */ write_limit_high / 2);
+ if (write_limit_low < 0)
+ {
+ ERROR ("WriteQueueLimitLow must be positive or zero.");
+ write_limit_low = write_limit_high / 2;
+ }
+ else if (write_limit_low > write_limit_high)
+ {
+ ERROR ("WriteQueueLimitLow must not be larger than "
+ "WriteQueueLimitHigh.");
+ write_limit_low = write_limit_high;
+ }
- start_write_threads ((size_t) num);
+ write_threads_num = global_option_get_long ("WriteThreads",
+ /* default = */ 5);
+ if (write_threads_num < 1)
+ {
+ ERROR ("WriteThreads must be positive.");
+ write_threads_num = 5;
}
+ start_write_threads ((size_t) write_threads_num);
+
if ((list_init == NULL) && (read_heap == NULL))
return;
destroy_all_callbacks (&list_shutdown);
destroy_all_callbacks (&list_log);
+ plugin_free_loaded ();
plugin_free_data_sets ();
} /* void plugin_shutdown_all */
return (0);
} /* int plugin_dispatch_values_internal */
+static double get_drop_probability (void) /* {{{ */
+{
+ long pos;
+ long size;
+ long wql;
+
+ pthread_mutex_lock (&write_lock);
+ wql = write_queue_length;
+ pthread_mutex_unlock (&write_lock);
+
+ if (wql < write_limit_low)
+ return (0.0);
+ if (wql >= write_limit_high)
+ return (1.0);
+
+ pos = 1 + wql - write_limit_low;
+ size = 1 + write_limit_high - write_limit_low;
+
+ return (((double) pos) / ((double) size));
+} /* }}} double get_drop_probability */
+
+static _Bool check_drop_value (void) /* {{{ */
+{
+ static cdtime_t last_message_time = 0;
+ static pthread_mutex_t last_message_lock = PTHREAD_MUTEX_INITIALIZER;
+
+ double p;
+ double q;
+ int status;
+
+ if (write_limit_high == 0)
+ return (0);
+
+ p = get_drop_probability ();
+ if (p == 0.0)
+ return (0);
+
+ status = pthread_mutex_trylock (&last_message_lock);
+ if (status == 0)
+ {
+ cdtime_t now;
+
+ now = cdtime ();
+ if ((now - last_message_time) > TIME_T_TO_CDTIME_T (1))
+ {
+ last_message_time = now;
+ ERROR ("plugin_dispatch_values: Low water mark "
+ "reached. Dropping %.0f%% of metrics.",
+ 100.0 * p);
+ }
+ pthread_mutex_unlock (&last_message_lock);
+ }
+
+ if (p == 1.0)
+ return (1);
+
+ q = cdrand_d ();
+ if (q > p)
+ return (1);
+ else
+ return (0);
+} /* }}} _Bool check_drop_value */
+
int plugin_dispatch_values (value_list_t const *vl)
{
int status;
+ if (check_drop_value ())
+ return (0);
+
status = plugin_write_enqueue (vl);
if (status != 0)
{
* <Carbon>
* Host "localhost"
* Port "2003"
+ * Protocol "udp"
+ * LogSendErrors true
* Prefix "collectd"
* </Carbon>
* </Plugin>
# define WG_DEFAULT_SERVICE "2003"
#endif
+#ifndef WG_DEFAULT_PROTOCOL
+# define WG_DEFAULT_PROTOCOL "tcp"
+#endif
+
+#ifndef WG_DEFAULT_LOG_SEND_ERRORS
+# define WG_DEFAULT_LOG_SEND_ERRORS 1
+#endif
+
#ifndef WG_DEFAULT_ESCAPE
# define WG_DEFAULT_ESCAPE '_'
#endif
char *node;
char *service;
+ char *protocol;
+ _Bool log_send_errors;
char *prefix;
char *postfix;
char escape_char;
status = swrite (cb->sock_fd, cb->send_buf, strlen (cb->send_buf));
if (status < 0)
{
- char errbuf[1024];
- ERROR ("write_graphite plugin: send failed with status %zi (%s)",
- status, sstrerror (errno, errbuf, sizeof (errbuf)));
+ const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
+ if (cb->log_send_errors)
+ {
+ char errbuf[1024];
+ ERROR ("write_graphite plugin: send to %s:%s (%s) failed with status %zi (%s)",
+ cb->node, cb->service, protocol,
+ status, sstrerror (errno, errbuf, sizeof (errbuf)));
+ }
close (cb->sock_fd);
cb->sock_fd = -1;
const char *node = cb->node ? cb->node : WG_DEFAULT_NODE;
const char *service = cb->service ? cb->service : WG_DEFAULT_SERVICE;
+ const char *protocol = cb->protocol ? cb->protocol : WG_DEFAULT_PROTOCOL;
+ char connerr[1024] = "";
+
if (cb->sock_fd > 0)
return (0);
ai_hints.ai_flags |= AI_ADDRCONFIG;
#endif
ai_hints.ai_family = AF_UNSPEC;
- ai_hints.ai_socktype = SOCK_STREAM;
+
+ if (0 == strcasecmp ("tcp", protocol))
+ ai_hints.ai_socktype = SOCK_STREAM;
+ else
+ ai_hints.ai_socktype = SOCK_DGRAM;
ai_list = NULL;
status = getaddrinfo (node, service, &ai_hints, &ai_list);
if (status != 0)
{
- ERROR ("write_graphite plugin: getaddrinfo (%s, %s) failed: %s",
- node, service, gai_strerror (status));
+ ERROR ("write_graphite plugin: getaddrinfo (%s, %s, %s) failed: %s",
+ node, service, protocol, gai_strerror (status));
return (-1);
}
{
cb->sock_fd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype,
ai_ptr->ai_protocol);
- if (cb->sock_fd < 0)
+ if (cb->sock_fd < 0) {
+ char errbuf[1024];
+ snprintf (connerr, sizeof (connerr), "failed to open socket: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
continue;
+ }
status = connect (cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if (status != 0)
{
+ char errbuf[1024];
+ snprintf (connerr, sizeof (connerr), "failed to connect to remote "
+ "host: %s", sstrerror (errno, errbuf, sizeof (errbuf)));
close (cb->sock_fd);
cb->sock_fd = -1;
continue;
if (cb->sock_fd < 0)
{
- char errbuf[1024];
+ if (connerr[0] == '\0')
+ /* this should not happen but try to get a message anyway */
+ sstrerror (errno, connerr, sizeof (connerr));
c_complain (LOG_ERR, &cb->init_complaint,
- "write_graphite plugin: Connecting to %s:%s via %s failed. "
- "The last error was: %s", node, service, protocol,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- "write_graphite plugin: Connecting to %s:%s failed. "
- "The last error was: %s", node, service, connerr);
++ "write_graphite plugin: Connecting to %s:%s via %s failed. "
++ "The last error was: %s", node, service, protocol, connerr);
return (-1);
}
else
{
c_release (LOG_INFO, &cb->init_complaint,
- "write_graphite plugin: Successfully connected to %s:%s.",
- node, service);
+ "write_graphite plugin: Successfully connected to %s:%s via %s.",
+ node, service, protocol);
}
wg_reset_buffer (cb);
sfree(cb->name);
sfree(cb->node);
+ sfree(cb->protocol);
sfree(cb->service);
sfree(cb->prefix);
sfree(cb->postfix);
cb->send_buf_fill += message_len;
cb->send_buf_free -= message_len;
- DEBUG ("write_graphite plugin: [%s]:%s buf %zu/%zu (%.1f %%) \"%s\"",
+ DEBUG ("write_graphite plugin: [%s]:%s (%s) buf %zu/%zu (%.1f %%) \"%s\"",
cb->node,
cb->service,
+ cb->protocol,
cb->send_buf_fill, sizeof (cb->send_buf),
100.0 * ((double) cb->send_buf_fill) / ((double) sizeof (cb->send_buf)),
message);
user_data_t user_data;
char callback_name[DATA_MAX_NAME_LEN];
int i;
+ int status = 0;
cb = malloc (sizeof (*cb));
if (cb == NULL)
cb->name = NULL;
cb->node = NULL;
cb->service = NULL;
+ cb->protocol = NULL;
+ cb->log_send_errors = WG_DEFAULT_LOG_SEND_ERRORS;
cb->prefix = NULL;
cb->postfix = NULL;
cb->escape_char = WG_DEFAULT_ESCAPE;
/* FIXME: Legacy configuration syntax. */
if (strcasecmp ("Carbon", ci->key) != 0)
{
- int status = cf_util_get_string (ci, &cb->name);
+ status = cf_util_get_string (ci, &cb->name);
if (status != 0)
{
wg_callback_free (cb);
cf_util_get_string (child, &cb->node);
else if (strcasecmp ("Port", child->key) == 0)
cf_util_get_service (child, &cb->service);
+ else if (strcasecmp ("Protocol", child->key) == 0)
+ {
+ cf_util_get_string (child, &cb->protocol);
+
+ if (strcasecmp ("UDP", cb->protocol) != 0 &&
+ strcasecmp ("TCP", cb->protocol) != 0)
+ {
+ ERROR ("write_graphite plugin: Unknown protocol (%s)",
+ cb->protocol);
+ status = -1;
+ }
+ }
+ else if (strcasecmp ("LogSendErrors", child->key) == 0)
+ cf_util_get_boolean (child, &cb->log_send_errors);
else if (strcasecmp ("Prefix", child->key) == 0)
cf_util_get_string (child, &cb->prefix);
else if (strcasecmp ("Postfix", child->key) == 0)
{
ERROR ("write_graphite plugin: Invalid configuration "
"option: %s.", child->key);
+ status = -1;
}
+
+ if (status != 0)
+ break;
+ }
+
+ if (status != 0)
+ {
+ wg_callback_free (cb);
+ return (status);
}
/* FIXME: Legacy configuration syntax. */
if (cb->name == NULL)
- ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s/%s",
+ ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s/%s/%s",
cb->node != NULL ? cb->node : WG_DEFAULT_NODE,
- cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE);
+ cb->service != NULL ? cb->service : WG_DEFAULT_SERVICE,
+ cb->protocol != NULL ? cb->protocol : WG_DEFAULT_PROTOCOL);
else
ssnprintf (callback_name, sizeof (callback_name), "write_graphite/%s",
cb->name);