Configuration examples

Monitoring a WiFi network

The following configuration is showing how to configure the monitoring WiFi interface wlan0

To extract metrics representing the trafic on the interface we need to create a dynamic configuration to collect data in pseudo file system /sys/class/net/wlan0/statistics/.

Collecting metrics

dynamic.1.name=wifi_received
dynamic.1.source=/sys/class/net/wlan0/statistics/rx_bytes
dynamic.1.regexp=(.*)
dynamic.1.postprocess=$1*-1
dynamic.1.rrd=DERIVE

dynamic.2.name=wifi_send
dynamic.2.source=/sys/class/net/wlan0/statistics/tx_bytes
dynamic.2.regexp=(.*)
dynamic.2.postprocess=
dynamic.2.rrd=DERIVE

Note

We dicided to represent downstream data with negative values. This is performed by the postprocess command: $1*-1

Add status

The collected metrics will be displayed in status page as define in the configuration bellow:

web.status.1.content.1.title=WiFi
web.status.1.content.1.icon=wifi.png
web.status.1.content.1.line.1="WiFi Sent: <b>"+KMG(data.wifi_send)+"<i class='icon-arrow-up'></i></b> Received: <b>"+KMG(Math.abs(data.wifi_received)) + "<i class='icon-arrow-down'></i></b>"
_images/wifi001.png

Add statistics

The following configuration add one graph to statistics page with the 2 curves representing upstream and downstream metrics:

web.statistics.1.content.1.title=WiFi
web.statistics.1.content.1.graph.1=wifi_send
web.statistics.1.content.1.graph.2=wifi_received
web.statistics.1.content.1.ds_graph_options.wifi_send.label=Upload bandwidth (bits)
web.statistics.1.content.1.ds_graph_options.wifi_send.lines={ fill: true }
web.statistics.1.content.1.ds_graph_options.wifi_send.color="#FF7777"
web.statistics.1.content.1.ds_graph_options.wifi_received.label=Download bandwidth (bits)
web.statistics.1.content.1.ds_graph_options.wifi_received.lines={ fill: true }
web.statistics.1.content.1.ds_graph_options.wifi_received.color="#77FF77"

In this configuration, we set color to green for downstream and red for upstream. The curves are filled.

Important

To apply the configuration, it is required to restart RPi-Monitor : /etc/init.d/rpimonotird restart

Monitor external disk

The disk have a disk with two partition /dev/sda1 and /dev/sda3.

The command and regular expression will be the following:

  • sda1 disk size command : df -t ext2,  regular expression: sda1\s+(\d+)
  • sda1 used space command : df -t ext2,  regular expression: sda1\s+\d+\s+(\d+)
  • sda3 disk size command : df -t ext4,  regular expression: sda3\s+(\d+)
  • sda3 used space command : df -t ext4,  regular expression: sda3\s+\d+\s+(\d+)

First we need to configure the extraction of partitions sizes which are extracted once at RPi-Monitor startup. We will create a file /etc/rpimonitord.conf.d/custo.conf with the data configured as static data like this:

static.1.name=storage1_total
static.1.source=df -t ext2
static.1.regexp=sda1\s+(\d+)
static.1.postprocess=$1/1024

static.2.name=storage2_total
static.2.source=df -t ext4
static.2.regexp=sda3\s+(\d+)
static.2.postprocess=$1/1024

The post processing is configured to transform kB into MB by dividing the extracted result by 1024.

For dynamic values extracted every 10 seconds, the configuration will be:

dynamic.1.name=storage1_used
dynamic.1.source=df -t ext2
dynamic.1.regexp=sda1\s+\d+\s+(\d+)
dynamic.1.postprocess=$1/1024
dynamic.1.rrd=GAUGE

dynamic.2.name=storage2_used
dynamic.2.source=df -t ext4
dynamic.2.regexp=sda3\s+\d+\s+(\d+)
dynamic.2.postprocess=$1/1024
dynamic.2.rrd=GAUGE

Dynamic stat will be stored into a RRD File as GAUGE. Ref to RRDTool help for detail about Data Source Types.

Now we will add a status line for this disk whit the following icon:

_images/hdd001.png

This icons has to be installed into the img directory of RPi-Monitor which is by default /usr/share/rpimonitor/web/img/.

The configuration to add a new status strip will then be the following:

