prometheus-node-exporter-lua: increase label density in hostapd_stations
authorMartin Weinelt <hexa@darmstadt.ccc.de>
Sun, 8 Nov 2020 23:15:34 +0000 (00:15 +0100)
committerEtienne Champetier <champetier.etienne@gmail.com>
Tue, 6 Jul 2021 17:37:36 +0000 (13:37 -0400)
Correlating data is only possible when we have more metadata, this adds
a bunch of labels for each client, that will increase the depth of
dashboards yet to come.

In particular the changes in this commit are:
 - renames the `ifname` label to `vif`
 - adds `frequency`, `channel`, `bssid`, `ssid`, `encryption` and `mode`

Signed-off-by: Martin Weinelt <hexa@darmstadt.ccc.de>
utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/hostapd_stations.lua

index 5e141e6bcfd218070bf8bb1fc7f4c4dd827d0b31..9c56e586cfd10e08bd7fe19a19f597cd5575e43a 100644 (file)
@@ -1,14 +1,46 @@
 local ubus = require "ubus"
 local bit32 = require "bit32"
 
-local function get_wifi_interfaces()
+local function get_wifi_interface_labels()
   local u = ubus.connect()
   local status = u:call("network.wireless", "status", {})
   local interfaces = {}
 
   for _, dev_table in pairs(status) do
     for _, intf in ipairs(dev_table['interfaces']) do
-      table.insert(interfaces, intf['ifname'])
+      local cfg = intf['config']
+
+      -- Migrate this to ubus interface once it exposes all interesting labels
+      local handle = io.popen("hostapd_cli -i " .. cfg['ifname'] .." status")
+      local hostapd_status = handle:read("*a")
+      handle:close()
+
+      local hostapd = {}
+      for line in hostapd_status:gmatch("[^\r\n]+") do
+        local name, value = string.match(line, "(.+)=(.+)")
+        if name == "phy" then
+          hostapd["vif"] = value
+        elseif name == "freq" then
+          hostapd["freq"] = value
+        elseif name == "channel" then
+          hostapd["channel"] = value
+        elseif name == "bssid[0]" then
+          hostapd["bssid"] = value
+        elseif name == "ssid[0]" then
+          hostapd["ssid"] = value
+        end
+      end
+
+      local labels = {
+        vif = hostapd['vif'],
+        ssid = hostapd['ssid'],
+        bssid = hostapd['bssid'],
+        encryption = cfg['encryption'], -- In a mixed scenario it would be good to know if A or B was used
+        frequency = hostapd['freq'],
+        channel = hostapd['channel'],
+      }
+
+      table.insert(interfaces, labels)
     end
   end
 
@@ -25,7 +57,7 @@ local function scrape()
   local metric_hostapd_station_rx_bytes = metric("hostapd_station_rx_bytes", "counter")
   local metric_hostapd_station_tx_packets = metric("hostapd_station_tx_packets", "counter")
   local metric_hostapd_station_tx_bytes = metric("hostapd_station_tx_bytes", "counter")
-  
+
   local metric_hostapd_station_inactive_msec = metric("hostapd_station_inactive_msec", "counter")
 
   local metric_hostapd_station_signal = metric("hostapd_station_signal", "gauge")
@@ -37,54 +69,50 @@ local function scrape()
   local metric_hostapd_station_vht_capb_su_beamformee = metric("hostapd_station_vht_capb_su_beamformee", "gauge")
   local metric_hostapd_station_vht_capb_mu_beamformee = metric("hostapd_station_vht_capb_mu_beamformee", "gauge")
 
-  local function evaluate_metrics(ifname, station, vals)
-    local label_station = {
-      ifname = ifname,
-      station = station,
-    }
-
+  local function evaluate_metrics(labels, vals)
     for k, v in pairs(vals) do
       if k == "flags" then
         if string.match(v, "[VHT]") then
