Support stopping and starting logging at runtime
Change-Id: If1e1b7119808d1f56e96efb71ea7000e0fa13fe8
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index 707a232..2095529 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -41,6 +41,8 @@
Pong pong_;
};
+using LoggerDeathTest = LoggerTest;
+
// Tests that we can startup at all. This confirms that the channels are all in
// the config.
TEST_F(LoggerTest, Starts) {
@@ -58,8 +60,9 @@
event_loop_factory_.RunFor(chrono::milliseconds(95));
- Logger logger(base_name, logger_event_loop.get(),
- std::chrono::milliseconds(100));
+ Logger logger(logger_event_loop.get());
+ logger.set_polling_period(std::chrono::milliseconds(100));
+ logger.StartLoggingLocalNamerOnRun(base_name);
event_loop_factory_.RunFor(chrono::milliseconds(20000));
}
@@ -101,6 +104,130 @@
EXPECT_EQ(ping_count, 2010);
}
+// Tests calling StartLogging twice.
+TEST_F(LoggerDeathTest, ExtraStart) {
+ const ::std::string tmpdir(getenv("TEST_TMPDIR"));
+ const ::std::string base_name1 = tmpdir + "/logfile1";
+ const ::std::string logfile1 = base_name1 + ".part0.bfbs";
+ const ::std::string base_name2 = tmpdir + "/logfile2";
+ const ::std::string logfile2 = base_name2 + ".part0.bfbs";
+ unlink(logfile1.c_str());
+ unlink(logfile2.c_str());
+
+ LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
+
+ {
+ std::unique_ptr<EventLoop> logger_event_loop =
+ event_loop_factory_.MakeEventLoop("logger");
+
+ event_loop_factory_.RunFor(chrono::milliseconds(95));
+
+ Logger logger(logger_event_loop.get());
+ logger.set_polling_period(std::chrono::milliseconds(100));
+ logger_event_loop->OnRun(
+ [base_name1, base_name2, &logger_event_loop, &logger]() {
+ logger.StartLogging(std::make_unique<LocalLogNamer>(
+ base_name1, logger_event_loop->node()));
+ EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
+ base_name2, logger_event_loop->node())),
+ "Already logging");
+ });
+ event_loop_factory_.RunFor(chrono::milliseconds(20000));
+ }
+}
+
+// Tests calling StopLogging twice.
+TEST_F(LoggerDeathTest, ExtraStop) {
+ const ::std::string tmpdir(getenv("TEST_TMPDIR"));
+ const ::std::string base_name = tmpdir + "/logfile";
+ const ::std::string logfile = base_name + ".part0.bfbs";
+ // Remove it.
+ unlink(logfile.c_str());
+
+ LOG(INFO) << "Logging data to " << logfile;
+
+ {
+ std::unique_ptr<EventLoop> logger_event_loop =
+ event_loop_factory_.MakeEventLoop("logger");
+
+ event_loop_factory_.RunFor(chrono::milliseconds(95));
+
+ Logger logger(logger_event_loop.get());
+ logger.set_polling_period(std::chrono::milliseconds(100));
+ logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
+ logger.StartLogging(std::make_unique<LocalLogNamer>(
+ base_name, logger_event_loop->node()));
+ logger.StopLogging(aos::monotonic_clock::min_time);
+ EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
+ "Not logging right now");
+ });
+ event_loop_factory_.RunFor(chrono::milliseconds(20000));
+ }
+}
+
+// Tests that we can startup twice.
+TEST_F(LoggerTest, StartsTwice) {
+ const ::std::string tmpdir(getenv("TEST_TMPDIR"));
+ const ::std::string base_name1 = tmpdir + "/logfile1";
+ const ::std::string logfile1 = base_name1 + ".part0.bfbs";
+ const ::std::string base_name2 = tmpdir + "/logfile2";
+ const ::std::string logfile2 = base_name2 + ".part0.bfbs";
+ unlink(logfile1.c_str());
+ unlink(logfile2.c_str());
+
+ LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
+
+ {
+ std::unique_ptr<EventLoop> logger_event_loop =
+ event_loop_factory_.MakeEventLoop("logger");
+
+ event_loop_factory_.RunFor(chrono::milliseconds(95));
+
+ Logger logger(logger_event_loop.get());
+ logger.set_polling_period(std::chrono::milliseconds(100));
+ logger.StartLogging(
+ std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
+ event_loop_factory_.RunFor(chrono::milliseconds(10000));
+ logger.StopLogging(logger_event_loop->monotonic_now());
+ event_loop_factory_.RunFor(chrono::milliseconds(10000));
+ logger.StartLogging(
+ std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
+ event_loop_factory_.RunFor(chrono::milliseconds(10000));
+ }
+
+ for (const auto &logfile :
+ {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
+ SCOPED_TRACE(std::get<0>(logfile));
+ LogReader reader(std::get<0>(logfile));
+ reader.Register();
+
+ EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
+
+ std::unique_ptr<EventLoop> test_event_loop =
+ reader.event_loop_factory()->MakeEventLoop("log_reader");
+
+ int ping_count = std::get<1>(logfile);
+ int pong_count = std::get<1>(logfile);
+
+ // Confirm that the ping and pong counts both match, and the value also
+ // matches.
+ test_event_loop->MakeWatcher("/test",
+ [&ping_count](const examples::Ping &ping) {
+ EXPECT_EQ(ping.value(), ping_count + 1);
+ ++ping_count;
+ });
+ 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);
+ });
+
+ reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
+ EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
+ }
+}
+
// Tests that we can read and write rotated log files.
TEST_F(LoggerTest, RotatedLogFile) {
const ::std::string tmpdir(getenv("TEST_TMPDIR"));
@@ -119,9 +246,9 @@
event_loop_factory_.RunFor(chrono::milliseconds(95));
- Logger logger(
- std::make_unique<LocalLogNamer>(base_name, logger_event_loop->node()),
- logger_event_loop.get(), std::chrono::milliseconds(100));
+ Logger logger(logger_event_loop.get());
+ logger.set_polling_period(std::chrono::milliseconds(100));
+ logger.StartLoggingLocalNamerOnRun(base_name);
event_loop_factory_.RunFor(chrono::milliseconds(10000));
logger.Rotate();
event_loop_factory_.RunFor(chrono::milliseconds(10000));
@@ -218,8 +345,9 @@
chrono::microseconds(50));
});
- Logger logger(base_name, logger_event_loop.get(),
- std::chrono::milliseconds(100));
+ Logger logger(logger_event_loop.get());
+ logger.set_polling_period(std::chrono::milliseconds(100));
+ logger.StartLoggingLocalNamerOnRun(base_name);
event_loop_factory_.RunFor(chrono::milliseconds(1000));
}
@@ -289,11 +417,13 @@
}
void StartLogger(LoggerState *logger) {
- logger->logger = std::make_unique<Logger>(
- std::make_unique<MultiNodeLogNamer>(logfile_base_,
- logger->event_loop->configuration(),
- logger->event_loop->node()),
- logger->event_loop.get(), chrono::milliseconds(100));
+ logger->logger = std::make_unique<Logger>(logger->event_loop.get());
+ logger->logger->set_polling_period(std::chrono::milliseconds(100));
+ logger->event_loop->OnRun([this, logger]() {
+ logger->logger->StartLogging(std::make_unique<MultiNodeLogNamer>(
+ logfile_base_, logger->event_loop->configuration(),
+ logger->event_loop->node()));
+ });
}
// Config and factory.