web.status.1.content.1.title=Storage
web.status.1.content.1.icon=usb_hdd.png
web.status.1.content.1.line.1="<b>/storage1</b> Used: <b>"+KMG(data.storage1_used,'M')+"</b> (<b>"+Percent(data.storage1_used,data.storage1_total,'M')+"</b>) Free: <b>"+KMG(data.storage1_total-data.storage1_used,'M')+ "</b> Total: <b>"+ KMG(data.storage1_total,'M') +"</b>"
web.status.1.content.1.line.2=ProgressBar(data.storage1_used,data.storage1_total)
web.status.1.content.1.line.3="<b>/storage2</b> Used: <b>"+KMG(data.storage2_used,'M')+"</b> (<b>"+Percent(data.storage2_used,data.storage2_total,'M')+"</b>) Free: <b>"+KMG(data.storage2_total-data.storage2_used,'M')+ "</b> Total: <b>"+ KMG(data.storage2_total,'M') +"</b>"

The configuration may need some explanation:

We do configure 4 lines. Each line is describing a javascript line using some predefined functions: KMG, Precent and ProgressBar. This function are called by the browser while rendering the page. Some variable coming from the extracted data are also used. These variables are starting by the keyword data. For deeper detail about this configuration execute the command man rpimonitord.conf

To see our modification we need to restart RPi-Monitor and refresh the statistics page into our browser.

sudo  service rpimonitor restart

The result of the configuration is at the bottom of the following screenshot:

_images/hdd002.png

The status page is working, let’s now add a graphic of the disk usage. This is done with the following configuration:

web.statistics.1.content.1.title=Storage1
web.statistics.1.content.1.graph.1=storage1_total
web.statistics.1.content.1.graph.2=storage1_used
web.statistics.1.content.1.ds_graph_options.storage1_total.label=Storage1 total space (MB)
web.statistics.1.content.1.ds_graph_options.storage1_total.color="#FF7777"
web.statistics.1.content.1.ds_graph_options.storage1_used.label=Storage1 used space (MB)
web.statistics.1.content.1.ds_graph_options.storage1_used.lines={ fill: true }
web.statistics.1.content.1.ds_graph_options.storage1_used.color="#7777FF"

web.statistics.1.content.2.title=Storage2
web.statistics.1.content.2.graph.1=storage2_total
web.statistics.1.content.2.graph.2=storage2_used
web.statistics.1.content.2.ds_graph_options.storage2_total.label=Storage2 total space (MB)
web.statistics.1.content.2.ds_graph_options.storage2_total.color="#FF7777"
web.statistics.1.content.2.ds_graph_options.storage2_used.label=Storage2 used space (MB)
web.statistics.1.content.2.ds_graph_options.storage2_used.lines={ fill: true }
web.statistics.1.content.2.ds_graph_options.storage2_used.color="#7777FF"

The configuration may also need some explanation

We do configure 2 graphs each having 2 curves. The first curve represent the total and is using static data extracted previously. This curve will be represented as a light red line.

The second curve is representing the usage of disk and is represented as a light blue line filled. The parameters defining the curve are define by the keyword ds_graph_options. Details of this parameter can be found in javascriptrrd help page. Restart rpimonitor to activate the new graph.

After waiting a little time to let the system extract data you will see this kind of graph.

_images/hdd003.png

Advanced service monitoring configuration

Here is an example of configuration proposed by Münir Ozan TOPCU:

########################################################################
# Extract information about Services
# 
########################################################################
dynamic.1.name=kodi_desc
dynamic.1.source=service kodi status | grep "kodi.service - "
dynamic.1.regexp=- (.*)
dynamic.2.name=kodi_act
dynamic.2.source=service kodi status | grep "Active: "
dynamic.2.regexp=(\(.*\))
dynamic.3.name=kodi_runtime
dynamic.3.source=service kodi status | grep "Active: "
dynamic.3.regexp=; (.*)

dynamic.4.name=rpimonitor_desc
dynamic.4.source=service rpimonitor status | grep "rpimonitor.service -"
dynamic.4.regexp=- (.*)
dynamic.5.name=rpimonitor_act
dynamic.5.source=service rpimonitor status | grep "Active: "
dynamic.5.regexp=(\(.*\))
dynamic.6.name=rpimonitor_runtime
dynamic.6.source=service rpimonitor status | grep "Active: "
dynamic.6.regexp=; (.*)

dynamic.7.name=smbd_desc
dynamic.7.source=service smbd status | grep "smbd.service - "
dynamic.7.regexp=- (.*)
dynamic.8.name=smbd_act
dynamic.8.source=service smbd status | grep "Active: "
dynamic.8.regexp=(\(.*\))
dynamic.9.name=smbd_runtime
dynamic.9.source=service smbd status | grep "Active: "
dynamic.9.regexp=; (.*)