-          metric_hostapd_station_vht(label_station, 1)
+          metric_hostapd_station_vht(labels, 1)
         end
         if string.match(v, "[HT]") then
-          metric_hostapd_station_ht(label_station, 1)
+          metric_hostapd_station_ht(labels, 1)
         end
         if string.match(v, "[WMM]") then
-          metric_hostapd_station_wmm(label_station, 1)
+          metric_hostapd_station_wmm(labels, 1)
         end
         if string.match(v, "[MFP]") then
-          metric_hostapd_station_mfp(label_station, 1)
+          metric_hostapd_station_mfp(labels, 1)
         end
       elseif k == "wpa" then
-        metric_hostapd_station_wpa(label_station, v)
+        metric_hostapd_station_wpa(labels, v)
       elseif k == "rx_packets" then
-        metric_hostapd_station_rx_packets(label_station, v)
+        metric_hostapd_station_rx_packets(labels, v)
       elseif k == "rx_bytes" then
-        metric_hostapd_station_rx_bytes(label_station, v)
+        metric_hostapd_station_rx_bytes(labels, v)
       elseif k == "tx_packets" then
-        metric_hostapd_station_tx_packets(label_station, v)
+        metric_hostapd_station_tx_packets(labels, v)
       elseif k == "tx_bytes" then
-        metric_hostapd_station_tx_bytes(label_station, v)
+        metric_hostapd_station_tx_bytes(labels, v)
       elseif k == "inactive_msec" then
-        metric_hostapd_station_inactive_msec(label_station, v)
+        metric_hostapd_station_inactive_msec(labels, v)
       elseif k == "signal" then
-        metric_hostapd_station_signal(label_station, v)
+        metric_hostapd_station_signal(labels, v)
       elseif k == "connected_time" then
-        metric_hostapd_station_connected_time(label_station, v)
+        metric_hostapd_station_connected_time(labels, v)
       elseif k == "sae_group" then
-        metric_hostapd_station_sae_group(label_station, v)
+        metric_hostapd_station_sae_group(labels, v)
       elseif k == "vht_caps_info" then
              local caps = tonumber(string.gsub(v, "0x", ""), 16)
-             metric_hostapd_station_vht_capb_su_beamformee(label_station, bit32.band(bit32.lshift(1, 12), caps) > 0 and 1 or 0)
-             metric_hostapd_station_vht_capb_mu_beamformee(label_station, bit32.band(bit32.lshift(1, 20), caps) > 0 and 1 or 0)
+             metric_hostapd_station_vht_capb_su_beamformee(labels, bit32.band(bit32.lshift(1, 12), caps) > 0 and 1 or 0)
+             metric_hostapd_station_vht_capb_mu_beamformee(labels, bit32.band(bit32.lshift(1, 20), caps) > 0 and 1 or 0)
       end
     end
   end
 
-  for _, ifname in ipairs(get_wifi_interfaces()) do
-    local handle = io.popen("hostapd_cli -i " .. ifname .." all_sta")
+  for _, labels in ipairs(get_wifi_interface_labels()) do
+    local vif = labels['vif']
+    local handle = io.popen("hostapd_cli -i " .. vif .." all_sta")
     local all_sta = handle:read("*a")
     handle:close()
 
@@ -94,7 +122,8 @@ local function scrape()
     for line in all_sta:gmatch("[^\r\n]+") do
       if string.match(line, "^%x[0123456789aAbBcCdDeE]:%x%x:%x%x:%x%x:%x%x:%x%x$") then
         if current_station ~= nil then
-          evaluate_metrics(ifname, current_station, current_station_values)
+          labels.station = current_station
+          evaluate_metrics(labels, current_station_values)
         end
         current_station = line
         current_station_values = {}
@@ -103,7 +132,8 @@ local function scrape()
         current_station_values[name] = value
       end
     end
-    evaluate_metrics(ifname, current_station, current_station_values)
+    labels.station = current_station
+    evaluate_metrics(labels, current_station_values)
   end
 end