Add interface to access log files
The final goal is to use it to play logs directly from memory.
Change-Id: I82349b9542fd83c92014ceec37f11a832189bdd6
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/events/logging/BUILD b/aos/events/logging/BUILD
index 9f31b15..cec39dd 100644
--- a/aos/events/logging/BUILD
+++ b/aos/events/logging/BUILD
@@ -100,6 +100,8 @@
target_compatible_with = ["@platforms//os:linux"],
visibility = ["//visibility:public"],
deps = [
+ ":buffer_encoder",
+ ":file_operations",
"//aos/time",
"//aos/util:file",
"@com_github_google_glog//:glog",
diff --git a/aos/events/logging/log_backend.cc b/aos/events/logging/log_backend.cc
index 918a6e6..ad97f7d 100644
--- a/aos/events/logging/log_backend.cc
+++ b/aos/events/logging/log_backend.cc
@@ -4,9 +4,11 @@
#include <filesystem>
+#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "glog/logging.h"
+#include "aos/events/logging/file_operations.h"
#include "aos/util/file.h"
DEFINE_bool(direct, false,
@@ -334,6 +336,31 @@
return std::make_unique<FileHandler>(filename);
}
+std::vector<std::string> FileBackend::ListFiles() const {
+ std::filesystem::path directory(base_name_);
+ if (!is_directory(directory)) {
+ directory = directory.parent_path();
+ }
+ internal::LocalFileOperations operations(directory.string());
+ std::vector<std::string> files;
+ operations.FindLogs(&files);
+
+ std::vector<std::string> names;
+ const std::string prefix = absl::StrCat(base_name_, separator_);
+ for (const auto &file : files) {
+ CHECK(absl::StartsWith(file, prefix));
+ names.push_back(file.substr(prefix.size()));
+ }
+ return names;
+}
+
+std::unique_ptr<DataDecoder> FileBackend::GetDecoder(
+ std::string_view id) const {
+ const std::string filename = absl::StrCat(base_name_, separator_, id);
+ CHECK(std::filesystem::exists(filename));
+ return std::make_unique<DummyDecoder>(filename);
+}
+
RenamableFileBackend::RenamableFileBackend(std::string_view base_name)
: base_name_(base_name), separator_(base_name_.back() == '/' ? "" : "_") {}
diff --git a/aos/events/logging/log_backend.h b/aos/events/logging/log_backend.h
index 6f79bc3..193c54f 100644
--- a/aos/events/logging/log_backend.h
+++ b/aos/events/logging/log_backend.h
@@ -11,6 +11,7 @@
#include "absl/types/span.h"
+#include "aos/events/logging/buffer_encoder.h"
#include "aos/time/time.h"
namespace aos::logger {
@@ -237,7 +238,7 @@
int flags_ = 0;
};
-// Class that decouples log writing and media (file system or memory). It is
+// Interface to decouple log writing and media (file system or memory). It is
// handy to use for tests.
class LogBackend {
public:
@@ -249,8 +250,21 @@
virtual std::unique_ptr<LogSink> RequestFile(std::string_view id) = 0;
};
+// Interface to decouple reading of logs and media (file system, memory or S3).
+class LogSource {
+ public:
+ virtual ~LogSource() = default;
+
+ // Provides a list of readable sources for log reading.
+ virtual std::vector<std::string> ListFiles() const = 0;
+
+ // Entry point for reading the content of log file.
+ virtual std::unique_ptr<DataDecoder> GetDecoder(
+ std::string_view id) const = 0;
+};
+
// Implements requests log files from file system.
-class FileBackend : public LogBackend {
+class FileBackend : public LogBackend, public LogSource {
public:
// base_name is the path to the folder where log files are.
explicit FileBackend(std::string_view base_name);
@@ -259,6 +273,12 @@
// Request file from a file system. It is not open yet.
std::unique_ptr<LogSink> RequestFile(std::string_view id) override;
+ // List all files that looks like log files under base_name.
+ std::vector<std::string> ListFiles() const override;
+
+ // Open decoder to read the content of the file.
+ std::unique_ptr<DataDecoder> GetDecoder(std::string_view id) const override;
+
private:
const std::string base_name_;
const std::string_view separator_;
diff --git a/aos/events/logging/log_backend_test.cc b/aos/events/logging/log_backend_test.cc
index 4e6987f..2720e46 100644
--- a/aos/events/logging/log_backend_test.cc
+++ b/aos/events/logging/log_backend_test.cc
@@ -27,14 +27,26 @@
TEST(LogBackendTest, CreateSimpleFile) {
const std::string logevent = aos::testing::TestTmpDir() + "/logevent/";
+ const std::string filename = "test.bfbs";
FileBackend backend(logevent);
- auto file = backend.RequestFile("test.log");
+ auto file = backend.RequestFile(filename);
ASSERT_EQ(file->OpenForWrite(), WriteCode::kOk);
auto result = Write(file.get(), "test");
EXPECT_EQ(result.code, WriteCode::kOk);
EXPECT_EQ(result.messages_written, 1);
EXPECT_EQ(file->Close(), WriteCode::kOk);
- EXPECT_TRUE(std::filesystem::exists(logevent + "test.log"));
+ EXPECT_TRUE(std::filesystem::exists(logevent + filename));
+
+ EXPECT_THAT(backend.ListFiles(), ::testing::ElementsAre(filename));
+
+ auto decoder = backend.GetDecoder(filename);
+ std::vector<uint8_t> buffer;
+ buffer.resize(10);
+ const auto count = decoder->Read(buffer.data(), buffer.data() + 10);
+ ASSERT_EQ(count, 4);
+ buffer.resize(4);
+ std::string view(buffer.begin(), buffer.end());
+ EXPECT_EQ(view, "test");
}
TEST(LogBackendTest, CreateRenamableFile) {