Support Logger using a second config for logging
There are use cases when rewriting a log file where you want to
add channels to the event_loop_->configuration(), ie remap things to
/original, and then log with the config without /original. To support
this, logger needs to be able to accept a configuration to log, and to
use to list all the channels.
Change-Id: I0a74610f4a30ccc7f83dd806f5be8543a9ad2114
diff --git a/aos/events/logging/logger.cc b/aos/events/logging/logger.cc
index 85809b1..2109206 100644
--- a/aos/events/logging/logger.cc
+++ b/aos/events/logging/logger.cc
@@ -88,14 +88,26 @@
Logger::Logger(std::string_view base_name, EventLoop *event_loop,
std::chrono::milliseconds polling_period)
+ : Logger(base_name, event_loop, event_loop->configuration(),
+ polling_period) {}
+Logger::Logger(std::string_view base_name, EventLoop *event_loop,
+ const Configuration *configuration,
+ std::chrono::milliseconds polling_period)
: Logger(std::make_unique<LocalLogNamer>(base_name, event_loop->node()),
- event_loop, polling_period) {}
+ event_loop, configuration, polling_period) {}
+Logger::Logger(std::unique_ptr<LogNamer> log_namer, EventLoop *event_loop,
+ std::chrono::milliseconds polling_period)
+ : Logger(std::move(log_namer), event_loop, event_loop->configuration(),
+ polling_period) {}
Logger::Logger(std::unique_ptr<LogNamer> log_namer, EventLoop *event_loop,
+ const Configuration *configuration,
std::chrono::milliseconds polling_period)
: event_loop_(event_loop),
uuid_(UUID::Random()),
log_namer_(std::move(log_namer)),
+ configuration_(configuration),
+ name_(network::GetHostname()),
timer_handler_(event_loop_->AddTimer([this]() { DoLogData(); })),
polling_period_(polling_period),
server_statistics_fetcher_(
@@ -108,14 +120,14 @@
// Find all the nodes which are logging timestamps on our node.
std::set<const Node *> timestamp_logger_nodes;
- for (const Channel *channel : *event_loop_->configuration()->channels()) {
+ for (const Channel *channel : *configuration_->channels()) {
if (!configuration::ChannelIsSendableOnNode(channel, event_loop_->node()) ||
!channel->has_destination_nodes()) {
continue;
}
for (const Connection *connection : *channel->destination_nodes()) {
const Node *other_node = configuration::GetNode(
- event_loop_->configuration(), connection->name()->string_view());
+ configuration_, connection->name()->string_view());
if (configuration::ConnectionDeliveryTimeIsLoggedOnNode(
connection, event_loop_->node())) {
@@ -132,7 +144,7 @@
// for them.
for (const Node *node : timestamp_logger_nodes) {
const Channel *channel = configuration::GetChannel(
- event_loop_->configuration(),
+ configuration_,
absl::StrCat("/aos/remote_timestamps/", node->name()->string_view()),
logger::MessageHeader::GetFullyQualifiedName(), event_loop_->name(),
event_loop_->node());
@@ -146,9 +158,16 @@
}
const size_t our_node_index = configuration::GetNodeIndex(
- event_loop_->configuration(), event_loop_->node());
+ configuration_, event_loop_->node());
- for (const Channel *channel : *event_loop_->configuration()->channels()) {
+ for (const Channel *config_channel : *configuration_->channels()) {
+ // The MakeRawFetcher method needs a channel which is in the event loop
+ // configuration() object, not the configuration_ object. Go look that up
+ // from the config.
+ const Channel *channel = aos::configuration::GetChannel(
+ event_loop_->configuration(), config_channel->name()->string_view(),
+ config_channel->type()->string_view(), "", event_loop_->node());
+
FetcherStruct fs;
fs.node_index = our_node_index;
const bool is_local =
@@ -195,8 +214,8 @@
<< configuration::CleanedChannelToString(channel);
fs.contents_writer =
log_namer_->MakeForwardedTimestampWriter(channel, timestamp_node);
- fs.node_index = configuration::GetNodeIndex(
- event_loop_->configuration(), timestamp_node);
+ fs.node_index =
+ configuration::GetNodeIndex(configuration_, timestamp_node);
}
fs.channel_index = channel_index;
fs.written = false;
@@ -205,13 +224,13 @@
++channel_index;
}
- node_state_.resize(configuration::MultiNode(event_loop_->configuration())
- ? event_loop_->configuration()->nodes()->size()
+ node_state_.resize(configuration::MultiNode(configuration_)
+ ? configuration_->nodes()->size()
: 1u);
for (const Node *node : log_namer_->nodes()) {
const int node_index =
- configuration::GetNodeIndex(event_loop_->configuration(), node);
+ configuration::GetNodeIndex(configuration_, node);
node_state_[node_index].log_file_header = MakeHeader(node);
}
@@ -222,6 +241,14 @@
event_loop_->OnRun([this]() { StartLogging(); });
}
+Logger::~Logger() {
+ // If we are replaying a log file, or in simulation, we want to force the last
+ // bit of data to be logged. The easiest way to deal with this is to poll
+ // everything as we go to destroy the class, ie, shut down the logger, and
+ // write it to disk.
+ DoLogData();
+}
+
void Logger::StartLogging() {
// Grab data from each channel right before we declare the log file started
// so we can capture the latest message on each channel. This lets us have
@@ -245,7 +272,7 @@
}
void Logger::WriteHeader() {
- if (configuration::MultiNode(event_loop_->configuration())) {
+ if (configuration::MultiNode(configuration_)) {
server_statistics_fetcher_.Fetch();
}
@@ -262,7 +289,7 @@
for (const Node *node : log_namer_->nodes()) {
const int node_index =
- configuration::GetNodeIndex(event_loop_->configuration(), node);
+ configuration::GetNodeIndex(configuration_, node);
MaybeUpdateTimestamp(node, node_index, monotonic_start_time,
realtime_start_time);
log_namer_->WriteHeader(&node_state_[node_index].log_file_header, node);
@@ -270,7 +297,7 @@
}
void Logger::WriteMissingTimestamps() {
- if (configuration::MultiNode(event_loop_->configuration())) {
+ if (configuration::MultiNode(configuration_)) {
server_statistics_fetcher_.Fetch();
} else {
return;
@@ -282,7 +309,7 @@
for (const Node *node : log_namer_->nodes()) {
const int node_index =
- configuration::GetNodeIndex(event_loop_->configuration(), node);
+ configuration::GetNodeIndex(configuration_, node);
if (MaybeUpdateTimestamp(
node, node_index,
server_statistics_fetcher_.context().monotonic_event_time,
@@ -324,7 +351,7 @@
monotonic_clock::min_time) {
return false;
}
- if (configuration::MultiNode(event_loop_->configuration())) {
+ if (configuration::MultiNode(configuration_)) {
if (event_loop_->node() == node) {
// There are no offsets to compute for ourself, so always succeed.
SetStartTime(node_index, monotonic_start_time, realtime_start_time);
@@ -378,10 +405,10 @@
// TODO(austin): Compress this much more efficiently. There are a bunch of
// duplicated schemas.
flatbuffers::Offset<aos::Configuration> configuration_offset =
- CopyFlatBuffer(event_loop_->configuration(), &fbb);
+ CopyFlatBuffer(configuration_, &fbb);
flatbuffers::Offset<flatbuffers::String> name_offset =
- fbb.CreateString(network::GetHostname());
+ fbb.CreateString(name_);
flatbuffers::Offset<flatbuffers::String> logger_uuid_offset =
fbb.CreateString(uuid_.string_view());
@@ -391,7 +418,7 @@
flatbuffers::Offset<Node> node_offset;
- if (configuration::MultiNode(event_loop_->configuration())) {
+ if (configuration::MultiNode(configuration_)) {
node_offset = CopyFlatBuffer(node, &fbb);
}
@@ -437,7 +464,7 @@
void Logger::Rotate() {
for (const Node *node : log_namer_->nodes()) {
const int node_index =
- configuration::GetNodeIndex(event_loop_->configuration(), node);
+ configuration::GetNodeIndex(configuration_, node);
log_namer_->Rotate(node, &node_state_[node_index].log_file_header);
}
}
diff --git a/aos/events/logging/logger.h b/aos/events/logging/logger.h
index d4ed786..3756f83 100644
--- a/aos/events/logging/logger.h
+++ b/aos/events/logging/logger.h
@@ -285,12 +285,33 @@
// configuration that is sent rately on a channel and would affect execution.
class Logger {
public:
+ // Constructs a logger.
+ // base_name/log_namer: Object used to write data to disk in one or more log
+ // files. If a base_name is passed in, a LocalLogNamer is wrapped
+ // around it.
+ // event_loop: The event loop used to read the messages.
+ // polling_period: The period used to poll the data.
+ // configuration: When provided, this is the configuration to log, and the
+ // configuration to use for the channel list to log. If not provided,
+ // this becomes the configuration from the event loop.
Logger(std::string_view base_name, EventLoop *event_loop,
std::chrono::milliseconds polling_period =
std::chrono::milliseconds(100));
+ Logger(std::string_view base_name, EventLoop *event_loop,
+ const Configuration *configuration,
+ std::chrono::milliseconds polling_period =
+ std::chrono::milliseconds(100));
Logger(std::unique_ptr<LogNamer> log_namer, EventLoop *event_loop,
std::chrono::milliseconds polling_period =
std::chrono::milliseconds(100));
+ Logger(std::unique_ptr<LogNamer> log_namer, EventLoop *event_loop,
+ const Configuration *configuration,
+ std::chrono::milliseconds polling_period =
+ std::chrono::milliseconds(100));
+ ~Logger();
+
+ // Overrides the name in the log file header.
+ void set_name(std::string_view name) { name_ = name; }
// Rotates the log file(s), triggering new part files to be written for each
// log file.
@@ -319,6 +340,12 @@
const UUID uuid_;
std::unique_ptr<LogNamer> log_namer_;
+ // The configuration to place at the top of the log file.
+ const Configuration *configuration_;
+
+ // Name to save in the log file. Defaults to hostname.
+ std::string name_;
+
// Structure to track both a fetcher, and if the data fetched has been
// written. We may want to delay writing data to disk so that we don't let
// data get too far out of order when written to disk so we can avoid making
@@ -450,7 +477,11 @@
// gets called.
void Deregister();
- // Returns the configuration from the log file.
+ // Returns the configuration being used for replay from the log file.
+ // Note that this may be different from the configuration actually used for
+ // handling events. You should generally only use this to create a
+ // SimulatedEventLoopFactory, and then get the configuration from there for
+ // everything else.
const Configuration *logged_configuration() const;
// Returns the configuration being used for replay.
// The pointer is invalidated whenever RemapLoggedChannel is called.
@@ -492,6 +523,10 @@
return &log_file_header_.message();
}
+ std::string_view name() const {
+ return log_file_header()->name()->string_view();
+ }
+
private:
const Channel *RemapChannel(const EventLoop *event_loop,
const Channel *channel);