Thursday, January 20, 2011

collectd-mod-exec Part 1

Having some spare time I decided to write about powerful yet not well documented feature of the OpenWRT's luci-app-statistics plugin -- collectd-mod-exec module. This module allows collecting any type of data an external application could supply. In other words the module starts a user specified application which feeds collectd module with data. Principally having this module installed one could simulate all other collectd-mod-* modules.



Generally an application or script should write specially formatted strings to the STDOUT so that collectd could parse them and add parsed data into the rrdtool database. Collectd awaits data to be fed at predefined time intervals. One can specify desired time interval in "Collectd Settings->Data collection interval". This time interval will be available to an executed script from an environment variable called COLLECTD_INTERVAL. At the same place one can specify a Hostname that will also be available to the script from the COLLECTD_HOSTNAME variable. If Hostname is not set in the "Collectd Settings" it will be read from the "System Settings". To put a value into the database the script shall write to STDOUT a string formatted the following way:
PUTVAL "HOST_NAME/exec-COLLECTION_NAME/data_type-DATA_NAME" interval=TIME_INTERVAL N:VALUE1:VALUE2:...
Based on this string collectd will create the following data structure in the directory specified in the "Statistics->Collectd->Output Plugins->RRDTool"
HOSTNAME/COLLECTION_NAME/data_type-DATA_NAME.rrd
and COLLECTION_NAME shall also appear in the "Statistics->Graphs->Exec" menu

Let's start with a simple script that will collect random values from 0 to 255.
 1 root@Alix:~# cat /mnt/sd/bin/test.sh
#!/bin/sh
 
HOST=$COLLECTD_HOSTNAME
INTERVAL=$COLLECTD_INTERVAL
 
[ -z "$INTERVAL" ] && INTERVAL=5
INTERVAL=$(awk -v i=$INTERVAL 'BEGIN{print int(i)}')

while sleep $INTERVAL; do
  val=$(dd if=/dev/urandom bs=1 count=1 2>/dev/null | hexdump -e "\"%d\n\"")
  echo "PUTVAL \"$HOST/exec-test/temperature\" interval=$INTERVAL N:$val"
done
Line 7 is added for debugging purposes because without it the script would just break if started from the command line. Script shall write values with specified time intervals otherwise nothing is stored in the database and this will result in gaps on the graph.

Edit 22.Nov.2015: line 8 is needed now because collectd sends fractional number with the $COLLECTD_INTERVAL and sleep fails.

Starting the script from the command line produces the following:
root@Alix:~# /mnt/sd/bin/test.sh
PUTVAL "/exec-test/temperature" interval=5 N:127
PUTVAL "/exec-test/temperature" interval=5 N:116
PUTVAL "/exec-test/temperature" interval=5 N:95
PUTVAL "/exec-test/temperature" interval=5 N:89
PUTVAL "/exec-test/temperature" interval=5 N:158
PUTVAL "/exec-test/temperature" interval=5 N:37
The output looks correct. It shall be noted that I specified "temperature" as the data type here but some random values are actually fed. It works because the upper limit is not defined for the "temperature" data type and the lower limit is -273.15 so my values do fall within this range. The "temperature" data type is already registered so I don't have to register it myself.

Script is to be registered on the "Statistics->System plugins->Exec" page:

[Image]

After pressing "Save & Apply" and restarting of the collectd (/etc/init.d/collectd restart) an additional entry with the name "test" is added into the "Statistics->Graphs->Exec" menu. If it is not it's usually a good idea to check if the script is running in the background:
root@Alix:~# ps
...
...
17565 root      1616 S    /usr/sbin/collectd -f
17566 root      1616 S    /usr/sbin/collectd -f
17567 root      1616 S    /usr/sbin/collectd -f
17568 root      1616 S    /usr/sbin/collectd -f
17569 root      1616 S    /usr/sbin/collectd -f
17570 root      1616 S    /usr/sbin/collectd -f
17571 nobody     956 S    /bin/sh /mnt/sd/bin/test.sh
Note: at the time of writing this Howto there is a bug in the luci-statistic plugin that after pressing "Save & Apply" the /etc/collectd.conf is not updated with the made changes. A workaround is to restart the luci-statistics (/etc/init.d/lucu_statistics restart) before restarting the collectd.

Data collected by the script is shown in the next picture:

[Image]


Next time I'll continue with a more useful script for the cpu and board temperature monitoring.

5 comments:

Anonymous said...

Thanks a lot for tutorial. Your script didn't work for me at first. So I made a small change.

/bin/dd and /usr/bin/hexdump

Thanks to thorkill@irc.freenode.net on #collectd

Deeps said...

Very nice . Thanks !

Anonymous said...

Hi,
I am running openWRT on a virutal machine.

I am trying to add an input plugin to collectd using the exec plugin. I want to have graphs produced with the rrdtool plugin.

I add the following script:
/sbin/test_plugin.sh


#!/bin/sh

HOST=$COLLECTD_HOSTNAME
INTERVAL=$COLLECTD_INTERVAL

[ -z "$INTERVAL" ] && INTERVAL=5
while sleep $INTERVAL; do
val=$(dd if=/dev/urandom bs=1 count=1 2>/dev/null | hexdump -e "\"%d\n\"")
echo "PUTVAL \"$HOST/exec-test/dummy\" interval=$INTERVAL N:$val"
done


and I added it to /etc/collectd.conf (I used the GUI):


LoadPlugin exec

Exec "root:root" "/sbin/test_plugin.sh"



I have rrdtool installed. I rebooted the device but I don't see any change.
Nothing in the GUI under "Graphs". no files are created unter /tmp/rrd
am I missing anthing? Is there anything else I need to do?
thanks!

Unknown said...

Hi, " The "temperature" data type is already registered so I don't have to register it myself."... I am getting data from .db file. how to mention datatype or how to register it ?

Thanks in advance...

Erwin said...

on your manpage .. it is not correct the exec.js file for the new openwrt 21.x

you are using there "0", which needs to be replaced to ":"
https://openwrt.org/docs/guide-user/perf_and_log/statistic.custom

thx cu camel