dynamic.10.name=sslocal_desc
dynamic.10.source=service sslocal status | grep "sslocal.service - "
dynamic.10.regexp=- (.*)
dynamic.11.name=sslocal_act
dynamic.11.source=service sslocal status | grep "Active: "
dynamic.11.regexp=(\(.*\))
dynamic.12.name=sslocal_runtime
dynamic.12.source=service sslocal status | grep "Active: "
dynamic.12.regexp=; (.*)

dynamic.13.name=ssh_desc
dynamic.13.source=service ssh status | grep "ssh.service - "
dynamic.13.regexp=- (.*)
dynamic.14.name=ssh_act
dynamic.14.source=service ssh status | grep "Active: "
dynamic.14.regexp=(\(.*\))
dynamic.15.name=ssh_runtime
dynamic.15.source=service ssh status | grep "Active: "
dynamic.15.regexp=; (.*)

dynamic.16.name=xrdp_desc
dynamic.16.source=service xrdp status | grep "xrdp.service - "
dynamic.16.regexp=- (.*)
dynamic.17.name=xrdp_act
dynamic.17.source=service xrdp status | grep "Active: "
dynamic.17.regexp=(\(.*\))
dynamic.18.name=xrdp_runtime
dynamic.18.source=service xrdp status | grep "Active: "
dynamic.18.regexp=; (.*)

dynamic.19.name=deluge_daemon_desc
dynamic.19.source=service deluge-daemon status | grep "deluge-daemon.service - "
dynamic.19.regexp=- (.*)
dynamic.20.name=deluge_daemon_act
dynamic.20.source=service deluge-daemon status | grep "Active: "
dynamic.20.regexp=(\(.*\))
dynamic.21.name=deluge_daemon_runtime
dynamic.21.source=service deluge-daemon status | grep "Active: "
dynamic.21.regexp=; (.*)

web.status.1.content.1.title="Services"
web.status.1.content.1.icon=daemons.png
web.status.1.content.1.line.1="<style type=\"text/css\">.tg331 {border-collapse:collapse;border-spacing:0;}.tg331 tr:nth-child(even){background-color: #f2f2f2}.tg331 table{border: 0px solid #e9e9e9;}.tg331 td{font-family:Arial, sans-serif;font-size:14px;padding:12px 2px;border-style:solid;border-width:0px;overflow:hidden;word-break:normal;}.tg331 th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:12px 2px;border-style:solid;border-width:0px;overflow:hidden;word-break:normal;}.tg331 .tg331-yw4l{vertical-align:top;text-align: left;}.tg331 hr {display: block;margin-top: 0.5em;margin-bottom: 0.5em;margin-left: auto;margin-right: auto;border-style: inset; border-width: 1px;}</style><table width=\"100%\" class=\"tg331\"><tr><td><b>Status</b></td><td><b>Service Name</b></td><td><b>Service Description</b></td><td><b>Run Time</b></td></tr><tr><td>"+Label(data.kodi_act,"=='(running)'","OK","success")+Label(data.kodi_act,"!='(running)'","KO","danger")+"</td><td><b>kodi</b></td><td>" + data.kodi_desc + "</td><td>"+Label(data.kodi_act,"=='(running)'",data.kodi_runtime,"default")+Label(data.kodi_act,"!='(running)'","-","default")+"</td></tr><tr><td>"+Label(data.rpimonitor_act,"=='(running)'","OK","success")+Label(data.rpimonitor_act,"!='(running)'","KO","danger")+"</td><td><b>rpimonitor</b></td><td>" + data.rpimonitor_desc + "</td><td>"+Label(data.rpimonitor_act,"=='(running)'",data.rpimonitor_runtime,"default")+Label(data.rpimonitor_act,"!='(running)'","-","default")+"</td></tr><tr><td>"+Label(data.smbd_act,"=='(running)'","OK","success")+Label(data.smbd_act,"!='(running)'","KO","danger")+"</td><td><b>smbd</b></td><td>" + data.smbd_desc + "</td><td>"+Label(data.smbd_act,"=='(running)'",data.smbd_runtime,"default")+Label(data.smbd_act,"!='(running)'","-","default")+"</td></tr><tr><td>"+Label(data.sslocal_act,"=='(running)'","OK","success")+Label(data.sslocal_act,"!='(running)'","KO","danger")+"</td><td><b>sslocal</b></td><td>" + data.sslocal_desc + "</td><td>"+Label(data.sslocal_act,"=='(running)'",data.sslocal_runtime,"default")+Label(data.sslocal_act,"!='(running)'","-","default")+"</td></tr><tr><td>"+Label(data.ssh_act,"=='(running)'","OK","success")+Label(data.ssh_act,"!='(running)'","KO","danger")+"</td><td><b>SSH</b></td><td>" + data.ssh_desc + "</td><td>"+Label(data.ssh_act,"=='(running)'",data.ssh_runtime,"default")+Label(data.ssh_act,"!='(running)'","-","default")+"</td></tr><tr><td>"+Label(data.xrdp_act,"=='(running)'","OK","success")+Label(data.xrdp_act,"!='(running)'","KO","danger")+"</td><td><b>xrdp</b></td><td>" + data.xrdp_desc + "</td><td>"+Label(data.xrdp_act,"=='(running)'",data.xrdp_runtime,"default")+Label(data.xrdp_act,"!='(running)'","-","default")+"</td></tr><tr><td>"+Label(data.deluge_daemon_act,"=='(running)'","OK","success")+Label(data.deluge_daemon_act,"!='(running)'","KO","danger")+"</td><td><b>deluge_daemon</b></td><td>" + data.deluge_daemon_desc + "</td><td>"+Label(data.deluge_daemon_act,"=='(running)'",data.deluge_daemon_runtime,"default")+Label(data.deluge_daemon_act,"!='(running)'","-","default")+"</td></tr></table>"

