about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--README.md37
-rw-r--r--filesystem.c76
-rw-r--r--filesystem.h8
-rw-r--r--main.c2
4 files changed, 122 insertions, 1 deletions
diff --git a/README.md b/README.md
index 7ea87fa..1626b83 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,7 @@ including generated metrics, labels and configuration options.
 | Name | Description |
 | ---- | ----------- |
 | [`cpu`](#cpu) | CPU usage from `/proc/stat` and CPU frequency scaling data from sysfs. |
+| [`filesystem`](#filesystem) | Statistics of mounted filesystems from `statvfs(2)`. |
 | [`hwmon`](#hwmon) | Temperature, fan and voltage sensors from `/sys/class/hwmon`. |
 | [`meminfo`](#meminfo) | Memory usage statistics from `/proc/meminfo`. |
 | [`network`](#network) | Network device transmit/receive statistics from `/proc/net/dev`. |
@@ -82,13 +83,39 @@ Metrics and labels:
   `cpufreq/scaling_cur_freq` value under the CPU-specific sysfs
   directory.
 
+### `filesystem`
+
+Metrics:
+
+* `node_filesystem_size_bytes`: Total size of the filesystem.
+* `node_filesystem_free_bytes`: Number of free bytes in the
+  filesystem.
+* `node_filesystem_avail_bytes`: Number of free bytes available to
+  unprivileged users.
+* `node_filesystem_files`: Total number of inodes supported by the
+  filesystem.
+* `node_filesystem_files_free`: Number of free inodes.
+* `node_filesystem_readonly`: Whether the filesystem is mounted
+  read-only: `0` (rw) or `1` (ro).
+
+Labels:
+
+* `device`: Device node mounted at the location.
+* `fstype`: Mounted filesystem type.
+* `mountpoint`: Location where the filesystem is mounted.
+
+TODO: inclusion/exclusion lists.
+
+The data is derived from scanning `/proc/mounts` and calling
+`statvfs(2)` on all lines that pass the inclusion checks.
+
 ### `hwmon`
 
 The `hwmon` collector pulls data from all the sysfs subdirectories
 under `/sys/class/hwmon`. The supported entry types are temperature
 (`temp*`), fan (`fan*` and voltage (`in*`) sensors.
 
-Metrics and dimensions:
+Metrics:
 
 * `node_hwmon_temp_celsius`: Current temperature in degrees Celsius.
 * `node_hwmon_fan_rpm`: Current fan speed in RPM.
@@ -144,6 +171,14 @@ included in your `/proc/net/dev` file. A normal set is:
 |   | X | `colls` | Collisions while transmitting |
 |   | X | `carrier` | ? |
 
+By default, statistics are reported for all network interfaces except
+the loopback interface (`lo`). The `--network-include=` and
+`--network-exclude=` options can be used to define a comma-separated
+list of interface names to explicitly include and exclude,
+respectively. If an include list is set, only those interfaces are
+included. Otherwise, all interfaces *not* mentioned in the exclude
+list are included.
+
 ### `textfile`
 
 The `textfile` collector can be used to conveniently export custom
diff --git a/filesystem.c b/filesystem.c
new file mode 100644
index 0000000..84f6805
--- /dev/null
+++ b/filesystem.c
@@ -0,0 +1,76 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <string.h>
+#include <sys/statvfs.h>
+
+#include "filesystem.h"
+#include "util.h"
+
+// size of input buffer for paths and lines
+#define BUF_SIZE 256
+
+static void filesystem_collect(scrape_req *req, void *ctx);
+
+const struct collector filesystem_collector = {
+  .name = "filesystem",
+  .collect = filesystem_collect,
+};
+
+static void filesystem_collect(scrape_req *req, void *ctx) {
+  // buffers
+
+  const char *labels[][2] = {  // all filled by code
+    { "device", 0 },
+    { "fstype", 0 },
+    { "mountpoint", 0 },
+    { 0, 0 },
+  };
+  const char **dev = &labels[0][1];
+  const char **fstype = &labels[1][1];
+  const char **mount = &labels[2][1];
+
+  char buf[BUF_SIZE];
+
+  FILE *f;
+  struct statvfs fs;
+
+  // loop over /proc/mounts to get visible mounts
+
+  f = fopen("/proc/mounts", "r");
+  if (!f)
+    return;
+
+  while (fgets_line(buf, sizeof buf, f)) {
+    // extract device, mountpoint and filesystem type
+
+    char *p;
+    *dev = strtok_r(buf, " ", &p);
+    if (!*dev)
+      continue;
+    *mount = strtok_r(0, " ", &p);
+    if (!*mount)
+      continue;
+    *fstype = strtok_r(0, " ", &p);
+    if (!*fstype)
+      continue;
+
+    if (**dev != '/')
+      continue;
+    // TODO: device, mountpoint, filesystem exclude lists
+
+    // report metrics from statfs
+
+    if (statvfs(*mount, &fs) != 0)
+      continue;
+
+    double bs = fs.f_frsize;
+    scrape_write(req, "node_filesystem_avail_bytes", labels, fs.f_bavail * bs);
+    scrape_write(req, "node_filesystem_files", labels, fs.f_files);
+    scrape_write(req, "node_filesystem_files_free", labels, fs.f_ffree);
+    scrape_write(req, "node_filesystem_free_bytes", labels, fs.f_bfree * bs);
+    scrape_write(req, "node_filesystem_readonly", labels, fs.f_flag & ST_RDONLY ? 1.0 : 0.0);
+    scrape_write(req, "node_filesystem_size_bytes", labels, fs.f_blocks * bs);
+  }
+
+  fclose(f);
+}
diff --git a/filesystem.h b/filesystem.h
new file mode 100644
index 0000000..60485cf
--- /dev/null
+++ b/filesystem.h
@@ -0,0 +1,8 @@
+#ifndef PNANOE_FILESYSTEM_H_
+#define PNANOE_FILESYSTEM_H_ 1
+
+#include "collector.h"
+
+extern const struct collector filesystem_collector;
+
+#endif // PNANOE_FILESYSTEM_H_
diff --git a/main.c b/main.c
index 84647d0..77d4e49 100644
--- a/main.c
+++ b/main.c
@@ -6,6 +6,7 @@
 #include <string.h>
 
 #include "cpu.h"
+#include "filesystem.h"
 #include "hwmon.h"
 #include "meminfo.h"
 #include "network.h"
@@ -16,6 +17,7 @@
 
 static const struct collector *collectors[] = {
   &cpu_collector,
+  &filesystem_collector,
   &hwmon_collector,
   &meminfo_collector,
   &network_collector,