Add --json to log_cat to print fully valid json
This makes it easy to use JSON based tooling to dig inside the results.
Change-Id: I483869fe27e117bdf86b9f775371842477ef1cbe
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/events/logging/log_cat.cc b/aos/events/logging/log_cat.cc
index 71293af..60ad0e2 100644
--- a/aos/events/logging/log_cat.cc
+++ b/aos/events/logging/log_cat.cc
@@ -20,6 +20,7 @@
DEFINE_string(type, "",
"Channel type to match for printing out channels. Empty means no "
"type filter.");
+DEFINE_bool(json, false, "If true, print fully valid JSON");
DEFINE_bool(fetch, false,
"If true, also print out the messages from before the start of the "
"log file");
@@ -46,6 +47,30 @@
DEFINE_bool(channels, false,
"If true, print out all the configured channels for this log.");
+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.
@@ -64,18 +89,43 @@
builder, channel->schema(), static_cast<const uint8_t *>(context.data),
{FLAGS_pretty, static_cast<size_t>(FLAGS_max_vector_size)});
- if (context.monotonic_remote_time != context.monotonic_event_time) {
- std::cout << node_name << 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;
+ 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 {
- std::cout << node_name << context.realtime_event_time << " ("
- << context.monotonic_event_time << ") "
- << channel->name()->c_str() << ' ' << channel->type()->c_str()
- << ": " << *builder << std::endl;
+ 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;
+ }
}
}
@@ -214,7 +264,7 @@
node_name_(
event_loop_->node() == nullptr
? ""
- : std::string(event_loop->node()->name()->string_view()) + " "),
+ : std::string(event_loop->node()->name()->string_view())),
builder_(builder) {
event_loop_->SkipTimingReport();
event_loop_->SkipAosLog();
@@ -259,6 +309,9 @@
void SetStarted(bool started, aos::monotonic_clock::time_point monotonic_now,
aos::realtime_clock::time_point realtime_now) {
started_ = started;
+ if (FLAGS_json) {
+ return;
+ }
if (started_) {
std::cout << std::endl;
std::cout << (event_loop_->node() != nullptr
diff --git a/aos/flatbuffer_introspection.cc b/aos/flatbuffer_introspection.cc
index 5f6ca45..b7f3727 100644
--- a/aos/flatbuffer_introspection.cc
+++ b/aos/flatbuffer_introspection.cc
@@ -200,9 +200,9 @@
reflection::BaseType elem_type = type->element();
if (vector->size() > json_options.max_vector_size) {
- out->Append("[ ... ");
+ out->Append("[ \"... ");
out->AppendInt(vector->size());
- out->Append(" elements ... ]");
+ out->Append(" elements ...\" ]");
break;
}
diff --git a/aos/flatbuffer_introspection_test.cc b/aos/flatbuffer_introspection_test.cc
index fe8460f..e435709 100644
--- a/aos/flatbuffer_introspection_test.cc
+++ b/aos/flatbuffer_introspection_test.cc
@@ -362,7 +362,7 @@
std::string out =
FlatbufferToJson(schema_, builder.GetBufferPointer(),
{.multi_line = false, .max_vector_size = 100});
- EXPECT_EQ(out, "{\"vector_foo_int\": [ ... 101 elements ... ]}");
+ EXPECT_EQ(out, "{\"vector_foo_int\": [ \"... 101 elements ...\" ]}");
}
TEST_F(FlatbufferIntrospectionTest, MultilineTest) {
diff --git a/aos/json_to_flatbuffer.cc b/aos/json_to_flatbuffer.cc
index 11ea3a2..6d4a2f1 100644
--- a/aos/json_to_flatbuffer.cc
+++ b/aos/json_to_flatbuffer.cc
@@ -840,7 +840,7 @@
}
if (size > max_vector_size_) {
++skip_levels_;
- to_string_.s += "[ ... " + std::to_string(size) + " elements ... ]";
+ to_string_.s += "[ \"... " + std::to_string(size) + " elements ...\" ]";
return;
}
to_string_.StartVector(size);
diff --git a/aos/json_to_flatbuffer_test.cc b/aos/json_to_flatbuffer_test.cc
index e353b99..42457f6 100644
--- a/aos/json_to_flatbuffer_test.cc
+++ b/aos/json_to_flatbuffer_test.cc
@@ -270,9 +270,9 @@
EXPECT_EQ(json_short, back_json_short_typetable);
EXPECT_EQ(json_short, back_json_short_reflection);
- EXPECT_EQ("{ \"vector_foo_int\": [ ... 101 elements ... ] }",
+ EXPECT_EQ("{ \"vector_foo_int\": [ \"... 101 elements ...\" ] }",
back_json_long_typetable);
- EXPECT_EQ("{ \"vector_foo_int\": [ ... 101 elements ... ] }",
+ EXPECT_EQ("{ \"vector_foo_int\": [ \"... 101 elements ...\" ] }",
back_json_long_reflection);
}