Automatic reverse-lookup of channel names in Foxglove

This makes it so that if you want to visualize a logfile, then
you will be able to, e.g., refer to "/aos aos.timing.Report"
regardless of what node you are on, without having to alter your
layouts to refer to "/pi1/pose aos.timing.Report". This may end up
causing extra confusion because it masks what the "true" channel name
is, but I expect that defaulting to shorter names will make it easier to
use.

Fix existing layouts that had prefixes hardcoded.

Change-Id: Ic708f48868bbb4b1e60bfef9ebec36100a1763fd
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/util/log_to_mcap.cc b/aos/util/log_to_mcap.cc
index 2e66e67..9a0af48 100644
--- a/aos/util/log_to_mcap.cc
+++ b/aos/util/log_to_mcap.cc
@@ -6,6 +6,10 @@
 DEFINE_string(node, "", "Node to replay from the perspective of.");
 DEFINE_string(output_path, "/tmp/log.mcap", "Log to output.");
 DEFINE_string(mode, "flatbuffer", "json or flatbuffer serialization.");
+DEFINE_bool(
+    canonical_channel_names, false,
+    "If set, use full channel names; by default, will shorten names to be the "
+    "shortest possible version of the name (e.g., /aos instead of /pi/aos).");
 
 // Converts an AOS log to an MCAP log that can be fed into Foxglove. To try this
 // out, run:
@@ -48,9 +52,12 @@
   std::unique_ptr<aos::EventLoop> mcap_event_loop =
       reader.event_loop_factory()->MakeEventLoop("mcap", node);
   CHECK(!FLAGS_output_path.empty());
-  aos::McapLogger relogger(mcap_event_loop.get(), FLAGS_output_path,
-                           FLAGS_mode == "flatbuffer"
-                               ? aos::McapLogger::Serialization::kFlatbuffer
-                               : aos::McapLogger::Serialization::kJson);
+  aos::McapLogger relogger(
+      mcap_event_loop.get(), FLAGS_output_path,
+      FLAGS_mode == "flatbuffer" ? aos::McapLogger::Serialization::kFlatbuffer
+                                 : aos::McapLogger::Serialization::kJson,
+      FLAGS_canonical_channel_names
+          ? aos::McapLogger::CanonicalChannelNames::kCanonical
+          : aos::McapLogger::CanonicalChannelNames::kShortened);
   reader.event_loop_factory()->Run();
 }
diff --git a/aos/util/mcap_logger.cc b/aos/util/mcap_logger.cc
index dc27504..4d4c1bd 100644
--- a/aos/util/mcap_logger.cc
+++ b/aos/util/mcap_logger.cc
@@ -83,10 +83,11 @@
 }
 
 McapLogger::McapLogger(EventLoop *event_loop, const std::string &output_path,
-                       Serialization serialization)
+                       Serialization serialization, CanonicalChannelNames canonical_channels)
     : event_loop_(event_loop),
       output_(output_path),
       serialization_(serialization),
+      canonical_channels_(canonical_channels),
       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
@@ -321,11 +322,34 @@
   // Schema ID
   AppendInt16(&string_builder_, schema_id);
   // Topic name
-  AppendString(&string_builder_,
-               override_name.empty()
-                   ? absl::StrCat(channel->name()->string_view(), " ",
-                                  channel->type()->string_view())
-                   : override_name);
+  std::string topic_name(override_name);
+  if (topic_name.empty()) {
+    switch (canonical_channels_) {
+      case CanonicalChannelNames::kCanonical:
+        topic_name = absl::StrCat(channel->name()->string_view(), " ",
+                                  channel->type()->string_view());
+        break;
+      case CanonicalChannelNames::kShortened: {
+        std::set<std::string> names = configuration::GetChannelAliases(
+            event_loop_->configuration(), channel, event_loop_->name(),
+            event_loop_->node());
+        std::string_view shortest_name;
+        for (const std::string &name : names) {
+          if (shortest_name.empty() || name.size() < shortest_name.size()) {
+            shortest_name = name;
+          }
+        }
+        if (shortest_name != channel->name()->string_view()) {
+          VLOG(1) << "Shortening " << channel->name()->string_view() << " "
+                  << channel->type()->string_view() << " to " << shortest_name;
+        }
+        topic_name = absl::StrCat(shortest_name, " ",
+                                  channel->type()->string_view());
+        break;
+      }
+    }
+  }
+  AppendString(&string_builder_, topic_name);
   // Encoding
   switch (serialization_) {
     case Serialization::kJson:
diff --git a/aos/util/mcap_logger.h b/aos/util/mcap_logger.h
index d7409fb..d264c1e 100644
--- a/aos/util/mcap_logger.h
+++ b/aos/util/mcap_logger.h
@@ -36,8 +36,18 @@
     kJson,
     kFlatbuffer,
   };
+  // Whether to attempt to shorten channel names.
+  enum class CanonicalChannelNames {
+    // Just use the full, unambiguous, channel names.
+    kCanonical,
+    // Use GetChannelAliases() to determine the shortest possible name for the
+    // channel for the current node, and use that in the MCAP file. This makes
+    // it so that the channels in the resulting file are more likely to match
+    // the channel names that are used in "real" applications.
+    kShortened,
+  };
   McapLogger(EventLoop *event_loop, const std::string &output_path,
-             Serialization serialization);
+             Serialization serialization, CanonicalChannelNames canonical_channels);
   ~McapLogger();
 
  private:
@@ -131,6 +141,7 @@
   aos::EventLoop *event_loop_;
   std::ofstream output_;
   const Serialization serialization_;
+  const CanonicalChannelNames canonical_channels_;
   size_t total_message_bytes_ = 0;
   std::map<const Channel *, size_t> total_channel_bytes_;
   // Buffer containing serialized message data for the currently-being-built