Here is the result:

_images/advancedservices001.png

Monitor rclone

Todo

write this section

Use MRTG with RPi-Monitor in read-only mode

Todo

write this section

Monitor a TOR relay

Here is an example of configuration proposed by Luiz Kill: on tor-info

#  Tor relay information
#  Page: 1
#  Information               Status     Statistics
#  - received                - yes      - yes
#  - send                    - yes      - yes
########################################################################

static.100.name=tor_bw_rate1
static.100.source=/usr/local/etc/tor/torrc
static.100.regexp=RelayBandwidthRate\s+(\d+)
static.100.postprocess=$1*-1

static.101.name=tor_bw_burst1
static.101.source=/usr/local/etc/tor/torrc
static.101.regexp=RelayBandwidthBurst\s+(\d+)
static.101.postprocess=$1*-1

static.102.name=tor_bw_rate2
static.102.source=/usr/local/etc/tor/torrc
static.102.regexp=RelayBandwidthRate\s+(\d+)
static.102.postprocess=$1*1

static.103.name=tor_bw_burst2
static.103.source=/usr/local/etc/tor/torrc
static.103.regexp=RelayBandwidthBurst\s+(\d+)
static.103.postprocess=$1*1

static.104.name=tor_nickname
static.104.source=/var/lib/rpimonitor/stat/tor_desc
static.104.regexp=Nickname.(.*)
static.104.postprocess=

static.105.name=tor_fingerprint
static.105.source=/var/lib/rpimonitor/stat/tor_desc
static.105.regexp=Fingerprint.(.*)
static.105.postprocess=

static.106.name=tor_version
static.106.source=/var/lib/rpimonitor/stat/tor_desc
static.106.regexp=Version.(.*)
static.106.postprocess=

static.107.name=tor_address
static.107.source=/var/lib/rpimonitor/stat/tor_desc
static.107.regexp=Address.(.*)
static.107.postprocess=

dynamic.102.name=tor_read
dynamic.102.source=/var/lib/rpimonitor/stat/tor_rx
dynamic.102.regexp=(.*)
dynamic.102.postprocess=$1*-1
dynamic.102.rrd=DERIVE
dynamic.102.max=0

dynamic.103.name=tor_written
dynamic.103.source=/var/lib/rpimonitor/stat/tor_tx
dynamic.103.regexp=(.*)
dynamic.103.postprocess=
dynamic.103.rrd=DERIVE
dynamic.103.min=0

dynamic.104.name=tor_uptime
dynamic.104.source=/var/lib/rpimonitor/stat/tor_desc
dynamic.104.regexp=Uptime.(.*)
dynamic.104.postprocess=$1
dynamic.104.rrd=GAUGE

dynamic.105.name=tor_published
dynamic.105.source=/var/lib/rpimonitor/stat/tor_desc
dynamic.105.regexp=Published.(.*)
dynamic.105.postprocess=
dynamic.105.rrd=

dynamic.106.name=tor_hibernating
dynamic.106.source=/var/lib/rpimonitor/stat/tor_desc
dynamic.106.regexp=Hibernating.(.*)
dynamic.106.postprocess=
dynamic.106.rrd=

dynamic.107.name=tor_observed_bw
dynamic.107.source=/var/lib/rpimonitor/stat/tor_desc
dynamic.107.regexp=Observed_Bandwidth.(.*)
dynamic.107.postprocess=
dynamic.107.rrd=

