]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #1555 from pjz/ipfs_health
authorCosta Tsaousis <costa@tsaousis.gr>
Fri, 13 Jan 2017 18:13:38 +0000 (20:13 +0200)
committerGitHub <noreply@github.com>
Fri, 13 Jan 2017 18:13:38 +0000 (20:13 +0200)
Add health tracking for ipfs

README.md
conf.d/health.d/haproxy.conf
conf.d/health_alarm_notify.conf
configs.signatures
plugins.d/alarm-notify.sh
python.d/README.md
python.d/haproxy.chart.py
src/freebsd_sysctl.c
src/macos_fw.c
src/macos_sysctl.c
src/proc_net_dev.c

index b6a7fc7cf29dfdeb3f657dcec0d07f8a4613d0ce..81b1c1464cc7d911f31e39c1b2ae30f14c214e52 100644 (file)
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank
  - **Sophisticated alarming**<br/>
    supports dynamic thresholds, hysteresis, alarm templates,
    multiple role-based notification methods (such as email, slack.com,
-   pushover.net, pushbullet.com telegram.org, twilio.com)
+   pushover.net, pushbullet.com telegram.org, twilio.com, messagebird.com)
    
  - **Extensible**<br/>
    you can monitor anything you can get a metric for,
index 8880fe9cfc96c2d672e95320ce571a144f059637..e49c70d485d9de4a3b3938dafce397f50ab89d32 100644 (file)
@@ -1,8 +1,27 @@
- template: haproxy_backend_server_status
-      on: haproxy_h.down
+template: haproxy_backend_server_status
+      on: haproxy_hs.down
    units: failed servers
    every: 10s
-    lookup: average -10s
+  lookup: average -10s
     crit: $this > 0
-    info: Some of your backend servers is down!
+    info: number of failed haproxy backend servers
+      to: sysadmin
+
+template: haproxy_backend_status
+      on: haproxy_hb.down
+   units: failed backend
+   every: 10s
+  lookup: average -10s
+    crit: $this > 0
+    info: number of failed haproxy backends
+      to: sysadmin
+
+template: haproxy_last_collected
+      on: haproxy_hb.down
+    calc: $now - $last_collected_t
+   units: seconds ago
+   every: 10s
+    warn: $this > (($status >= $WARNING)  ? ($update_every) : ( 5 * $update_every))
+    crit: $this > (($status == $CRITICAL) ? ($update_every) : (60 * $update_every))
+    info: number of seconds since the last successful data collection
       to: sysadmin
index dea4ea0511244604f62dae9f996b69a29af6545e..edc55184fb3420c77925ed8574de4091a76a3360 100644 (file)
@@ -9,6 +9,7 @@
 # - messages to your slack team (slack.com),
 # - messages to your telegram chat / group chat (telegram.org)
 # - sms messages to your cell phone or any sms enabled device (twilio.com)
+# - sms messages to your cell phone or any sms enabled device (messagebird.com)
 # - notifications to users on pagerduty.com
 #
 # The 'to' line given at netdata alarms defines a *role*, so that many
@@ -70,12 +71,13 @@ curl=""
 # In these examples, the first recipient receives all the alarms
 # while the second one receives only the critical ones:
 #
-#  email   : "user1@example.com user2@example.com|critical"
-#  pushover: "2987343...9437837 8756278...2362736|critical"
-#  telegram: "111827421 112746832|critical"
-#  slack   : "alarms disasters|critical"
-#  twilio  : "+15555555555 +17777777777|critical"
-#  pd      : "<pd_service_key_1> <pd_service_key_2>|critical"
+#  email      : "user1@example.com user2@example.com|critical"
+#  pushover   : "2987343...9437837 8756278...2362736|critical"
+#  telegram   : "111827421 112746832|critical"
+#  slack      : "alarms disasters|critical"
+#  twilio     : "+15555555555 +17777777777|critical"
+#  messagebird: "+15555555555 +17777777777|critical"
+#  pd         : "<pd_service_key_1> <pd_service_key_2>|critical"
 #
 # If a recipient is set to empty string, the default recipient of the given
 # notification method (email, pushover, telegram, slack, pd) will be used.
@@ -160,6 +162,26 @@ TWILIO_ACCOUNT_TOKEN=""
 TWILIO_NUMBER=""
 DEFAULT_RECIPIENT_TWILIO=""
 
+#------------------------------------------------------------------------------
+# Messagebird (messagebird.com) SMS options
+
+# multiple recipients can be given like this:
+#                  "+15555555555 +17777777777"
+
+# enable/disable sending messagebird SMS
+SEND_MESSAGEBIRD="YES"
+
+# to get an access key, create a free account at https://www.messagebird.com
+# verify and activate the account (no CC info needed)
+# login to your account and enter your phonenumber to get some free credits
+# to get the API key, click on 'API' in the sidebar, then 'API Access (REST)' 
+# click 'Add access key' and fill in data (you want a live key to send SMS)
+
+# Without an access key, netdata cannot send Messagebird text messages.
+MESSAGEBIRD_ACCESS_KEY=""
+MESSAGEBIRD_NUMBER=""
+DEFAULT_RECIPIENT_MESSAGEBIRD=""
+
 #------------------------------------------------------------------------------
 # telegram (telegram.org) global notification options
 
@@ -253,6 +275,8 @@ role_recipients_slack[sysadmin]="${DEFAULT_RECIPIENT_SLACK}"
 
 role_recipients_twilio[sysadmin]="${DEFAULT_RECIPIENT_TWILIO}"
 
+role_recipients_messagebird[sysadmin]="${DEFAULT_RECIPIENT_MESSAGEBIRD}"
+
 role_recipients_pd[sysadmin]="${DEFAULT_RECIPIENT_PD}"
 
 # -----------------------------------------------------------------------------
@@ -270,6 +294,8 @@ role_recipients_slack[domainadmin]="${DEFAULT_RECIPIENT_SLACK}"
 
 role_recipients_twilio[domainadmin]="${DEFAULT_RECIPIENT_TWILIO}"
 
+role_recipients_messagebird[domainadmin]="${DEFAULT_RECIPIENT_MESSAGEBIRD}"
+
 role_recipients_pd[domainadmin]="${DEFAULT_RECIPIENT_PD}"
 
 # -----------------------------------------------------------------------------
@@ -288,6 +314,8 @@ role_recipients_slack[dba]="${DEFAULT_RECIPIENT_SLACK}"
 
 role_recipients_twilio[dba]="${DEFAULT_RECIPIENT_TWILIO}"
 
+role_recipients_messagebird[dba]="${DEFAULT_RECIPIENT_MESSAGEBIRD}"
+
 role_recipients_pd[dba]="${DEFAULT_RECIPIENT_PD}"
 
 # -----------------------------------------------------------------------------
@@ -306,6 +334,8 @@ role_recipients_slack[webmaster]="${DEFAULT_RECIPIENT_SLACK}"
 
 role_recipients_twilio[webmaster]="${DEFAULT_RECIPIENT_TWILIO}"
 
+role_recipients_messagebird[webmaster]="${DEFAULT_RECIPIENT_MESSAGEBIRD}"
+
 role_recipients_pd[webmaster]="${DEFAULT_RECIPIENT_PD}"
 
 # -----------------------------------------------------------------------------
@@ -324,4 +354,6 @@ role_recipients_slack[proxyadmin]="${DEFAULT_RECIPIENT_SLACK}"
 
 role_recipients_twilio[proxyadmin]="${DEFAULT_RECIPIENT_TWILIO}"
 
+role_recipients_messagebird[proxyadmin]="${DEFAULT_RECIPIENT_MESSAGEBIRD}"
+
 role_recipients_pd[proxyadmin]="${DEFAULT_RECIPIENT_PD}"
