Pull PrintMessage out into aos_cli_utils.h
This lets us share aos_dump and log_cat printing code so they both have
the same feature set.
Change-Id: I66802f9e071fd072ee64bf317b0ff704132a250c
Signed-off-by: Austin Schuh <austin.schuh@bluerivertech.com>
diff --git a/aos/BUILD b/aos/BUILD
index 69303a9..d78b303 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -542,6 +542,7 @@
":configuration",
"//aos:init",
"//aos/events:shm_event_loop",
+ "//aos/events:simulated_event_loop",
"@com_github_google_glog//:glog",
],
)
diff --git a/aos/aos_cli_utils.cc b/aos/aos_cli_utils.cc
index dbd1bcd..2016a71 100644
--- a/aos/aos_cli_utils.cc
+++ b/aos/aos_cli_utils.cc
@@ -4,8 +4,14 @@
#include <sys/types.h>
#include <unistd.h>
+#include <chrono>
#include <iostream>
+#include "aos/configuration.h"
+#include "aos/events/shm_event_loop.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/time/time.h"
+
DEFINE_string(config, "aos_config.json", "File path of aos configuration");
DEFINE_bool(
@@ -21,6 +27,8 @@
namespace aos {
namespace {
+namespace chrono = std::chrono;
+
bool EndsWith(std::string_view str, std::string_view ending) {
const std::size_t offset = str.size() - ending.size();
return str.size() >= ending.size() &&
@@ -28,6 +36,27 @@
ending.end());
}
+void StreamSeconds(std::ostream &stream,
+ const aos::monotonic_clock::time_point now) {
+ if (now < monotonic_clock::epoch()) {
+ chrono::seconds seconds =
+ chrono::duration_cast<chrono::seconds>(now.time_since_epoch());
+
+ stream << "-" << -seconds.count() << "." << std::setfill('0')
+ << std::setw(9)
+ << chrono::duration_cast<chrono::nanoseconds>(seconds -
+ now.time_since_epoch())
+ .count();
+ } else {
+ chrono::seconds seconds =
+ chrono::duration_cast<chrono::seconds>(now.time_since_epoch());
+ stream << seconds.count() << "." << std::setfill('0') << std::setw(9)
+ << chrono::duration_cast<chrono::nanoseconds>(
+ now.time_since_epoch() - seconds)
+ .count();
+ }
+}
+
} // namespace
bool CliUtilInfo::Initialize(
@@ -179,4 +208,87 @@
std::cout << ')';
}
+void PrintMessage(const std::string_view node_name, const aos::Channel *channel,
+ const aos::Context &context, aos::FastStringBuilder *builder,
+ PrintOptions options) {
+ // Print the flatbuffer out to stdout, both to remove the
+ // unnecessary cruft from glog and to allow the user to readily
+ // redirect just the logged output independent of any debugging
+ // information on stderr.
+
+ builder->Reset();
+
+ CHECK(flatbuffers::Verify(*channel->schema(),
+ *channel->schema()->root_table(),
+ static_cast<const uint8_t *>(context.data),
+ static_cast<size_t>(context.size)))
+ << ": Corrupted flatbuffer on " << channel->name()->c_str() << " "
+ << channel->type()->c_str();
+
+ aos::FlatbufferToJson(
+ builder, channel->schema(), static_cast<const uint8_t *>(context.data),
+ {options.pretty, static_cast<size_t>(options.max_vector_size),
+ options.pretty_max, options.use_hex});
+
+ if (options.json) {
+ std::cout << "{";
+ if (!node_name.empty()) {
+ std::cout << "\"node\": \"" << node_name << "\", ";
+ }
+ std::cout << "\"monotonic_event_time\": ";
+ StreamSeconds(std::cout, context.monotonic_event_time);
+ std::cout << ", \"realtime_event_time\": \"" << context.realtime_event_time
+ << "\", ";
+
+ if (context.monotonic_remote_time != context.monotonic_event_time) {
+ std::cout << "\"monotonic_remote_time\": ";
+ StreamSeconds(std::cout, context.monotonic_remote_time);
+ std::cout << ", \"realtime_remote_time\": \""
+ << context.realtime_remote_time << "\", ";
+ }
+
+ std::cout << "\"channel\": "
+ << aos::configuration::StrippedChannelToString(channel)
+ << ", \"data\": " << *builder << "}\n";
+ } else {
+ if (!node_name.empty()) {
+ std::cout << node_name << " ";
+ }
+
+ if (options.print_timestamps) {
+ if (context.monotonic_remote_time != context.monotonic_event_time) {
+ std::cout << context.realtime_event_time << " ("
+ << context.monotonic_event_time << ") sent "
+ << context.realtime_remote_time << " ("
+ << context.monotonic_remote_time << ") "
+ << channel->name()->c_str() << ' ' << channel->type()->c_str()
+ << ": " << *builder << "\n";
+ } else {
+ std::cout << context.realtime_event_time << " ("
+ << context.monotonic_event_time << ") "
+ << channel->name()->c_str() << ' ' << channel->type()->c_str()
+ << ": " << *builder << "\n";
+ }
+ } else {
+ std::cout << *builder << '\n';
+ }
+ }
+}
+
+void PrintMessage(const aos::Channel *channel, const aos::Context &context,
+ aos::FastStringBuilder *builder, PrintOptions options) {
+ PrintMessage("", channel, context, builder, options);
+}
+
+void PrintMessage(const std::string_view node_name,
+ aos::NodeEventLoopFactory *node_factory,
+ const aos::Channel *channel, const aos::Context &context,
+ aos::FastStringBuilder *builder, PrintOptions options) {
+ if (!options.json && options.distributed_clock) {
+ std::cout << node_factory->ToDistributedClock(context.monotonic_event_time)
+ << " ";
+ }
+ PrintMessage(node_name, channel, context, builder, options);
+}
+
} // namespace aos
diff --git a/aos/aos_cli_utils.h b/aos/aos_cli_utils.h
index a2d8c62..7e143dd 100644
--- a/aos/aos_cli_utils.h
+++ b/aos/aos_cli_utils.h
@@ -3,10 +3,40 @@
#include "aos/configuration.h"
#include "aos/events/shm_event_loop.h"
+#include "aos/events/simulated_event_loop.h"
#include "gflags/gflags.h"
namespace aos {
+struct PrintOptions {
+ // Format the JSON with the pretty option.
+ bool pretty;
+ // Max vector size to skip expanding.
+ size_t max_vector_size;
+ // Put everything on a separate line instead of keeping small messages
+ // together.
+ bool pretty_max;
+ // Print the timestamps.
+ bool print_timestamps;
+ // Make everything JSON compliant.
+ bool json;
+ // Print the distributed clock.
+ bool distributed_clock;
+ // Print numbers out in hex.
+ bool use_hex;
+};
+
+// Print the flatbuffer out to stdout, both to remove the unnecessary cruft from
+// glog and to allow the user to readily redirect just the logged output
+// independent of any debugging information on stderr.
+void PrintMessage(const std::string_view node_name,
+ aos::NodeEventLoopFactory *node_factory,
+ const aos::Channel *channel, const aos::Context &context,
+ aos::FastStringBuilder *builder, PrintOptions options);
+
+void PrintMessage(const aos::Channel *channel, const aos::Context &context,
+ aos::FastStringBuilder *builder, PrintOptions options);
+
// The information needed by the main function of a CLI tool.
struct CliUtilInfo {
// If this returns true, main should return immediately with 0.
diff --git a/aos/aos_dump.cc b/aos/aos_dump.cc
index 86f4305..9f3d01f 100644
--- a/aos/aos_dump.cc
+++ b/aos/aos_dump.cc
@@ -8,8 +8,9 @@
#include "aos/json_to_flatbuffer.h"
#include "gflags/gflags.h"
-DEFINE_int32(max_vector_size, 100,
+DEFINE_int64(max_vector_size, 100,
"If positive, vectors longer than this will not be printed");
+DEFINE_bool(json, false, "If true, print fully valid JSON");
DEFINE_bool(fetch, false,
"If true, fetch the current message on the channel first");
DEFINE_bool(pretty, false,
@@ -28,46 +29,6 @@
"exiting. -1 means forever, 0 means don't wait.");
DEFINE_bool(use_hex, false, "Are integers in the messages printed in hex notation.");
-namespace {
-
-void PrintMessage(const aos::Channel *channel, const aos::Context &context,
- aos::FastStringBuilder *builder) {
- // Print the flatbuffer out to stdout, both to remove the
- // unnecessary cruft from glog and to allow the user to readily
- // redirect just the logged output independent of any debugging
- // information on stderr.
-
- builder->Reset();
-
- CHECK(flatbuffers::Verify(*channel->schema(),
- *channel->schema()->root_table(),
- static_cast<const uint8_t *>(context.data),
- static_cast<size_t>(context.size)))
- << ": Corrupted flatbuffer on " << channel->name()->c_str() << " "
- << channel->type()->c_str();
-
- aos::FlatbufferToJson(
- builder, channel->schema(), static_cast<const uint8_t *>(context.data),
- {FLAGS_pretty, static_cast<size_t>(FLAGS_max_vector_size),
- FLAGS_pretty_max, FLAGS_use_hex});
-
- if (FLAGS_print_timestamps) {
- if (context.monotonic_remote_time != context.monotonic_event_time) {
- std::cout << context.realtime_remote_time << " ("
- << context.monotonic_remote_time << ") delivered "
- << context.realtime_event_time << " ("
- << context.monotonic_event_time << "): " << *builder << '\n';
- } else {
- std::cout << context.realtime_event_time << " ("
- << context.monotonic_event_time << "): " << *builder << '\n';
- }
- } else {
- std::cout << *builder << '\n';
- }
-}
-
-} // namespace
-
int main(int argc, char **argv) {
gflags::SetUsageMessage(
"Prints messages from arbitrary channels as they are received given a "
@@ -94,12 +55,23 @@
aos::monotonic_clock::time_point next_send_time =
aos::monotonic_clock::min_time;
+
for (const aos::Channel *channel : cli_info.found_channels) {
if (FLAGS_fetch) {
const std::unique_ptr<aos::RawFetcher> fetcher =
cli_info.event_loop->MakeRawFetcher(channel);
if (fetcher->Fetch()) {
- PrintMessage(channel, fetcher->context(), &str_builder);
+ PrintMessage(
+ channel, fetcher->context(), &str_builder,
+ {
+ .pretty = FLAGS_pretty,
+ .max_vector_size = static_cast<size_t>(FLAGS_max_vector_size),
+ .pretty_max = FLAGS_pretty_max,
+ .print_timestamps = FLAGS_print_timestamps,
+ .json = FLAGS_json,
+ .distributed_clock = false,
+ .use_hex = FLAGS_use_hex,
+ });
++message_count;
}
}
@@ -120,7 +92,17 @@
if (FLAGS_count > 0 && message_count >= FLAGS_count) {
return;
}
- PrintMessage(channel, context, &str_builder);
+ PrintMessage(channel, context, &str_builder,
+ {
+ .pretty = FLAGS_pretty,
+ .max_vector_size =
+ static_cast<size_t>(FLAGS_max_vector_size),
+ .pretty_max = FLAGS_pretty_max,
+ .print_timestamps = FLAGS_print_timestamps,
+ .json = FLAGS_json,
+ .distributed_clock = false,
+ .use_hex = FLAGS_use_hex,
+ });
++message_count;
next_send_time = context.monotonic_event_time +
std::chrono::milliseconds(FLAGS_rate_limit);
diff --git a/aos/events/logging/BUILD b/aos/events/logging/BUILD
index 0afdda0..e32da37 100644
--- a/aos/events/logging/BUILD
+++ b/aos/events/logging/BUILD
@@ -310,6 +310,7 @@
visibility = ["//visibility:public"],
deps = [
":log_reader",
+ "//aos:aos_cli_utils",
"//aos:configuration",
"//aos:init",
"//aos:json_to_flatbuffer",
diff --git a/aos/events/logging/log_cat.cc b/aos/events/logging/log_cat.cc
index 1333de6..1f166e4 100644
--- a/aos/events/logging/log_cat.cc
+++ b/aos/events/logging/log_cat.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "absl/strings/escaping.h"
+#include "aos/aos_cli_utils.h"
#include "aos/configuration.h"
#include "aos/events/logging/log_reader.h"
#include "aos/events/simulated_event_loop.h"
@@ -33,10 +34,14 @@
DEFINE_bool(format_raw, true,
"If true and --raw is specified, print out raw data, but use the "
"schema to format the data.");
-DEFINE_int32(max_vector_size, 100,
+DEFINE_int64(max_vector_size, 100,
"If positive, vectors longer than this will not be printed");
DEFINE_bool(pretty, false,
"If true, pretty print the messages on multiple lines");
+DEFINE_bool(
+ pretty_max, false,
+ "If true, expand every field to its own line (expands more than -pretty)");
+DEFINE_bool(print_timestamps, true, "If true, timestamps are printed.");
DEFINE_bool(print, true,
"If true, actually print the messages. If false, discard them, "
"confirming they can be parsed.");
@@ -59,94 +64,6 @@
using aos::monotonic_clock;
namespace chrono = std::chrono;
-void StreamSeconds(std::ostream &stream,
- const aos::monotonic_clock::time_point now) {
- if (now < monotonic_clock::epoch()) {
- chrono::seconds seconds =
- chrono::duration_cast<chrono::seconds>(now.time_since_epoch());
-
- stream << "-" << -seconds.count() << "." << std::setfill('0')
- << std::setw(9)
- << chrono::duration_cast<chrono::nanoseconds>(seconds -
- now.time_since_epoch())
- .count();
- } else {
- chrono::seconds seconds =
- chrono::duration_cast<chrono::seconds>(now.time_since_epoch());
- stream << seconds.count() << "." << std::setfill('0') << std::setw(9)
- << chrono::duration_cast<chrono::nanoseconds>(
- now.time_since_epoch() - seconds)
- .count();
- }
-}
-
-// Print the flatbuffer out to stdout, both to remove the unnecessary cruft from
-// glog and to allow the user to readily redirect just the logged output
-// independent of any debugging information on stderr.
-void PrintMessage(const std::string_view node_name,
- aos::NodeEventLoopFactory *node_factory,
- const aos::Channel *channel, const aos::Context &context,
- aos::FastStringBuilder *builder) {
- builder->Reset();
- CHECK(flatbuffers::Verify(*channel->schema(),
- *channel->schema()->root_table(),
- static_cast<const uint8_t *>(context.data),
- static_cast<size_t>(context.size)))
- << ": Corrupted flatbuffer on " << channel->name()->c_str() << " "
- << channel->type()->c_str();
-
- aos::FlatbufferToJson(
- builder, channel->schema(), static_cast<const uint8_t *>(context.data),
- {.multi_line = FLAGS_pretty,
- .max_vector_size = static_cast<size_t>(FLAGS_max_vector_size),
- .max_multi_line = false,
- .use_hex = FLAGS_use_hex});
-
- if (FLAGS_json) {
- std::cout << "{";
- if (!node_name.empty()) {
- std::cout << "\"node\": \"" << node_name << "\", ";
- }
- std::cout << "\"monotonic_event_time\": ";
- StreamSeconds(std::cout, context.monotonic_event_time);
- std::cout << ", \"realtime_event_time\": \"" << context.realtime_event_time
- << "\", ";
-
- if (context.monotonic_remote_time != context.monotonic_event_time) {
- std::cout << "\"monotonic_remote_time\": ";
- StreamSeconds(std::cout, context.monotonic_remote_time);
- std::cout << ", \"realtime_remote_time\": \""
- << context.realtime_remote_time << "\", ";
- }
-
- std::cout << "\"channel\": "
- << aos::configuration::StrippedChannelToString(channel)
- << ", \"data\": " << *builder << "}" << std::endl;
- } else {
- if (FLAGS_distributed_clock) {
- std::cout << node_factory->ToDistributedClock(
- context.monotonic_event_time)
- << " ";
- }
- if (!node_name.empty()) {
- std::cout << node_name << " ";
- }
- if (context.monotonic_remote_time != context.monotonic_event_time) {
- std::cout << context.realtime_event_time << " ("
- << context.monotonic_event_time << ") sent "
- << context.realtime_remote_time << " ("
- << context.monotonic_remote_time << ") "
- << channel->name()->c_str() << ' ' << channel->type()->c_str()
- << ": " << *builder << std::endl;
- } else {
- std::cout << context.realtime_event_time << " ("
- << context.monotonic_event_time << ") "
- << channel->name()->c_str() << ' ' << channel->type()->c_str()
- << ": " << *builder << std::endl;
- }
- }
-}
-
// Prints out raw log parts to stdout.
int PrintRaw(int argc, char **argv) {
if (argc != 2) {
@@ -336,7 +253,17 @@
return;
}
- PrintMessage(node_name_, node_factory_, channel, context, builder_);
+ PrintMessage(
+ node_name_, node_factory_, channel, context, builder_,
+ {
+ .pretty = FLAGS_pretty,
+ .max_vector_size = static_cast<size_t>(FLAGS_max_vector_size),
+ .pretty_max = FLAGS_pretty_max,
+ .print_timestamps = FLAGS_print_timestamps,
+ .json = FLAGS_json,
+ .distributed_clock = FLAGS_distributed_clock,
+ .use_hex = FLAGS_use_hex,
+ });
++(*message_print_counter_);
if (FLAGS_count > 0 && *message_print_counter_ >= FLAGS_count) {
factory_->Exit();