Add a "configuration" channel to MCAP files for foxglove
This is helpful for doing certain types of analysis where you might want
to, e.g., correlate channel indices to a channel name/type (e.g., for
analyzing sent-too-fast errors or for using the ReplayTiming
message implemented by I471fefd96a4d043766b54dd4488726e24926a95f).
Change-Id: Ic68026be58205607a2099ccfd7547187989ec26c
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/util/mcap_logger.cc b/aos/util/mcap_logger.cc
index 561a02b..dc27504 100644
--- a/aos/util/mcap_logger.cc
+++ b/aos/util/mcap_logger.cc
@@ -1,6 +1,7 @@
#include "aos/util/mcap_logger.h"
#include "absl/strings/str_replace.h"
+#include "aos/configuration_schema.h"
#include "aos/flatbuffer_merge.h"
#include "single_include/nlohmann/json.hpp"
@@ -85,7 +86,29 @@
Serialization serialization)
: event_loop_(event_loop),
output_(output_path),
- serialization_(serialization) {
+ serialization_(serialization),
+ configuration_channel_([]() {
+ // Setup a fake Channel for providing the configuration in the MCAP
+ // file. This is included for convenience so that consumers of the MCAP
+ // file can actually dereference things like the channel indices in AOS
+ // timing reports.
+ flatbuffers::FlatBufferBuilder fbb;
+ flatbuffers::Offset<flatbuffers::String> name_offset =
+ fbb.CreateString("");
+ flatbuffers::Offset<flatbuffers::String> type_offset =
+ fbb.CreateString("aos.Configuration");
+ flatbuffers::Offset<reflection::Schema> schema_offset =
+ aos::CopyFlatBuffer(
+ aos::FlatbufferSpan<reflection::Schema>(ConfigurationSchema()),
+ &fbb);
+ Channel::Builder channel(fbb);
+ channel.add_name(name_offset);
+ channel.add_type(type_offset);
+ channel.add_schema(schema_offset);
+ fbb.Finish(channel.Finish());
+ return fbb.Release();
+ }()),
+ configuration_(CopyFlatBuffer(event_loop_->configuration())) {
event_loop->SkipTimingReport();
event_loop->SkipAosLog();
CHECK(output_);
@@ -181,6 +204,20 @@
}
}
+ // Manually add in a special /configuration channel.
+ if (register_handlers == RegisterHandlers::kYes) {
+ configuration_id_ = ++id;
+ event_loop_->OnRun([this]() {
+ Context config_context;
+ config_context.monotonic_event_time = event_loop_->monotonic_now();
+ config_context.queue_index = 0;
+ config_context.size = configuration_.span().size();
+ config_context.data = configuration_.span().data();
+ WriteMessage(configuration_id_, &configuration_channel_.message(),
+ config_context, ¤t_chunk_);
+ });
+ }
+
std::vector<SummaryOffset> offsets;
const uint64_t schema_offset = output_.tellp();
@@ -189,6 +226,8 @@
WriteSchema(pair.first, pair.second);
}
+ WriteSchema(configuration_id_, &configuration_channel_.message());
+
const uint64_t channel_offset = output_.tellp();
offsets.push_back(
@@ -201,6 +240,13 @@
WriteChannel(pair.first, pair.first, pair.second);
}
+ // Provide the configuration message on a special channel that is just named
+ // "configuration", which is guaranteed not to conflict with existing under
+ // our current naming scheme (since our current scheme will, at a minimum, put
+ // a space between the name/type of a channel).
+ WriteChannel(configuration_id_, configuration_id_,
+ &configuration_channel_.message(), "configuration");
+
offsets.push_back({OpCode::kChannel, channel_offset,
static_cast<uint64_t>(output_.tellp()) - channel_offset});
return offsets;
@@ -267,7 +313,8 @@
}
void McapLogger::WriteChannel(const uint16_t id, const uint16_t schema_id,
- const aos::Channel *channel) {
+ const aos::Channel *channel,
+ std::string_view override_name) {
string_builder_.Reset();
// Channel ID
AppendInt16(&string_builder_, id);
@@ -275,8 +322,10 @@
AppendInt16(&string_builder_, schema_id);
// Topic name
AppendString(&string_builder_,
- absl::StrCat(channel->name()->string_view(), " ",
- channel->type()->string_view()));
+ override_name.empty()
+ ? absl::StrCat(channel->name()->string_view(), " ",
+ channel->type()->string_view())
+ : override_name);
// Encoding
switch (serialization_) {
case Serialization::kJson: