Allow using shortened channel names in foxglove_websocket
This makes the websocket server's defaults consistent with log_to_mcap.
By using shortened channel names, we make ti easier to reuse layouts
across nodes (e.g., this way, the /piX prefix will be removed for
the channels available on the current pi being debugged).
Change-Id: Ief1f0c5a8932425017b4718ec9f9d2bae1de2c72
Signed-off-by: James Kuszmaul <jabukuszmaul@gmail.com>
diff --git a/aos/util/foxglove_websocket.cc b/aos/util/foxglove_websocket.cc
index 715ba13..77dca20 100644
--- a/aos/util/foxglove_websocket.cc
+++ b/aos/util/foxglove_websocket.cc
@@ -11,6 +11,10 @@
"with a read_method of PIN (see aos/configuration.fbs; PIN is an "
"enum value). Having this enabled will cause foxglove to consume "
"extra shared memory resources.");
+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).");
int main(int argc, char *argv[]) {
gflags::SetUsageMessage(
@@ -53,7 +57,10 @@
: aos::FoxgloveWebsocketServer::Serialization::kJson,
FLAGS_fetch_pinned_channels
? aos::FoxgloveWebsocketServer::FetchPinnedChannels::kYes
- : aos::FoxgloveWebsocketServer::FetchPinnedChannels::kNo);
+ : aos::FoxgloveWebsocketServer::FetchPinnedChannels::kNo,
+ FLAGS_canonical_channel_names
+ ? aos::FoxgloveWebsocketServer::CanonicalChannelNames::kCanonical
+ : aos::FoxgloveWebsocketServer::CanonicalChannelNames::kShortened);
event_loop.Run();
}
diff --git a/aos/util/foxglove_websocket_lib.cc b/aos/util/foxglove_websocket_lib.cc
index 1cc3a8a..06c551e 100644
--- a/aos/util/foxglove_websocket_lib.cc
+++ b/aos/util/foxglove_websocket_lib.cc
@@ -1,8 +1,8 @@
#include "aos/util/foxglove_websocket_lib.h"
-#include "aos/util/mcap_logger.h"
-#include "aos/flatbuffer_merge.h"
#include "absl/strings/escaping.h"
+#include "aos/flatbuffer_merge.h"
+#include "aos/util/mcap_logger.h"
#include "gflags/gflags.h"
DEFINE_uint32(sorting_buffer_ms, 100,
@@ -17,10 +17,12 @@
namespace aos {
FoxgloveWebsocketServer::FoxgloveWebsocketServer(
aos::EventLoop *event_loop, uint32_t port, Serialization serialization,
- FetchPinnedChannels fetch_pinned_channels)
+ FetchPinnedChannels fetch_pinned_channels,
+ CanonicalChannelNames canonical_channels)
: event_loop_(event_loop),
serialization_(serialization),
fetch_pinned_channels_(fetch_pinned_channels),
+ canonical_channels_(canonical_channels),
server_(port, "aos_foxglove") {
for (const aos::Channel *channel :
*event_loop_->configuration()->channels()) {
@@ -30,18 +32,28 @@
(!is_pinned || fetch_pinned_channels_ == FetchPinnedChannels::kYes)) {
const FlatbufferDetachedBuffer<reflection::Schema> schema =
RecursiveCopyFlatBuffer(channel->schema());
+ const std::string shortest_name =
+ ShortenedChannelName(event_loop_->configuration(), channel,
+ event_loop_->name(), event_loop_->node());
+ std::string name_to_send;
+ switch (canonical_channels_) {
+ case CanonicalChannelNames::kCanonical:
+ name_to_send = channel->name()->string_view();
+ break;
+ case CanonicalChannelNames::kShortened:
+ name_to_send = shortest_name;
+ break;
+ }
const ChannelId id =
(serialization_ == Serialization::kJson)
? server_.addChannel(foxglove::websocket::ChannelWithoutId{
- .topic =
- channel->name()->str() + " " + channel->type()->str(),
+ .topic = name_to_send + " " + channel->type()->str(),
.encoding = "json",
.schemaName = channel->type()->str(),
.schema =
JsonSchemaForFlatbuffer({channel->schema()}).dump()})
: server_.addChannel(foxglove::websocket::ChannelWithoutId{
- .topic =
- channel->name()->str() + " " + channel->type()->str(),
+ .topic = name_to_send + " " + channel->type()->str(),
.encoding = "flatbuffer",
.schemaName = channel->type()->str(),
.schema = absl::Base64Escape(
diff --git a/aos/util/foxglove_websocket_lib.h b/aos/util/foxglove_websocket_lib.h
index 9be2f61..7c326c2 100644
--- a/aos/util/foxglove_websocket_lib.h
+++ b/aos/util/foxglove_websocket_lib.h
@@ -24,9 +24,20 @@
kYes,
kNo,
};
+ // 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,
+ };
FoxgloveWebsocketServer(aos::EventLoop *event_loop, uint32_t port,
Serialization serialization,
- FetchPinnedChannels fetch_pinned_channels);
+ FetchPinnedChannels fetch_pinned_channels,
+ CanonicalChannelNames canonical_channels);
~FoxgloveWebsocketServer();
private:
@@ -47,6 +58,7 @@
aos::EventLoop *event_loop_;
const Serialization serialization_;
const FetchPinnedChannels fetch_pinned_channels_;
+ const CanonicalChannelNames canonical_channels_;
foxglove::websocket::Server server_;
// A map of fetchers for every single channel that could be subscribed to.
std::map<ChannelId, FetcherState> fetchers_;
diff --git a/aos/util/mcap_logger.cc b/aos/util/mcap_logger.cc
index 40e55f0..111d784 100644
--- a/aos/util/mcap_logger.cc
+++ b/aos/util/mcap_logger.cc
@@ -84,6 +84,21 @@
return schema;
}
+std::string ShortenedChannelName(const aos::Configuration *config,
+ const aos::Channel *channel,
+ std::string_view application_name,
+ const aos::Node *node) {
+ std::set<std::string> names =
+ configuration::GetChannelAliases(config, channel, application_name, node);
+ std::string_view shortest_name;
+ for (const std::string &name : names) {
+ if (shortest_name.empty() || name.size() < shortest_name.size()) {
+ shortest_name = name;
+ }
+ }
+ return std::string(shortest_name);
+}
+
namespace {
std::string_view CompressionName(McapLogger::Compression compression) {
switch (compression) {
@@ -354,15 +369,9 @@
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;
- }
- }
+ const std::string shortest_name =
+ ShortenedChannelName(event_loop_->configuration(), channel,
+ event_loop_->name(), event_loop_->node());
if (shortest_name != channel->name()->string_view()) {
VLOG(1) << "Shortening " << channel->name()->string_view() << " "
<< channel->type()->string_view() << " to " << shortest_name;
diff --git a/aos/util/mcap_logger.h b/aos/util/mcap_logger.h
index c3fdda1..50e9300 100644
--- a/aos/util/mcap_logger.h
+++ b/aos/util/mcap_logger.h
@@ -24,6 +24,13 @@
const FlatbufferType &type,
JsonSchemaRecursion recursion_level = JsonSchemaRecursion::kTopLevel);
+// Returns the shortest possible alias for the specified channel on the
+// specified node/application.
+std::string ShortenedChannelName(const aos::Configuration *config,
+ const aos::Channel *channel,
+ std::string_view application_name,
+ const aos::Node *node);
+
// Generates an MCAP file, per the specification at
// https://github.com/foxglove/mcap/tree/main/docs/specification
// This currently generates an uncompressed logfile with full message indexing
diff --git a/aos/util/mcap_logger_test.cc b/aos/util/mcap_logger_test.cc
index 8bc3419..c6febf9 100644
--- a/aos/util/mcap_logger_test.cc
+++ b/aos/util/mcap_logger_test.cc
@@ -10,7 +10,8 @@
// will require writing an MCAP reader (or importing an existing one).
// Confirm that the schema for the reflection.Schema table itself hasn't
-// changed. reflection.Schema should be a very stable type, so this should need
+// changed. reflection.Schema should be a very stable type, so this should
+// need
// updating except when we change the JSON schema generation itself.
TEST(JsonSchemaTest, ReflectionSchema) {
std::string schema_json =