dynamic.108.name=tor_average_bw
dynamic.108.source=/var/lib/rpimonitor/stat/tor_desc
dynamic.108.regexp=Average_Bandwidth.(.*)
dynamic.108.postprocess=
dynamic.108.rrd=

dynamic.109.name=tor_burst_bw
dynamic.109.source=/var/lib/rpimonitor/stat/tor_desc
dynamic.109.regexp=Burst_Bandwidth.(.*)
dynamic.109.postprocess=
dynamic.109.rrd=

web.statistics.1.content.102.name=Tor - Traffic
web.statistics.1.content.102.graph.1=tor_written
web.statistics.1.content.102.graph.2=tor_read
web.statistics.1.content.102.graph.3=tor_bw_rate1
web.statistics.1.content.102.graph.5=tor_bw_rate2
web.statistics.1.content.102.graph.4=tor_bw_burst1
web.statistics.1.content.102.graph.6=tor_bw_burst2

web.statistics.1.content.102.ds_graph_options.tor_written.label=Written (bytes)
web.statistics.1.content.102.ds_graph_options.tor_written.lines={ fill: true }
web.statistics.1.content.102.ds_graph_options.tor_written.color="#66428A"

web.statistics.1.content.102.ds_graph_options.tor_read.label=Read (bytes)
web.statistics.1.content.102.ds_graph_options.tor_read.lines={ fill: true }
web.statistics.1.content.102.ds_graph_options.tor_read.color="#008937"

web.statistics.1.content.102.ds_graph_options.tor_bw_rate1.label=Read Rate Limit (bytes)
web.statistics.1.content.102.ds_graph_options.tor_bw_rate1.lines={ fill: false }
web.statistics.1.content.102.ds_graph_options.tor_bw_rate1.color="#ffff00"

web.statistics.1.content.102.ds_graph_options.tor_bw_burst1.label=Read Burst Limit (bytes)
web.statistics.1.content.102.ds_graph_options.tor_bw_burst1.lines={ fill: false }
web.statistics.1.content.102.ds_graph_options.tor_bw_burst1.color="#DF0101"

web.statistics.1.content.102.ds_graph_options.tor_bw_rate2.label=Write Rate Limit (bytes)
web.statistics.1.content.102.ds_graph_options.tor_bw_rate2.lines={ fill: false }
web.statistics.1.content.102.ds_graph_options.tor_bw_rate2.color="#ffff00"

web.statistics.1.content.102.ds_graph_options.tor_bw_burst2.label=Write Burst Limit (bytes)
web.statistics.1.content.102.ds_graph_options.tor_bw_burst2.lines={ fill: false }
web.statistics.1.content.102.ds_graph_options.tor_bw_burst2.color="#DF0101"

web.statistics.1.content.102.graph_options.yaxis={ tickFormatter: function (v) { if (Math.abs(v) > 1048576) return (Math.round(v*10/1024/1024)/10) + " MiB/s" ; if (Math.abs(v) > 1024) return (Math.round(v*10/1024)/10) + " KiB/s" ; else return v + " B/s" }, }

web.status.1.content.101.name=Tor
web.status.1.content.101.icon=tor.png
web.status.1.content.101.line.1="Version: <b>" + data.tor_version + "</b>"
web.status.1.content.101.line.2="Nickname: <b>" + data.tor_nickname + "</b> Fingerprint: <b>" + data.tor_fingerprint + "</b>"
web.status.1.content.101.line.3="Address: <b>" + data.tor_address + "</b>"
web.status.1.content.101.line.4="Last published: <b>" + data.tor_published + "</b>"
web.status.1.content.101.line.5="Uptime: <b>" + Uptime(data.tor_uptime) + "</b>"
web.status.1.content.101.line.6="Hibernating: <b>" + data.tor_hibernating + "</b>"
web.status.1.content.101.line.7="Average Bandwidth: <b>" + KMG(data.tor_average_bw) + "/s</b> Burst: <b>" + KMG(data.tor_burst_bw) + "/s</b> Observed: <b>" + KMG(data.tor_observed_bw) + "/s</b>"

web.status.1.content.101.line.8="Written: <b>"+KMG(data.tor_written)+"<i class='icon-arrow-up'></i></b> Read: <b>"+KMG(Math.abs(data.tor_read)) + "<i class='icon-arrow-down'></i></b>"
web.status.1.content.101.line.9="Other: <b><a target=_blank href='https://atlas.torproject.org/#details/" + data.tor_fingerprint + "'>Atlas</a> | <a target=_blank href='https://globe.torproject.org/#/relay/" + data.tor_fingerprint + "'>Globe</a></b>"

Here is the result:

_images/tor001.png