index 198759f9cb193bb9868594c67d96836625191ec9..e83b90632e0946d04c2b2612f6941d2bae0eb1a5 100644 (file)
@@ -30,7 +30,9 @@ declare -A configs_signatures=(
   ['15d8401b56a74120f9f832873ec9c578']='health.d/postgres.conf'
   ['15e32114994b92be7853b88091e7c6fb']='python.d/exim.conf'
   ['174c21a6ce5de97bda83d502aa47a9f8']='health.d/apache.conf'
+  ['178281aa2241d4a3e6b798bb9c4ae577']='python.d/haproxy.conf'
   ['18ee1c6197a4381b1c1631ef6129824f']='apps_groups.conf'
+  ['1972e48345e6c3f0d65f94a03317622b']='health_alarm_notify.conf'
   ['1c12b678ab65f271a96da1bbd0a1ab1c']='health.d/softnet.conf'
   ['1ea8e8ef1fa8a3a0fcdfba236f4cb195']='python.d/mysql.conf'
   ['1ef0fd38e7969c023bc3fa6d89eaf6d6']='python.d/mdstat.conf'
@@ -243,8 +245,10 @@ declare -A configs_signatures=(
   ['a8bb4e1d0525f59692778ad8f675a77a']='python.d/example.conf'
   ['a8feb36776005bf419c90278787a1be8']='health.d/entropy.conf'
   ['a94af1c808aafdf00537d85ff2197ec8']='python.d/exim.conf'
+  ['a9ab68845db2fb695b7060273a6ac68e']='health_alarm_notify.conf'
   ['a9cd91675467c5426f5b51c47602c889']='apps_groups.conf'
   ['aa4bee249bfc0c4a88ac8c2ffb97aa0d']='health.d/squid.conf'
+  ['aa8b57a733c2035917acf81a8ebdfbe7']='health.d/haproxy.conf'
   ['abaf2e021f9f6ee5d1c4e4726f47348e']='health.d/ipc.conf'
   ['acaa6731a272f6d251afb357e99b518f']='apps_groups.conf'
   ['ade389c1b6efe0cff47c33e662731f0a']='python.d/squid.conf'
@@ -252,7 +256,9 @@ declare -A configs_signatures=(
   ['af44cc53aa2bc5cc8935667119567522']='python.d.conf'
   ['afdae4646c755ff2d117527fbf761c8e']='health.d/disks.conf'
   ['b07eebc6f58d19721ac069171b911d2a']='health_alarm_notify.conf'
+  ['b0c59b2bd7a10f6a3f2be6b4b27857db']='health.d/haproxy.conf'
   ['b0f0a0ac415e4b1a82187b80d211e83b']='python.d/mysql.conf'
+  ['b185914d4f795e1732273dc4c7a35845']='health.d/memory.conf'
   ['b27f10a38a95edbbec20f44a4728b7c4']='python.d.conf'
   ['b32164929eda7449a9677044e11151bf']='python.d.conf'
   ['b3fc4749b132e55ac0d3a0f92859237e']='health.d/tcp_resets.conf'
@@ -288,6 +294,7 @@ declare -A configs_signatures=(
   ['cd08e5534c94bf1f2cd28396c76b8bbc']='health.d/ram.conf'
   ['ce2e8768964a936f58c4c2144aee8a01']='health_alarm_notify.conf'
   ['ce3b65eac6c472b21905f7f72104f4c9']='python.d/nginx.conf'
+  ['cf48dfd828af70bea04db7a809f94358']='health.d/haproxy.conf'
   ['cfecf298bdafaa7e0a3a263548e82132']='python.d/sensors.conf'
   ['d11711b3647bc2bdd0292dd7deebbeb1']='health.d/net.conf'
   ['d1596fe068c8674efade49a4a8e22b5d']='health.d/isc_dhcpd.conf'
index 9f5ca1b09d0aae71ba2fc1fdfa406c5d06421aa4..3dbc0c7c324003b185b07a41e1617155975da743 100755 (executable)
@@ -22,6 +22,7 @@
 #  - twilio.com notifications by Levi Blaney @shadycuz PR #1211
 #  - kafka notifications
 #  - pagerduty.com notifications by Jim Cooley @jimcooley PR #1373
+#  - messagebird.com notifications by @tech_no_logical
 
 # -----------------------------------------------------------------------------
 # testing notifications
@@ -172,6 +173,7 @@ sendmail=
 SEND_SLACK="YES"
 SEND_PUSHOVER="YES"
 SEND_TWILIO="YES"
+SEND_MESSAGEBIRD="YES"
 SEND_TELEGRAM="YES"
 SEND_EMAIL="YES"
 SEND_PUSHBULLET="YES"
@@ -200,6 +202,12 @@ TWILIO_NUMBER=
 DEFAULT_RECIPIENT_TWILIO=
 declare -A role_recipients_twilio=()
 
+# messagebird configs
+MESSAGEBIRD_ACCESS_KEY=
+MESSAGEBIRD_NUMBER=
+DEFAULT_RECIPIENT_MESSAGEBIRD=
+declare -A role_recipients_messagebird=()
+
 # telegram configs
 TELEGRAM_BOT_TOKEN=
 DEFAULT_RECIPIENT_TELEGRAM=
@@ -315,6 +323,14 @@ do
         [ "${r}" != "disabled" ] && filter_recipient_by_criticality twilio "${r}" && arr_twilio[${r/|*/}]="1"
     done
 
+    # messagebird
+    a="${role_recipients_messagebird[${x}]}"
+    [ -z "${a}" ] && a="${DEFAULT_RECIPIENT_MESSAGEBIRD}"
+    for r in ${a//,/ }
+    do
+        [ "${r}" != "disabled" ] && filter_recipient_by_criticality messagebird "${r}" && arr_messagebird[${r/|*/}]="1"
+    done
+
     # telegram
     a="${role_recipients_telegram[${x}]}"
     [ -z "${a}" ] && a="${DEFAULT_RECIPIENT_TELEGRAM}"
@@ -356,6 +372,10 @@ to_pushbullet="${!arr_pushbullet[*]}"
 to_twilio="${!arr_twilio[*]}"
 [ -z "${to_twilio}" ] && SEND_TWILIO="NO"
 
+# build the list of messagebird recipients (phone numbers)
+to_messagebird="${!arr_messagebird[*]}"
+[ -z "${to_messagebird}" ] && SEND_MESSAGEBIRD="NO"
+
 # check array of telegram recipients (chat ids)
 to_telegram="${!arr_telegram[*]}"
 [ -z "${to_telegram}" ] && SEND_TELEGRAM="NO"
@@ -389,6 +409,9 @@ done
 # check twilio
 [ -z "${TWILIO_ACCOUNT_TOKEN}" -o -z "${TWILIO_ACCOUNT_SID}" -o -z "${TWILIO_NUMBER}" ] && SEND_TWILIO="NO"
 
+# check messagebird
+[ -z "${MESSAGEBIRD_ACCESS_KEY}" -o -z "${MESSAGEBIRD_NUMBER}" ] && SEND_MESSAGEBIRD="NO"
+
 # check telegram
 [ -z "${TELEGRAM_BOT_TOKEN}" ] && SEND_TELEGRAM="NO"
 
@@ -410,7 +433,7 @@ if [ "${SEND_PD}" = "YES" ]
 fi
 
 # if we need curl, check for the curl command
-if [ \( "${SEND_PUSHOVER}" = "YES" -o "${SEND_SLACK}" = "YES" -o "${SEND_TWILIO}" = "YES" -o "${SEND_TELEGRAM}" = "YES" -o "${SEND_PUSHBULLET}" = "YES" -o "${SEND_KAFKA}" = "YES" \) -a -z "${curl}" ]
+if [ \( "${SEND_PUSHOVER}" = "YES" -o "${SEND_SLACK}" = "YES" -o "${SEND_TWILIO}" = "YES" -o "${SEND_MESSAGEBIRD}" = "YES" -o "${SEND_TELEGRAM}" = "YES" -o "${SEND_PUSHBULLET}" = "YES" -o "${SEND_KAFKA}" = "YES" \) -a -z "${curl}" ]
     then
     curl="$(which curl 2>/dev/null || command -v curl 2>/dev/null)"
     if [ -z "${curl}" ]
@@ -422,6 +445,7 @@ if [ \( "${SEND_PUSHOVER}" = "YES" -o "${SEND_SLACK}" = "YES" -o "${SEND_TWILIO}
         SEND_TELEGRAM="NO"
         SEND_SLACK="NO"
         SEND_TWILIO="NO"
+        SEND_MESSAGEBIRD="NO"
         SEND_KAFKA="NO"
     fi
 fi
@@ -434,14 +458,15 @@ if [ "${SEND_EMAIL}" = "YES" -a -z "${sendmail}" ]
 fi
 
 # check that we have at least a method enabled
-if [   "${SEND_EMAIL}"      != "YES" \
-    -a "${SEND_PUSHOVER}"   != "YES" \
-    -a "${SEND_TELEGRAM}"   != "YES" \
-    -a "${SEND_SLACK}"      != "YES" \
-    -a "${SEND_TWILIO}"     != "YES" \
-    -a "${SEND_PUSHBULLET}" != "YES" \
-    -a "${SEND_KAFKA}"      != "YES" \
-    -a "${SEND_PD}"         != "YES" \
+if [   "${SEND_EMAIL}"          != "YES" \
+    -a "${SEND_PUSHOVER}"       != "YES" \
+    -a "${SEND_TELEGRAM}"       != "YES" \
+    -a "${SEND_SLACK}"          != "YES" \
+    -a "${SEND_TWILIO}"         != "YES" \
+    -a "${SEND_MESSAGEBIRD}"    != "YES" \
+    -a "${SEND_PUSHBULLET}"     != "YES" \
+    -a "${SEND_KAFKA}"          != "YES" \
+    -a "${SEND_PD}"             != "YES" \
     ]
     then
     fatal "All notification methods are disabled. Not sending notification to '${roles}' for '${name}' = '${value}' of chart '${chart}' for status '${status}'."
@@ -760,6 +785,39 @@ send_twilio() {
     return 1
 }
 
+# -----------------------------------------------------------------------------
+# messagebird sender
+
+send_messagebird() {
+    local accesskey="${1}" messagebirdnumber="${2}" recipients="${3}"  title="${4}" message="${5}" httpcode sent=0 user
+    if [ "${SEND_MESSAGEBIRD}" = "YES" -a ! -z "${accesskey}" -a ! -z "${messagebirdnumber}" -a ! -z "${recipients}" -a ! -z "${message}" -a ! -z "${title}" ]
+        then
+        #https://developers.messagebird.com/docs/messaging
+        for user in ${recipients}
+        do
+            httpcode=$(${curl} -X POST --write-out %{http_code} --silent --output /dev/null \
+                --data-urlencode "originator=${messagebirdnumber}" \
+                --data-urlencode "recipients=${user}" \
+                --data-urlencode "body=${title} ${message}" \
+                       --data-urlencode "datacoding=auto" \
+                -H "Authorization: AccessKey ${accesskey}" \
+                "https://rest.messagebird.com/messages")
+
+            if [ "${httpcode}" == "201" ]
+            then
+                info "sent Messagebird SMS for: ${host} ${chart}.${name} is ${status} to '${user}'"
+                sent=$((sent + 1))
+            else
+                error "failed to send Messagebird SMS for: ${host} ${chart}.${name} is ${status} to '${user}' with HTTP error code ${httpcode}."
+            fi
+        done
+
+        [ ${sent} -gt 0 ] && return 0
+    fi
+
+    return 1
+}
+
 # -----------------------------------------------------------------------------
 # telegram sender
 
@@ -999,6 +1057,18 @@ ${info}"
 
 SENT_TWILIO=$?
 
+# -----------------------------------------------------------------------------
+# send the messagebird SMS
+
+send_messagebird "${MESSAGEBIRD_ACCESS_KEY}" "${MESSAGEBIRD_NUMBER}" "${to_messagebird}" "${host} ${status_message} - ${name//_/ } - ${chart}" "${alarm} 
+Severity: ${severity}
+Chart: ${chart}
+Family: ${family}
+${info}"
+
+SENT_MESSAGEBIRD=$?
+
+
 # -----------------------------------------------------------------------------
 # send the telegram.org message
 
@@ -1123,14 +1193,15 @@ SENT_EMAIL=$?
 # -----------------------------------------------------------------------------
 # let netdata know
 
-if [   ${SENT_EMAIL}      -eq 0 \
-    -o ${SENT_PUSHOVER}   -eq 0 \
-    -o ${SENT_TELEGRAM}   -eq 0 \
-    -o ${SENT_SLACK}      -eq 0 \
-    -o ${SENT_TWILIO}     -eq 0 \
-    -o ${SENT_PUSHBULLET} -eq 0 \
-    -o ${SENT_KAFKA}      -eq 0 \
-    -o ${SENT_PD}         -eq 0 \
+if [   ${SENT_EMAIL}        -eq 0 \
+    -o ${SENT_PUSHOVER}     -eq 0 \
+    -o ${SENT_TELEGRAM}     -eq 0 \
+    -o ${SENT_SLACK}        -eq 0 \
+    -o ${SENT_TWILIO}       -eq 0 \
+    -o ${SENT_MESSAGEBIRD}  -eq 0 \
+    -o ${SENT_PUSHBULLET}   -eq 0 \
+    -o ${SENT_KAFKA}        -eq 0 \
+    -o ${SENT_PD}           -eq 0 \
     ]
     then
     # we did send something
index d0ad5120f2be4c59b6298cef8500edab5c1081fe..00f81342e3c05f2a80e3342ae3c9e3789d4302d8 100644 (file)
@@ -412,6 +412,56 @@ and restart/reload your FREERADIUS server.
 
 ---
 
+# haproxy
+
+Module monitors frontend and backend metrics such as bytes in, bytes out, sessions current, sessions in queue current.
+And health metrics such as backend servers status (server check should be used).
+
+Plugin can obtain data from url **OR** unix socket.
+
+**Requirement:**
+Socket MUST be readable AND writable by netdata user.
+
+It produces:
+
+1. **Frontend** family charts
+ * Kilobytes in/s 
+ * Kilobytes out/s
+ * Sessions current
+ * Sessions in queue current
+
+2. **Backend** family charts
+ * Kilobytes in/s 
+ * Kilobytes out/s
+ * Sessions current
+ * Sessions in queue current
+
+3. **Health** chart
+ * number of failed servers for every backend (in DOWN state)
+
+
+### configuration
+
+Sample:
+
+```yaml
+via_url:
+  user       : 'username' # ONLY IF stats auth is used
+  pass       : 'password' # # ONLY IF stats auth is used
+  url     : 'http://ip.address:port/url;csv;norefresh'
+```
+
+OR
+
+```yaml
+via_socket:
+  socket       : 'path/to/haproxy/sock'
+```
+
+If no configuration is given, module will fail to run.
+
+---
+
 # hddtemp
  
 Module monitors disk temperatures from one or more hddtemp daemons.
index 0f8e3e783e51cc14b3da7d99881fd4a3ee95b16c..2fb97d755bab93e5132e66d92a9fa4361202f770 100644 (file)
@@ -10,7 +10,7 @@ priority = 60000
 retries = 60
 
 # charts order (can be overridden if you want less charts, or different order)
-ORDER = ['fbin', 'fbout', 'fscur', 'fqcur', 'bbin', 'bbout', 'bscur', 'bqcur', 'health_down']
+ORDER = ['fbin', 'fbout', 'fscur', 'fqcur', 'bbin', 'bbout', 'bscur', 'bqcur', 'health_sdown', 'health_bdown']
 CHARTS = {
     'fbin': {
         'options': [None, "Kilobytes in", "kilobytes in/s", 'Frontend', 'haproxy_f.bin', 'line'],
@@ -44,8 +44,12 @@ CHARTS = {
         'options': [None, "Sessions in queue", "sessions", 'Backend', 'haproxy_b.qcur', 'line'],
         'lines': [
         ]},
-    'health_down': {
-        'options': [None, "Servers in DOWN state", "failed servers", 'Health', 'haproxy_h.down', 'line'],
+    'health_sdown': {
+        'options': [None, "Number of servers in backend in DOWN state", "failed servers", 'Health', 'haproxy_hs.down', 'line'],
+        'lines': [
+        ]},
+    'health_bdown': {
+        'options': [None, "Is backend alive? 1 = DOWN", "failed backend", 'Health', 'haproxy_hb.down', 'line'],
         'lines': [
         ]}
 }
@@ -93,7 +97,8 @@ class Service(UrlService, SocketService):
             self.definitions['bbout']['lines'].append(['_'.join(['bbout', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'incremental', 1, 1024])
             self.definitions['bscur']['lines'].append(['_'.join(['bscur', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
             self.definitions['bqcur']['lines'].append(['_'.join(['bqcur', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
-            self.definitions['health_down']['lines'].append(['_'.join(['hdown', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
+            self.definitions['health_sdown']['lines'].append(['_'.join(['hsdown', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
+            self.definitions['health_bdown']['lines'].append(['_'.join(['hbdown', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
                 
     def _get_data(self):
         """
@@ -127,8 +132,9 @@ class Service(UrlService, SocketService):
                 to_netdata.update({'_'.join([_, backend['# pxname']]): int(backend[_[1:]]) if backend.get(_[1:]) else 0})
 
         for _ in range(len(back_ends)):
-            to_netdata.update({'_'.join(['hdown', back_ends[_]['# pxname']]):
+            to_netdata.update({'_'.join(['hsdown', back_ends[_]['# pxname']]):
                            len([server for server in servers if is_server_down(server, back_ends, _)])})
+            to_netdata.update({'_'.join(['hbdown', back_ends[_]['# pxname']]): 1 if is_backend_down(back_ends, _) else 0})
 
         return to_netdata
 
@@ -160,6 +166,12 @@ def is_server(server):
 
 def is_server_down(server, back_ends, _):
     try:
-        return server['# pxname'] == back_ends[_]['# pxname'] and server['status'] != 'UP' and server['status'] != 'no check'
+        return server['# pxname'] == back_ends[_]['# pxname'] and server['status'] == 'DOWN'
+    except Exception:
+        return False
+
+def is_backend_down(back_ends, _):
+    try:
+        return back_ends[_]['status'] == 'DOWN'
     except Exception:
         return False
index 26c5f9c379756664e93c782c92a62dc6a8bc9d6a..7edaf4f020b796b2db3a503a08428a2ed68c617c 100644 (file)
@@ -35,6 +35,8 @@
 #include <netinet/icmp6.h>
 // NEEDED BY do_space, do_inodes
 #include <sys/mount.h>
+// NEEDED BY do_uptime
+#include <time.h>
 
 #define KILO_FACTOR 1024
 #define MEGA_FACTOR 1048576     // 1024 * 1024
@@ -62,7 +64,7 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
         do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1,
         do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1, do_icmp6_router = -1,
-        do_icmp6_neighbor = -1, do_icmp6_types = -1, do_space = -1, do_inodes = -1;
+        do_icmp6_neighbor = -1, do_icmp6_types = -1, do_space = -1, do_inodes = -1, do_uptime = -1;
 
     if (unlikely(do_cpu == -1)) {
         do_cpu                  = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
@@ -116,6 +118,7 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         do_icmp6_types          = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
         do_space                = config_get_boolean("plugin:freebsd:sysctl", "space usage for all disks", 1);
         do_inodes               = config_get_boolean("plugin:freebsd:sysctl", "inodes usage for all disks", 1);
+        do_uptime               = config_get_boolean("plugin:macos:sysctl", "system uptime", 1);
     }
 
     RRDSET *st;
@@ -269,6 +272,9 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
     int mntsize;
     char mntonname[MNAMELEN + 1];
 
+    // NEEDED BY: do_uptime
+    struct timespec boot_time, cur_time;
+
     // --------------------------------------------------------------------
 
     if (last_loadavg_usec <= dt) {
@@ -2174,5 +2180,26 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         }
     }
 
+    // --------------------------------------------------------------------
+
+    if (likely(do_uptime)) {
+        if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
+            do_uptime = 0;
+            error("DISABLED: system.uptime");
+        } else {
+            clock_gettime(CLOCK_REALTIME, &cur_time);
+            st = rrdset_find("system.uptime");
+
+            if(unlikely(!st)) {
+                st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
+                rrddim_add(st, "uptime", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "uptime", cur_time.tv_sec - boot_time.tv_sec);
+            rrdset_done(st);
+        }
+    }
+
     return 0;
 }
index 47d70eda7b34f9b442d1b8e4b43dfe890eee79d6..a62aa7a7e257f4a82192bf776ceb46f161bc0b7b 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 #include <IOKit/IOKitLib.h>
 #include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/IOBSD.h>
+// NEEDED BY do_space, do_inodes
+#include <sys/mount.h>
+// NEEDED BY: struct ifaddrs, getifaddrs()
+#include <net/if.h>
+#include <ifaddrs.h>
+
+// NEEDED BY: do_bandwidth
+#define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+
+#define MAXDRIVENAME 31
+
+#define KILO_FACTOR 1024
+#define MEGA_FACTOR 1048576     // 1024 * 1024
+#define GIGA_FACTOR 1073741824  // 1024 * 1024 * 1024
 
 int do_macos_iokit(int update_every, usec_t dt) {
     (void)dt;
 
-    static int do_io = -1;
+    static int do_io = -1, do_space = -1, do_inodes = -1, do_bandwidth = -1;
 
     if (unlikely(do_io == -1)) {
-        do_io                  = config_get_boolean("plugin:macos:iokit", "disk i/o", 1);
+        do_io                   = config_get_boolean("plugin:macos:iokit", "disk i/o", 1);
+        do_space                = config_get_boolean("plugin:macos:sysctl", "space usage for all disks", 1);
+        do_inodes               = config_get_boolean("plugin:macos:sysctl", "inodes usage for all disks", 1);
+        do_bandwidth            = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1);
     }
 
     RRDSET *st;
 
     mach_port_t         master_port;
-    io_registry_entry_t drive;
+    io_registry_entry_t drive, drive_media;
     io_iterator_t       drive_list;
-    CFNumberRef         number;
     CFDictionaryRef     properties, statistics;
-    UInt64              value;
+    CFStringRef         name;
+    CFNumberRef         number;
+    kern_return_t       status;
     collected_number    total_disk_reads = 0;
     collected_number    total_disk_writes = 0;
+    struct diskstat {
+        char name[MAXDRIVENAME];
+        collected_number bytes_read;
+        collected_number bytes_write;
+        collected_number reads;
+        collected_number writes;
+        collected_number time_read;
+        collected_number time_write;
+        collected_number latency_read;
+        collected_number latency_write;
+    } diskstat;
+    struct cur_diskstat {
+        collected_number duration_read_ns;
+        collected_number duration_write_ns;
+        collected_number busy_time_ns;
+    } cur_diskstat;
+    struct prev_diskstat {
+        collected_number bytes_read;
+        collected_number bytes_write;
+        collected_number operations_read;
+        collected_number operations_write;
+        collected_number duration_read_ns;
+        collected_number duration_write_ns;
+        collected_number busy_time_ns;
+    } prev_diskstat;
+
+    // NEEDED BY: do_space, do_inodes
+    struct statfs *mntbuf;
+    int mntsize, i;
+    char mntonname[MNAMELEN + 1];
+    char title[4096 + 1];
+
+    // NEEDED BY: do_bandwidth
+    struct ifaddrs *ifa, *ifap;
 
     /* Get ports and services for drive statistics. */
-    if (IOMasterPort(bootstrap_port, &master_port)) {
+    if (unlikely(IOMasterPort(bootstrap_port, &master_port))) {
         error("MACOS: IOMasterPort() failed");
         do_io = 0;
         error("DISABLED: system.io");
     /* Get the list of all drive objects. */
-    } else if (IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list)) {
+    } else if (unlikely(IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list))) {
         error("MACOS: IOServiceGetMatchingServices() failed");
         do_io = 0;
         error("DISABLED: system.io");
     } else {
         while ((drive = IOIteratorNext(drive_list)) != 0) {
-            number = 0;
             properties = 0;
             statistics = 0;
-            value = 0;
+            number = 0;
+            bzero(&diskstat, sizeof(diskstat));
+
+            /* Get drive media object. */
+            status = IORegistryEntryGetChildEntry(drive, kIOServicePlane, &drive_media);
+            if (unlikely(status != KERN_SUCCESS)) {
+                IOObjectRelease(drive);
+                continue;
+            }
+
+            /* Get drive media properties. */
+            if (likely(!IORegistryEntryCreateCFProperties(drive_media, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
+                /* Get disk name. */
+                if (likely(name = (CFStringRef)CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey)))) {
+                    CFStringGetCString(name, diskstat.name, MAXDRIVENAME, kCFStringEncodingUTF8);
+                }
+            }
+
+            /* Release. */
+            CFRelease(properties);
+            IOObjectRelease(drive_media);
 
             /* Obtain the properties for this drive object. */
-            if (IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0)) {
+            if (unlikely(IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
                 error("MACOS: IORegistryEntryCreateCFProperties() failed");
                 do_io = 0;
                 error("DISABLED: system.io");
                 break;
-            } else if (properties != 0) {
+            } else if (likely(properties)) {
                 /* Obtain the statistics from the drive properties. */
-                statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey));
+                if (likely(statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)))) {
+
+                    // --------------------------------------------------------------------
 
-                if (statistics != 0) {
                     /* Get bytes read. */
-                    number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey));
-                    if (number != 0) {
-                        CFNumberGetValue(number, kCFNumberSInt64Type, &value);
-                        total_disk_reads += value;
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_read);
+                        total_disk_reads += diskstat.bytes_read;
                     }
 
                     /* Get bytes written. */
-                    number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey));
-                    if (number != 0) {
-                        CFNumberGetValue(number, kCFNumberSInt64Type, &value);
-                        total_disk_writes += value;
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_write);
+                        total_disk_writes += diskstat.bytes_write;
+                    }
+
+                    st = rrdset_find_bytype("disk", diskstat.name);
+                    if (unlikely(!st)) {
+                        st = rrdset_create("disk", diskstat.name, NULL, diskstat.name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+
+                        rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
+                        rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
+                    }
+                    else rrdset_next(st);
+
+                    prev_diskstat.bytes_read = rrddim_set(st, "reads", diskstat.bytes_read);
+                    prev_diskstat.bytes_write = rrddim_set(st, "writes", diskstat.bytes_write);
+                    rrdset_done(st);
+
+                    // --------------------------------------------------------------------
+
+                    /* Get number of reads. */
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.reads);
+                    }
+
+                    /* Get number of writes. */
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes);
+                    }
+
+                    st = rrdset_find_bytype("disk_ops", diskstat.name);
+                    if (unlikely(!st)) {
+                        st = rrdset_create("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
+                        st->isdetail = 1;
+
+                        rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                        rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    }
+                    else rrdset_next(st);
+
+                    prev_diskstat.operations_read = rrddim_set(st, "reads", diskstat.reads);
+                    prev_diskstat.operations_write = rrddim_set(st, "writes", diskstat.writes);
+                    rrdset_done(st);
+
+                    // --------------------------------------------------------------------
+
+                    /* Get reads time. */
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_read);
+                    }
+
+                    /* Get writes time. */
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write);
+                    }
+
+                    st = rrdset_find_bytype("disk_util", diskstat.name);
+                    if (unlikely(!st)) {
+                        st = rrdset_create("disk_util", diskstat.name, NULL, diskstat.name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
+                        st->isdetail = 1;
+
+                        rrddim_add(st, "utilization", NULL, 1, 10000000, RRDDIM_INCREMENTAL);
+                    }
+                    else rrdset_next(st);
+
+                    cur_diskstat.busy_time_ns = (diskstat.time_read + diskstat.time_write);
+                    prev_diskstat.busy_time_ns = rrddim_set(st, "utilization", cur_diskstat.busy_time_ns);
+                    rrdset_done(st);
+
+                    // --------------------------------------------------------------------
+
+                    /* Get reads latency. */
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_read);
+                    }
+
+                    /* Get writes latency. */
+                    if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) {
+                        CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write);
+                    }
+
+                    st = rrdset_find_bytype("disk_iotime", diskstat.name);
+                    if (unlikely(!st)) {
+                        st = rrdset_create("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
+                        st->isdetail = 1;
+
+                        rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_INCREMENTAL);
+                        rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_INCREMENTAL);
+                    }
+                    else rrdset_next(st);
+
+                    cur_diskstat.duration_read_ns = diskstat.time_read + diskstat.latency_read;
+                    cur_diskstat.duration_write_ns = diskstat.time_write + diskstat.latency_write;
+                    prev_diskstat.duration_read_ns = rrddim_set(st, "reads", cur_diskstat.duration_read_ns);
+                    prev_diskstat.duration_write_ns = rrddim_set(st, "writes", cur_diskstat.duration_write_ns);
+                    rrdset_done(st);
+
+                    // --------------------------------------------------------------------
+                    // calculate differential charts
+                    // only if this is not the first time we run
+
+                    if (likely(dt)) {
+
+                        // --------------------------------------------------------------------
+
+                        st = rrdset_find_bytype("disk_await", diskstat.name);
+                        if (unlikely(!st)) {
+                            st = rrdset_create("disk_await", diskstat.name, NULL, diskstat.name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
+                            st->isdetail = 1;
+
+                            rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
+                            rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_ABSOLUTE);
+                        }
+                        else rrdset_next(st);
+
+                        rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ?
+                            (cur_diskstat.duration_read_ns - prev_diskstat.duration_read_ns) / (diskstat.reads - prev_diskstat.operations_read) : 0);
+                        rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ?
+                            (cur_diskstat.duration_write_ns - prev_diskstat.duration_write_ns) / (diskstat.writes - prev_diskstat.operations_write) : 0);
+                        rrdset_done(st);
+
+                        // --------------------------------------------------------------------
+
+                        st = rrdset_find_bytype("disk_avgsz", diskstat.name);
+                        if (unlikely(!st)) {
+                            st = rrdset_create("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
+                            st->isdetail = 1;
+
+                            rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
+                            rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
+                        }
+                        else rrdset_next(st);
+
+                        rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ?
+                            (diskstat.bytes_read - prev_diskstat.bytes_read) / (diskstat.reads - prev_diskstat.operations_read) : 0);
+                        rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ?
+                            (diskstat.bytes_write - prev_diskstat.bytes_write) / (diskstat.writes - prev_diskstat.operations_write) : 0);
+                        rrdset_done(st);
+
+                        // --------------------------------------------------------------------
+
+                        st = rrdset_find_bytype("disk_svctm", diskstat.name);
+                        if (unlikely(!st)) {
+                            st = rrdset_create("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
+                            st->isdetail = 1;
+
+                            rrddim_add(st, "svctm", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
+                        }
+                        else rrdset_next(st);
+
+                        rrddim_set(st, "svctm", ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) ?
+                            (cur_diskstat.busy_time_ns - prev_diskstat.busy_time_ns) / ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) : 0);
+                        rrdset_done(st);
                     }
                 }
 
@@ -79,7 +300,7 @@ int do_macos_iokit(int update_every, usec_t dt) {
         IOObjectRelease(drive_list);
     }
 
-    if (do_io) {
+    if (likely(do_io)) {
         st = rrdset_find_bytype("system", "io");
         if (unlikely(!st)) {
             st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
@@ -93,5 +314,174 @@ int do_macos_iokit(int update_every, usec_t dt) {
         rrdset_done(st);
     }
 
+    // Can be merged with FreeBSD plugin
+    // --------------------------------------------------------------------------
+
+    if (likely(do_space || do_inodes)) {
+        // there is no mount info in sysctl MIBs
+        if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
+            error("MACOS: getmntinfo() failed");
+            do_space = 0;
+            error("DISABLED: disk_space.X");
+            do_inodes = 0;
+            error("DISABLED: disk_inodes.X");
+        } else {
+            for (i = 0; i < mntsize; i++) {
+                if (mntbuf[i].f_flags == MNT_RDONLY ||
+                        mntbuf[i].f_blocks == 0 ||
+                        // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
+                        strcmp(mntbuf[i].f_fstypename, "autofs") == 0 ||
+                        strcmp(mntbuf[i].f_fstypename, "procfs") == 0 ||
+                        strcmp(mntbuf[i].f_fstypename, "subfs") == 0 ||
+                        strcmp(mntbuf[i].f_fstypename, "devfs") == 0 ||
+                        strcmp(mntbuf[i].f_fstypename, "none") == 0)
+                    continue;
+
+                // --------------------------------------------------------------------------
+
+                if (likely(do_space)) {
+                    st = rrdset_find_bytype("disk_space", mntbuf[i].f_mntonname);
+                    if (unlikely(!st)) {
+                        snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+                        st = rrdset_create("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.space", title, "GB", 2023,
+                                           update_every,
+                                           RRDSET_TYPE_STACKED);
+
+                        rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
+                        rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRDDIM_ABSOLUTE);
+                        rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR,
+                                   RRDDIM_ABSOLUTE);
+                    } else
+                        rrdset_next(st);
+
+                    rrddim_set(st, "avail", (collected_number) mntbuf[i].f_bavail);
+                    rrddim_set(st, "used", (collected_number) (mntbuf[i].f_blocks - mntbuf[i].f_bfree));
+                    rrddim_set(st, "reserved_for_root", (collected_number) (mntbuf[i].f_bfree - mntbuf[i].f_bavail));
+                    rrdset_done(st);
+                }
+
+                // --------------------------------------------------------------------------
+
+                if (likely(do_inodes)) {
+                    st = rrdset_find_bytype("disk_inodes", mntbuf[i].f_mntonname);
+                    if (unlikely(!st)) {
+                        snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+                        st = rrdset_create("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.inodes", title, "Inodes", 2024,
+                                           update_every, RRDSET_TYPE_STACKED);
+
+                        rrddim_add(st, "avail", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                        rrddim_add(st, "used", NULL, 1, 1, RRDDIM_ABSOLUTE);
+                        rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRDDIM_ABSOLUTE);
+                    } else
+                        rrdset_next(st);
+
+                    rrddim_set(st, "avail", (collected_number) mntbuf[i].f_ffree);
+                    rrddim_set(st, "used", (collected_number) (mntbuf[i].f_files - mntbuf[i].f_ffree));
+                    rrdset_done(st);
+                }
+            }
+        }
+    }
+
+    // Can be merged with FreeBSD plugin
+    // --------------------------------------------------------------------
+
+    if (likely(do_bandwidth)) {
+        if (unlikely(getifaddrs(&ifap))) {
+            error("MACOS: getifaddrs()");
+            do_bandwidth = 0;
+            error("DISABLED: system.ipv4");
+        } else {
+            for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+                if (ifa->ifa_addr->sa_family != AF_LINK)
+                        continue;
+
+                // --------------------------------------------------------------------
+
+                st = rrdset_find_bytype("net", ifa->ifa_name);
+                if (unlikely(!st)) {
+                    st = rrdset_create("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
+
+                    rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "received", IFA_DATA(ibytes));
+                rrddim_set(st, "sent", IFA_DATA(obytes));
+                rrdset_done(st);
+
+                // --------------------------------------------------------------------
+
+                st = rrdset_find_bytype("net_packets", ifa->ifa_name);
+                if (unlikely(!st)) {
+                    st = rrdset_create("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "multicast_received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "multicast_sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "received", IFA_DATA(ipackets));
+                rrddim_set(st, "sent", IFA_DATA(opackets));
+                rrddim_set(st, "multicast_received", IFA_DATA(imcasts));
+                rrddim_set(st, "multicast_sent", IFA_DATA(omcasts));
+                rrdset_done(st);
+
+                // --------------------------------------------------------------------
+
+                st = rrdset_find_bytype("net_errors", ifa->ifa_name);
+                if (unlikely(!st)) {
+                    st = rrdset_create("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "inbound", IFA_DATA(ierrors));
+                rrddim_set(st, "outbound", IFA_DATA(oerrors));
+                rrdset_done(st);
+
+                // --------------------------------------------------------------------
+
+                st = rrdset_find_bytype("net_drops", ifa->ifa_name);
+                if (unlikely(!st)) {
+                    st = rrdset_create("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "inbound", IFA_DATA(iqdrops));
+                rrdset_done(st);
+
+                // --------------------------------------------------------------------
+
+                st = rrdset_find_bytype("net_events", ifa->ifa_name);
+                if (unlikely(!st)) {
+                    st = rrdset_create("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "collisions", IFA_DATA(collisions));
+                rrdset_done(st);
+            }
+
+            freeifaddrs(ifap);
+        }
+    }
+
+
     return 0;
 }
index 1c680a825798ef02f2aa403fc884ea162dea99d7..3a8498efa96a3d7a65b25a4ee43e8a485aaf2f47 100644 (file)
@@ -17,6 +17,8 @@
 #include <netinet/icmp_var.h>
 // NEEDED BY do_icmp6...
 #include <netinet/icmp6.h>
+// NEEDED BY do_uptime
+#include <time.h>
 
 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
 
@@ -35,7 +37,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
                do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
                do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1,
                do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1,
-               do_icmp6_router = -1, do_icmp6_neighbor = -1, do_icmp6_types = -1;
+               do_icmp6_router = -1, do_icmp6_neighbor = -1, do_icmp6_types = -1, do_uptime = -1;
 
 
     if (unlikely(do_loadavg == -1)) {
@@ -68,6 +70,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
         do_icmp6_router         = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
         do_icmp6_neighbor       = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
         do_icmp6_types          = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
+        do_uptime               = config_get_boolean("plugin:macos:sysctl", "system uptime", 1);
     }
 
     RRDSET *st;
@@ -206,6 +209,9 @@ int do_macos_sysctl(int update_every, usec_t dt) {
         u_long  msgs_out;
     } icmp6_total = {0, 0};
 
+    // NEEDED BY: do_uptime
+    struct timespec boot_time, cur_time;
+
     // --------------------------------------------------------------------
 
     if (last_loadavg_usec <= dt) {
@@ -1065,6 +1071,27 @@ int do_macos_sysctl(int update_every, usec_t dt) {
         }
     }
 
+    // --------------------------------------------------------------------
+
+    if (likely(do_uptime)) {
+        if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
+            do_uptime = 0;
+            error("DISABLED: system.uptime");
+        } else {
+            clock_gettime(CLOCK_REALTIME, &cur_time);
+            st = rrdset_find("system.uptime");
+
+            if(unlikely(!st)) {
+                st = rrdset_create("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
+                rrddim_add(st, "uptime", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "uptime", cur_time.tv_sec - boot_time.tv_sec);
+            rrdset_done(st);
+        }
+    }
+
     return 0;
 }
 
index 06182d44ff9559f8a15673f7c9cbee853d6ec859..99c77cd1ba398b58cb261e0acd1e3860c89b00f5 100644 (file)
 #include "common.h"
 
+struct netdev {
+    char *name;
+    uint32_t hash;
+    size_t len;
+
+    // flags
+    int configured;
+    int enabled;
+
+    int do_bandwidth;
+    int do_packets;
+    int do_errors;
+    int do_drops;
+    int do_fifo;
+    int do_compressed;
+    int do_events;
+
+    // data collected
+    unsigned long long rbytes;
+    unsigned long long rpackets;
+    unsigned long long rerrors;
+    unsigned long long rdrops;
+    unsigned long long rfifo;
+    unsigned long long rframe;
+    unsigned long long rcompressed;
+    unsigned long long rmulticast;
+
+    unsigned long long tbytes;
+    unsigned long long tpackets;
+    unsigned long long terrors;
+    unsigned long long tdrops;
+    unsigned long long tfifo;
+    unsigned long long tcollisions;
+    unsigned long long tcarrier;
+    unsigned long long tcompressed;
+
+    // charts
+    RRDSET *st_bandwidth;
+    RRDSET *st_packets;
+    RRDSET *st_errors;
+    RRDSET *st_drops;
+    RRDSET *st_fifo;
+    RRDSET *st_compressed;
+    RRDSET *st_events;
+
+    // dimensions
+    RRDDIM *rd_rbytes;
+    RRDDIM *rd_rpackets;
+    RRDDIM *rd_rerrors;
+    RRDDIM *rd_rdrops;
+    RRDDIM *rd_rfifo;
+    RRDDIM *rd_rframe;
+    RRDDIM *rd_rcompressed;
+    RRDDIM *rd_rmulticast;
+
+    RRDDIM *rd_tbytes;
+    RRDDIM *rd_tpackets;
+    RRDDIM *rd_terrors;
+    RRDDIM *rd_tdrops;
+    RRDDIM *rd_tfifo;
+    RRDDIM *rd_tcollisions;
+    RRDDIM *rd_tcarrier;
+    RRDDIM *rd_tcompressed;
+
+    struct netdev *next;
+};
+
+static struct netdev *netdev_root = NULL;
+
+static struct netdev *get_netdev(const char *name) {
+    static struct netdev *last = NULL;
+    struct netdev *d;
+
+    uint32_t hash = simple_hash(name);
+
+    // search it, from the last position to the end
+    for(d = last ; d ; d = d->next) {
+        if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
+            last = d->next;
+            return d;
+        }
+    }
+
+    // search it from the beginning to the last position we used
+    for(d = netdev_root ; d != last ; d = d->next) {
+        if(unlikely(hash == d->hash && !strcmp(name, d->name))) {
+            last = d->next;
+            return d;
+        }
+    }
+
+    // create a new one
+    d = callocz(1, sizeof(struct netdev));
+    d->name = strdupz(name);
+    d->hash = simple_hash(d->name);
+    d->len = strlen(d->name);
+
+    // link it to the end
+    if(netdev_root) {
+        struct netdev *e;
+        for(e = netdev_root; e->next ; e = e->next) ;
+        e->next = d;
+    }
+    else
+        netdev_root = d;
+
+    return d;
+}
+
 int do_proc_net_dev(int update_every, usec_t dt) {
+    (void)dt;
+
     static procfile *ff = NULL;
-    static int enable_new_interfaces = -1, enable_ifb_interfaces = -1;
+    static int enable_new_interfaces = -1, enable_ifb_interfaces = -1, enable_veth_interfaces = -1;
     static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
 
-    if(dt) {};
+    if(unlikely(enable_new_interfaces == -1)) {
+        enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
+        enable_ifb_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable ifb interfaces", CONFIG_ONDEMAND_NO);
+        enable_veth_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable veth interfaces", enable_new_interfaces);
+
+        do_bandwidth    = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        do_packets      = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        do_errors       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        do_drops        = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        do_fifo         = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        do_compressed   = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+        do_events       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    }
 
-    if(!ff) {
+    if(unlikely(!ff)) {
         char filename[FILENAME_MAX + 1];
         snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/dev");
         ff = procfile_open(config_get("plugin:proc:/proc/net/dev", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
+        if(unlikely(!ff)) return 1;
     }
-    if(!ff) return 1;
 
     ff = procfile_readall(ff);
-    if(!ff) return 0; // we return 0, so that we will retry to open it next time
-
-    if(enable_new_interfaces == -1) enable_new_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable new interfaces detected at runtime", CONFIG_ONDEMAND_ONDEMAND);
-    if(enable_ifb_interfaces == -1) enable_ifb_interfaces = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "enable ifb interfaces", CONFIG_ONDEMAND_NO);
-
-    if(do_bandwidth == -1)  do_bandwidth    = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "bandwidth for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-    if(do_packets == -1)    do_packets      = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-    if(do_errors == -1)     do_errors       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "errors for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-    if(do_drops == -1)      do_drops        = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "drops for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-    if(do_fifo == -1)       do_fifo         = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "fifo for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-    if(do_compressed == -1) do_compressed   = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "compressed packets for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
-    if(do_events == -1)     do_events       = config_get_boolean_ondemand("plugin:proc:/proc/net/dev", "frames, collisions, carrier counters for all interfaces", CONFIG_ONDEMAND_ONDEMAND);
+    if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
 
     uint32_t lines = procfile_lines(ff), l;
-
-    char *iface;
-    unsigned long long rbytes, rpackets, rerrors, rdrops, rfifo, rframe, rcompressed, rmulticast;
-    unsigned long long tbytes, tpackets, terrors, tdrops, tfifo, tcollisions, tcarrier, tcompressed;
-
     for(l = 2; l < lines ;l++) {
-        uint32_t words = procfile_linewords(ff, l);
-        if(words < 17) continue;
-
-        iface       = procfile_lineword(ff, l, 0);
-
-        rbytes      = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
-        rpackets    = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
-        rerrors     = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
-        rdrops      = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
-        rfifo       = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
-        rframe      = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
-        rcompressed = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
-        rmulticast  = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
-
-        tbytes      = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
-        tpackets    = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
-        terrors     = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
-        tdrops      = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
-        tfifo       = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
-        tcollisions = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
-        tcarrier    = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
-        tcompressed = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
-
-        int ddo_bandwidth = do_bandwidth, ddo_packets = do_packets, ddo_errors = do_errors, ddo_drops = do_drops, ddo_fifo = do_fifo, ddo_compressed = do_compressed, ddo_events = do_events;
-
-        int default_enable = enable_new_interfaces;
-
-        // prevent unused interfaces from creating charts
-        if(strcmp(iface, "lo") == 0)
-            default_enable = 0;
-        else {
-            int len = strlen(iface);
-            if(len >= 4 && strcmp(&iface[len-4], "-ifb") == 0)
-                default_enable = enable_ifb_interfaces;
-        }
+        // require 17 words on each line
+        if(unlikely(procfile_linewords(ff, l) < 17)) continue;
+
+        struct netdev *d = get_netdev(procfile_lineword(ff, l, 0));
+
+        if(unlikely(!d->configured)) {
+            // this is the first time we see this interface
+
+            // remember we configured it
+            d->configured = 1;
+
+            // start with the default enabled flag
+            d->enabled = enable_new_interfaces;
+            if(d->enabled) {
+                if(unlikely(!strcmp(d->name, "lo")))
+                    d->enabled = CONFIG_ONDEMAND_NO;
+                else if(unlikely(!strncmp(d->name, "veth", 4)))
+                    d->enabled = enable_veth_interfaces;
+                else if(unlikely(d->len >= 4 && strcmp(&d->name[d->len - 4], "-ifb") == 0))
+                    d->enabled = enable_ifb_interfaces;
+            }
 
-        // check if the user wants it
-        {
             char var_name[512 + 1];
-            snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", iface);
-            default_enable = config_get_boolean_ondemand(var_name, "enabled", default_enable);
-            if(default_enable == CONFIG_ONDEMAND_NO) continue;
-            if(default_enable == CONFIG_ONDEMAND_ONDEMAND && !rbytes && !tbytes) continue;
-
-            ddo_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", ddo_bandwidth);
-            ddo_packets = config_get_boolean_ondemand(var_name, "packets", ddo_packets);
-            ddo_errors = config_get_boolean_ondemand(var_name, "errors", ddo_errors);
-            ddo_drops = config_get_boolean_ondemand(var_name, "drops", ddo_drops);
-            ddo_fifo = config_get_boolean_ondemand(var_name, "fifo", ddo_fifo);
-            ddo_compressed = config_get_boolean_ondemand(var_name, "compressed", ddo_compressed);
-            ddo_events = config_get_boolean_ondemand(var_name, "events", ddo_events);
-
-            if(ddo_bandwidth == CONFIG_ONDEMAND_ONDEMAND && rbytes == 0 && tbytes == 0) ddo_bandwidth = 0;
-            if(ddo_errors == CONFIG_ONDEMAND_ONDEMAND && rerrors == 0 && terrors == 0) ddo_errors = 0;
-            if(ddo_drops == CONFIG_ONDEMAND_ONDEMAND && rdrops == 0 && tdrops == 0) ddo_drops = 0;
-            if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND && rfifo == 0 && tfifo == 0) ddo_fifo = 0;
-            if(ddo_compressed == CONFIG_ONDEMAND_ONDEMAND && rcompressed == 0 && tcompressed == 0) ddo_compressed = 0;
-            if(ddo_events == CONFIG_ONDEMAND_ONDEMAND && rframe == 0 && tcollisions == 0 && tcarrier == 0) ddo_events = 0;
-
-            // for absolute values, we need to switch the setting to 'yes'
-            // to allow it refresh from now on
-            // if(ddo_fifo == CONFIG_ONDEMAND_ONDEMAND) config_set(var_name, "fifo", "yes");
+            snprintfz(var_name, 512, "plugin:proc:/proc/net/dev:%s", d->name);
+            d->enabled = config_get_boolean_ondemand(var_name, "enabled", d->enabled);
+
+            if(d->enabled == CONFIG_ONDEMAND_NO)
+                continue;
+
+            d->do_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", do_bandwidth);
+            d->do_packets = config_get_boolean_ondemand(var_name, "packets", do_packets);
+            d->do_errors = config_get_boolean_ondemand(var_name, "errors", do_errors);
+            d->do_drops = config_get_boolean_ondemand(var_name, "drops", do_drops);
+            d->do_fifo = config_get_boolean_ondemand(var_name, "fifo", do_fifo);
+            d->do_compressed = config_get_boolean_ondemand(var_name, "compressed", do_compressed);
+            d->do_events = config_get_boolean_ondemand(var_name, "events", do_events);
         }
 
-        RRDSET *st;
+        if(unlikely(!d->enabled))
+            continue;
+
+        d->rbytes      = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
+        d->rpackets    = strtoull(procfile_lineword(ff, l, 2), NULL, 10);
+        d->rerrors     = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
+        d->rdrops      = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
+        d->rfifo       = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
+        d->rframe      = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
+        d->rcompressed = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
+        d->rmulticast  = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
+
+        d->tbytes      = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
+        d->tpackets    = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
+        d->terrors     = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
+        d->tdrops      = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
+        d->tfifo       = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
+        d->tcollisions = strtoull(procfile_lineword(ff, l, 14), NULL, 10);
+        d->tcarrier    = strtoull(procfile_lineword(ff, l, 15), NULL, 10);
+        d->tcompressed = strtoull(procfile_lineword(ff, l, 16), NULL, 10);
 
         // --------------------------------------------------------------------
 
-        if(ddo_bandwidth) {
-            st = rrdset_find_bytype("net", iface);
-            if(!st) {
-                st = rrdset_create("net", iface, NULL, iface, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
+        if(unlikely((d->do_bandwidth == CONFIG_ONDEMAND_ONDEMAND && (d->rbytes || d->tbytes))))
+            d->do_bandwidth = CONFIG_ONDEMAND_YES;
+
+        if(d->do_bandwidth == CONFIG_ONDEMAND_YES) {
+            if(unlikely(!d->st_bandwidth)) {
+                d->st_bandwidth = rrdset_find_bytype("net", d->name);
 
-                rrddim_add(st, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+                if(!d->st_bandwidth) {
+                    d->st_bandwidth = rrdset_create("net", d->name, NULL, d->name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
+                    d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, 1024, RRDDIM_INCREMENTAL);
+                    d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, 1024, RRDDIM_INCREMENTAL);
+                }
             }
-            else rrdset_next(st);
+            else rrdset_next(d->st_bandwidth);
 
-            rrddim_set(st, "received", rbytes);
-            rrddim_set(st, "sent", tbytes);
-            rrdset_done(st);
+            rrddim_set_by_pointer(d->st_bandwidth, d->rd_rbytes, d->rbytes);
+            rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, d->tbytes);
+            rrdset_done(d->st_bandwidth);
         }
 
         // --------------------------------------------------------------------
 
-        if(ddo_packets) {
-            st = rrdset_find_bytype("net_packets", iface);
-            if(!st) {
-                st = rrdset_create("net_packets", iface, NULL, iface, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
-                st->isdetail = 1;
+        if(unlikely((d->do_packets == CONFIG_ONDEMAND_ONDEMAND && (d->rpackets || d->tpackets || d->rmulticast))))
+            d->do_packets = CONFIG_ONDEMAND_YES;
 
-                rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        if(d->do_packets == CONFIG_ONDEMAND_YES) {
+            if(unlikely(!d->st_packets)) {
+                d->st_packets = rrdset_find_bytype("net_packets", d->name);
+
+                if(!d->st_packets) {
+                    d->st_packets = rrdset_create("net_packets", d->name, NULL, d->name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
+                    d->st_packets->isdetail = 1;
+
+                    d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                }
             }
-            else rrdset_next(st);
+            else rrdset_next(d->st_packets);
 
-            rrddim_set(st, "received", rpackets);
-            rrddim_set(st, "sent", tpackets);
-            rrddim_set(st, "multicast", rmulticast);
-            rrdset_done(st);
+            rrddim_set_by_pointer(d->st_packets, d->rd_rpackets, d->rpackets);
+            rrddim_set_by_pointer(d->st_packets, d->rd_tpackets, d->tpackets);
+            rrddim_set_by_pointer(d->st_packets, d->rd_rmulticast, d->rmulticast);
+            rrdset_done(d->st_packets);
         }
 
         // --------------------------------------------------------------------
 
-        if(ddo_errors) {
-            st = rrdset_find_bytype("net_errors", iface);
-            if(!st) {
-                st = rrdset_create("net_errors", iface, NULL, iface, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
-                st->isdetail = 1;
+        if(unlikely((d->do_errors == CONFIG_ONDEMAND_ONDEMAND && (d->rerrors || d->terrors))))
+            d->do_errors = CONFIG_ONDEMAND_YES;
+
+        if(d->do_errors == CONFIG_ONDEMAND_YES) {
+            if(unlikely(!d->st_errors)) {
+                d->st_errors = rrdset_find_bytype("net_errors", d->name);
 
-                rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                if(!d->st_errors) {
+                    d->st_errors = rrdset_create("net_errors", d->name, NULL, d->name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
+                    d->st_errors->isdetail = 1;
+
+                    d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
             }
-            else rrdset_next(st);
+            else rrdset_next(d->st_errors);
 
-            rrddim_set(st, "inbound", rerrors);
-            rrddim_set(st, "outbound", terrors);
-            rrdset_done(st);
+            rrddim_set_by_pointer(d->st_errors, d->rd_rerrors, d->rerrors);
+            rrddim_set_by_pointer(d->st_errors, d->rd_terrors, d->terrors);
+            rrdset_done(d->st_errors);
         }
 
         // --------------------------------------------------------------------
 
-        if(ddo_drops) {
-            st = rrdset_find_bytype("net_drops", iface);
-            if(!st) {
-                st = rrdset_create("net_drops", iface, NULL, iface, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
-                st->isdetail = 1;
+        if(unlikely((d->do_drops == CONFIG_ONDEMAND_ONDEMAND && (d->rdrops || d->tdrops))))
+            d->do_drops = CONFIG_ONDEMAND_YES;
+
+        if(d->do_drops == CONFIG_ONDEMAND_YES) {
+            if(unlikely(!d->st_drops)) {
+                d->st_drops = rrdset_find_bytype("net_drops", d->name);
 
-                rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                if(!d->st_drops) {
+                    d->st_drops = rrdset_create("net_drops", d->name, NULL, d->name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
+                    d->st_drops->isdetail = 1;
+
+                    d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
             }
-            else rrdset_next(st);
+            else rrdset_next(d->st_drops);
 
-            rrddim_set(st, "inbound", rdrops);
-            rrddim_set(st, "outbound", tdrops);
-            rrdset_done(st);
+            rrddim_set_by_pointer(d->st_drops, d->rd_rdrops, d->rdrops);
+            rrddim_set_by_pointer(d->st_drops, d->rd_tdrops, d->tdrops);
+            rrdset_done(d->st_drops);
         }
 
         // --------------------------------------------------------------------
 
-        if(ddo_fifo) {
-            st = rrdset_find_bytype("net_fifo", iface);
-            if(!st) {
-                st = rrdset_create("net_fifo", iface, NULL, iface, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
-                st->isdetail = 1;
+        if(unlikely((d->do_fifo == CONFIG_ONDEMAND_ONDEMAND && (d->rfifo || d->tfifo))))
+            d->do_fifo = CONFIG_ONDEMAND_YES;
+
+        if(d->do_fifo == CONFIG_ONDEMAND_YES) {
+            if(unlikely(!d->st_fifo)) {
+                d->st_fifo = rrdset_find_bytype("net_fifo", d->name);
 
-                rrddim_add(st, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                if(!d->st_fifo) {
+                    d->st_fifo = rrdset_create("net_fifo", d->name, NULL, d->name, "net.fifo", "Interface FIFO Buffer Errors", "errors", 7004, update_every, RRDSET_TYPE_LINE);
+                    d->st_fifo->isdetail = 1;
+
+                    d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
             }
-            else rrdset_next(st);
+            else rrdset_next(d->st_fifo);
 
-            rrddim_set(st, "receive", rfifo);
-            rrddim_set(st, "transmit", tfifo);
-            rrdset_done(st);
+            rrddim_set_by_pointer(d->st_fifo, d->rd_rfifo, d->rfifo);
+            rrddim_set_by_pointer(d->st_fifo, d->rd_tfifo, d->tfifo);
+            rrdset_done(d->st_fifo);
         }
 
         // --------------------------------------------------------------------
 
-        if(ddo_compressed) {
-            st = rrdset_find_bytype("net_compressed", iface);
-            if(!st) {
-                st = rrdset_create("net_compressed", iface, NULL, iface, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
-                st->isdetail = 1;
+        if(unlikely((d->do_compressed == CONFIG_ONDEMAND_ONDEMAND && (d->rcompressed || d->tcompressed))))
+            d->do_compressed = CONFIG_ONDEMAND_YES;
+
+        if(d->do_compressed == CONFIG_ONDEMAND_YES) {
+            if(unlikely(!d->st_compressed)) {
+                d->st_compressed = rrdset_find_bytype("net_compressed", d->name);
+                if(!d->st_compressed) {
+                    d->st_compressed = rrdset_create("net_compressed", d->name, NULL, d->name, "net.compressed", "Compressed Packets", "packets/s", 7005, update_every, RRDSET_TYPE_LINE);
+                    d->st_compressed->isdetail = 1;
 
-                rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
             }
-            else rrdset_next(st);
+            else rrdset_next(d->st_compressed);
 
-            rrddim_set(st, "received", rcompressed);
-            rrddim_set(st, "sent", tcompressed);
-            rrdset_done(st);
+            rrddim_set_by_pointer(d->st_compressed, d->rd_rcompressed, d->rcompressed);
+            rrddim_set_by_pointer(d->st_compressed, d->rd_tcompressed, d->tcompressed);
+            rrdset_done(d->st_compressed);
         }
 
         // --------------------------------------------------------------------
 
-        if(ddo_events) {
-            st = rrdset_find_bytype("net_events", iface);
-            if(!st) {
-                st = rrdset_create("net_events", iface, NULL, iface, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
-                st->isdetail = 1;
+        if(unlikely((d->do_events == CONFIG_ONDEMAND_ONDEMAND && (d->rframe || d->tcollisions || d->tcarrier))))
+            d->do_events = CONFIG_ONDEMAND_YES;
+
+        if(d->do_events == CONFIG_ONDEMAND_YES) {
+            if(unlikely(!d->st_events)) {
+                d->st_events = rrdset_find_bytype("net_events", d->name);
+                if(!d->st_events) {
+                    d->st_events = rrdset_create("net_events", d->name, NULL, d->name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
+                    d->st_events->isdetail = 1;
 
-                rrddim_add(st, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
-                rrddim_add(st, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_rframe      = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_tcollisions = rrddim_add(d->st_events, "collisions", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    d->rd_tcarrier    = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                }
             }
-            else rrdset_next(st);
+            else rrdset_next(d->st_events);
 
-            rrddim_set(st, "frames", rframe);
-            rrddim_set(st, "collisions", tcollisions);
-            rrddim_set(st, "carrier", tcarrier);
-            rrdset_done(st);
+            rrddim_set_by_pointer(d->st_events, d->rd_rframe,      d->rframe);
+            rrddim_set_by_pointer(d->st_events, d->rd_tcollisions, d->tcollisions);
+            rrddim_set_by_pointer(d->st_events, d->rd_tcarrier,    d->tcarrier);
+            rrdset_done(d->st_events);
         }
     }