Add application to monitor filesystem utilization.
Change-Id: I2305ac657c7b2c528d31e27f44b1a7d5015c2492
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/util/filesystem_monitor.cc b/aos/util/filesystem_monitor.cc
new file mode 100644
index 0000000..4efb141
--- /dev/null
+++ b/aos/util/filesystem_monitor.cc
@@ -0,0 +1,140 @@
+#include <sys/statvfs.h>
+
+#include "absl/strings/str_split.h"
+#include "gflags/gflags.h"
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/util/filesystem_generated.h"
+
+DEFINE_string(config, "aos_config.json", "File path of aos configuration");
+
+namespace aos::util {
+namespace {
+std::optional<std::string> ReadShortFile(std::string_view file_name) {
+ // Open as input and seek to end immediately.
+ std::ifstream file(std::string(file_name), std::ios_base::in);
+ if (!file.good()) {
+ VLOG(1) << "Can't read " << file_name;
+ return std::nullopt;
+ }
+ const size_t kMaxLineLength = 4096;
+ char buffer[kMaxLineLength];
+ file.read(buffer, kMaxLineLength);
+ if (!file.eof()) {
+ return std::nullopt;
+ }
+ return std::string(buffer, file.gcount());
+}
+} // namespace
+
+// Periodically sends out the Filesystems message with filesystem utilization
+// info.
+class FilesystemMonitor {
+ public:
+ FilesystemMonitor(aos::EventLoop *event_loop)
+ : event_loop_(event_loop),
+ sender_(event_loop_->MakeSender<FilesystemStatus>("/aos")) {
+ periodic_timer_ =
+ event_loop_->AddTimer([this]() { PublishFilesystemStatus(); });
+ event_loop_->OnRun([this]() {
+ periodic_timer_->Schedule(event_loop_->monotonic_now(),
+ std::chrono::seconds(5));
+ });
+ }
+
+ private:
+ void PublishFilesystemStatus() {
+ aos::Sender<FilesystemStatus>::Builder builder = sender_.MakeBuilder();
+
+ std::optional<std::string> contents = ReadShortFile("/proc/self/mountinfo");
+
+ CHECK(contents.has_value());
+
+ std::vector<flatbuffers::Offset<Filesystem>> filesystems;
+
+ // Iterate through /proc/self/mounts to find all the filesystems.
+ for (std::string_view line :
+ absl::StrSplit(std::string_view(contents->c_str(), contents->size()),
+ '\n', absl::SkipWhitespace())) {
+ // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt for
+ // the format.
+ std::vector<std::string_view> elements =
+ absl::StrSplit(line, ' ', absl::SkipWhitespace());
+
+ // First thing after - is the filesystem type.
+ size_t i = 6;
+ while (elements[i] != "-") {
+ ++i;
+ CHECK_LT(i + 1, elements.size());
+ }
+
+ // Mount point is the 4th element.
+ std::string mount_point(elements[4]);
+ std::string_view type = elements[i + 1];
+
+ // Ignore filesystems without reasonable types.
+ if (type != "ext2" && type != "xfs" && type != "vfat" && type != "ext3" &&
+ type != "ext4" && type != "tmpfs" && type != "devtmpfs") {
+ continue;
+ }
+ VLOG(1) << mount_point << ", type " << type;
+
+ struct statvfs info;
+
+ PCHECK(statvfs(mount_point.c_str(), &info) == 0);
+
+ VLOG(1) << "overall size: " << info.f_frsize * info.f_blocks << ", free "
+ << info.f_bfree * info.f_bsize << ", inodes " << info.f_files
+ << ", free " << info.f_ffree;
+
+ flatbuffers::Offset<flatbuffers::String> path_offset =
+ builder.fbb()->CreateString(mount_point);
+ flatbuffers::Offset<flatbuffers::String> type_offset =
+ builder.fbb()->CreateString(type);
+ Filesystem::Builder filesystem_builder =
+ builder.MakeBuilder<Filesystem>();
+ filesystem_builder.add_path(path_offset);
+ filesystem_builder.add_type(type_offset);
+ filesystem_builder.add_overall_space(info.f_frsize * info.f_blocks);
+ filesystem_builder.add_free_space(info.f_bfree * info.f_bsize);
+ filesystem_builder.add_overall_inodes(info.f_files);
+ filesystem_builder.add_free_inodes(info.f_ffree);
+
+ filesystems.emplace_back(filesystem_builder.Finish());
+ }
+
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Filesystem>>>
+ filesystems_offset = builder.fbb()->CreateVector(filesystems);
+
+ FilesystemStatus::Builder filesystem_status_builder =
+ builder.MakeBuilder<FilesystemStatus>();
+
+ filesystem_status_builder.add_filesystems(filesystems_offset);
+
+ (void)builder.Send(filesystem_status_builder.Finish());
+ }
+
+ aos::EventLoop *event_loop_;
+
+ aos::Sender<FilesystemStatus> sender_;
+
+ aos::TimerHandler *periodic_timer_;
+};
+
+} // namespace aos::util
+
+int main(int argc, char **argv) {
+ aos::InitGoogle(&argc, &argv);
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(FLAGS_config);
+
+ aos::ShmEventLoop shm_event_loop(&config.message());
+
+ aos::util::FilesystemMonitor filesystem_monitor(&shm_event_loop);
+
+ shm_event_loop.Run();
+
+ return 0;
+}