prometheus-node-exporter-lua: add filesystem metrics
authorWill May <redacted>
Wed, 11 Dec 2024 12:33:37 +0000 (12:33 +0000)
committerEtienne Champetier <redacted>
Sun, 24 May 2026 15:02:28 +0000 (11:02 -0400)
Add a collector for the various fileystem metrics which matches the
node-exporter behaviour. This collector supports the following metrics:

* node_filesystem_size_bytes
* node_filesystem_free_bytes
* node_filesystem_avail_bytes
* node_filesystem_files
* node_filesystem_files_free
* node_filesystem_readonly

Signed-off-by: Will May <redacted>
utils/prometheus-node-exporter-lua/Makefile
utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/filesystem.lua [new file with mode: 0644]

index e559a05a99ffb87aede4bb76bc9544693f5f878b..c5f0390d5d58afa6b3d47d2e378d1846d36ae9cf 100644 (file)
@@ -4,7 +4,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=prometheus-node-exporter-lua
-PKG_VERSION:=2026.05.06
+PKG_VERSION:=2026.05.07
 PKG_RELEASE:=1
 
 PKG_MAINTAINER:=Etienne CHAMPETIER <champetier.etienne@gmail.com>
@@ -81,6 +81,17 @@ define Package/prometheus-node-exporter-lua-dawn/install
        $(INSTALL_DATA) ./files/usr/lib/lua/prometheus-collectors/dawn.lua $(1)/usr/lib/lua/prometheus-collectors/
 endef
 
+define Package/prometheus-node-exporter-lua-filesystem
+  $(call Package/prometheus-node-exporter-lua/Default)
+  TITLE+= (filesystem collector)
+  DEPENDS:=prometheus-node-exporter-lua +luci-lib-nixio
+endef
+
+define Package/prometheus-node-exporter-lua-filesystem/install
+       $(INSTALL_DIR) $(1)/usr/lib/lua/prometheus-collectors
+       $(INSTALL_BIN) ./files/usr/lib/lua/prometheus-collectors/filesystem.lua $(1)/usr/lib/lua/prometheus-collectors/
+endef
+
 define Package/prometheus-node-exporter-lua-hostapd_stations
   $(call Package/prometheus-node-exporter-lua/Default)
   TITLE+= (hostapd_stations collector) - Requires a full hostapd / wpad build
@@ -293,6 +304,7 @@ endef
 $(eval $(call BuildPackage,prometheus-node-exporter-lua))
 $(eval $(call BuildPackage,prometheus-node-exporter-lua-bmx7))
 $(eval $(call BuildPackage,prometheus-node-exporter-lua-dawn))
+$(eval $(call BuildPackage,prometheus-node-exporter-lua-filesystem))
 $(eval $(call BuildPackage,prometheus-node-exporter-lua-hostapd_stations))
 $(eval $(call BuildPackage,prometheus-node-exporter-lua-hostapd_ubus_stations))
 $(eval $(call BuildPackage,prometheus-node-exporter-lua-hwmon))
diff --git a/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/filesystem.lua b/utils/prometheus-node-exporter-lua/files/usr/lib/lua/prometheus-collectors/filesystem.lua
new file mode 100644 (file)
index 0000000..25a1084
--- /dev/null
@@ -0,0 +1,85 @@
+-- depends on luci-lib-nixio
+local nix = require "nixio"
+
+local function scrape()
+  -- node exporter description - Filesystem size in bytes
+  local metric_size_bytes = metric("node_filesystem_size_bytes", "gauge")
+  -- node exporter description - Filesystem free space in bytes
+  local metric_free_bytes = metric("node_filesystem_free_bytes", "gauge")
+  -- node exporter description - Filesystem space available to non-root users in bytes
+  local metric_avail_bytes = metric("node_filesystem_avail_bytes", "gauge")
+  -- node exporter description - Filesystem total file nodes
+  local metric_files = metric("node_filesystem_files", "gauge")
+  -- node exporter description - Filesystem total free file nodes
+  local metric_files_free = metric("node_filesystem_files_free", "gauge")
+  -- node exporter description - Filesystem read-only status
+  local metric_readonly = metric("node_filesystem_readonly", "gauge")
+
+  for e in io.lines("/proc/self/mounts") do
+    local fields = space_split(e)
+
+    local device = fields[1]
+    local mount_point = fields[2]
+    local fs_type = fields[3]
+
+    -- Filter list from node exporter:
+    -- https://github.com/prometheus/node_exporter/blob/b9d0932179a0c5b3a8863f3d6cdafe8584cedc8e/collector/filesystem_linux.go#L36-L37
+    if mount_point:find("/dev/?", 1) ~= 1
+        and mount_point:find("/proc/?", 1) ~= 1
+        and mount_point:find("/run/credentials/?", 1) ~= 1
+        and mount_point:find("/sys/?", 1) ~= 1
+        and mount_point:find("/var/lib/docker/?", 1) ~= 1
+        and mount_point:find("/var/lib/containers/storage/?", 1) ~= 1
+        and fs_type ~= "autofs"
+        and fs_type ~= "binfmt_misc"
+        and fs_type ~= "bpf"
+        and fs_type ~= "cgroup"
+        and fs_type ~= "cgroup2"
+        and fs_type ~= "configfs"
+        and fs_type ~= "debugfs"
+        and fs_type ~= "devpts"
+        and fs_type ~= "devtmpfs"
+        and fs_type ~= "fusectl"
+        and fs_type ~= "hugetlbfs"
+        and fs_type ~= "iso9660"
+        and fs_type ~= "mqueue"
+        and fs_type ~= "nsfs"
+        and fs_type ~= "overlay"
+        and fs_type ~= "proc"
+        and fs_type ~= "procfs"
+        and fs_type ~= "pstore"
+        and fs_type ~= "rpc_pipefs"
+        and fs_type ~= "securityfs"
+        and fs_type ~= "selinuxfs"
+        and fs_type ~= "squashfs"
+        and fs_type ~= "sysfs"
+        and fs_type ~= "tracefs" then
+      -- note that this excludes / as it's an overlay filesystem
+
+      local stat = nix.fs.statvfs(mount_point)
+
+      -- https://github.com/torvalds/linux/blob/e5fa841af679cb830da6c609c740a37bdc0b8b35/include/linux/statfs.h#L31
+      local ST_RDONLY = 0x001
+
+      local labels = {
+        device = device,
+        fstype = fs_type,
+        mountpoint = mount_point,
+      }
+
+      local ro = 0
+      if (nix.bit.band(stat.flag, ST_RDONLY)) == 1 then
+        ro = 1
+      end
+
+      metric_size_bytes(labels, stat.blocks * stat.bsize)
+      metric_free_bytes(labels, stat.bfree * stat.bsize)
+      metric_avail_bytes(labels, stat.bavail * stat.bsize)
+      metric_files(labels, stat.files)
+      metric_files_free(labels, stat.ffree)
+      metric_readonly(labels, ro)
+    end
+  end
+end
+
+return { scrape = scrape }
git clone https://git.99rst.org/PROJECT