Add logger and log_dumper binaries
This enables actually logging data on the roborio and subsequently
actually doing basic viewing of the data in the logfiles.
Tested manually on my local machine.
This also makes an //aos/events/logging folder (this is distinct from
the //aos/logging folder which contains older logging information).
Change-Id: I41f3216d6c56e8330667e8dd6050b1a0dd5b19c9
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
new file mode 100644
index 0000000..1137e66
--- /dev/null
+++ b/aos/events/logging/logger_test.cc
@@ -0,0 +1,111 @@
+#include "aos/events/logging/logger.h"
+
+#include "aos/events/event_loop.h"
+#include "aos/events/ping_lib.h"
+#include "aos/events/pong_lib.h"
+#include "aos/events/simulated_event_loop.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+namespace aos {
+namespace logger {
+namespace testing {
+
+namespace chrono = std::chrono;
+
+class LoggerTest : public ::testing::Test {
+ public:
+ LoggerTest()
+ : config_(
+ aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
+ event_loop_factory_(&config_.message()),
+ ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
+ ping_(ping_event_loop_.get()),
+ pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
+ pong_(pong_event_loop_.get()) {}
+
+ // Config and factory.
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
+ SimulatedEventLoopFactory event_loop_factory_;
+
+ // Event loop and app for Ping
+ std::unique_ptr<EventLoop> ping_event_loop_;
+ Ping ping_;
+
+ // Event loop and app for Pong
+ std::unique_ptr<EventLoop> pong_event_loop_;
+ Pong pong_;
+};
+
+// Tests that we can startup at all. This confirms that the channels are all in
+// the config.
+TEST_F(LoggerTest, Starts) {
+ const ::std::string tmpdir(getenv("TEST_TMPDIR"));
+ const ::std::string logfile = tmpdir + "/logfile.bfbs";
+ // Remove it.
+ unlink(logfile.c_str());
+
+ LOG(INFO) << "Logging data to " << logfile;
+
+ {
+ DetachedBufferWriter writer(logfile);
+ std::unique_ptr<EventLoop> logger_event_loop =
+ event_loop_factory_.MakeEventLoop("logger");
+
+ event_loop_factory_.RunFor(chrono::milliseconds(95));
+
+ Logger logger(&writer, logger_event_loop.get(),
+ std::chrono::milliseconds(100));
+ event_loop_factory_.RunFor(chrono::milliseconds(20000));
+ }
+
+ LogReader reader(logfile);
+
+ LOG(INFO) << "Config " << FlatbufferToJson(reader.configuration());
+
+ // TODO(austin): Figure out what the API needs to look like. How do we replay
+ // the data that was fetched before it all starts? How do we set the starting
+ // time from the log file? Probably need to let the reader do more if it
+ // knows about the factory.
+ SimulatedEventLoopFactory log_reader_factory(reader.configuration());
+ std::unique_ptr<EventLoop> reader_event_loop =
+ log_reader_factory.MakeEventLoop("log_reader");
+
+ reader.Register(reader_event_loop.get());
+
+ // Capture monotonic start time in OnRun and offset from there? Let the user
+ // configure the factory if they want time to match?
+ /*
+ log_reader_factory.InitializeTime(log_reader.monotonic_start_time(),
+ log_reader.realtime_start_time());
+ */
+ std::unique_ptr<EventLoop> test_event_loop =
+ log_reader_factory.MakeEventLoop("log_reader");
+
+ int ping_count = 10;
+ int pong_count = 10;
+
+ // Confirm that the ping value matches.
+ test_event_loop->MakeWatcher("/test",
+ [&ping_count](const examples::Ping &ping) {
+ EXPECT_EQ(ping.value(), ping_count + 1);
+ ++ping_count;
+ });
+ // Confirm that the ping and pong counts both match, and the value also
+ // matches.
+ test_event_loop->MakeWatcher(
+ "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
+ EXPECT_EQ(pong.value(), pong_count + 1);
+ ++pong_count;
+ EXPECT_EQ(ping_count, pong_count);
+ });
+
+ log_reader_factory.RunFor(std::chrono::seconds(100));
+ EXPECT_EQ(ping_count, 2010);
+
+ reader.Deregister();
+}
+
+} // namespace testing
+} // namespace logger
+} // namespace aos