Work around duplicate headers at the start of logs
Somehow, we have managed to log duplicate headers at the beginning of
some of our logs.
log_11_data/11/aos/aos.message_bridge.Timestamp.part0.bfbs.xz and
friends seem to be where we are finding these issues. Hide this
behavior behind a flag.
We urgently need a follow-up commit which fixes the log writer so it
doesn't write duplicate headers. Unfortuantely, we have valuable data
logged with duplicate headers in it so we need this workaround.
Change-Id: I905023fc647547fda5004b303f1a6988ec311a93
Signed-off-by: Austin Schuh <austin.schuh@bluerivertech.com>
diff --git a/aos/events/logging/log_cat.cc b/aos/events/logging/log_cat.cc
index c2378ab..edd0ac7 100644
--- a/aos/events/logging/log_cat.cc
+++ b/aos/events/logging/log_cat.cc
@@ -6,6 +6,7 @@
#include <string_view>
#include <vector>
+#include "absl/strings/escaping.h"
#include "aos/configuration.h"
#include "aos/events/logging/log_reader.h"
#include "aos/events/simulated_event_loop.h"
@@ -91,20 +92,61 @@
if (argc != 2) {
LOG(FATAL) << "Expected 1 logfile as an argument.";
}
- aos::logger::MessageReader reader(argv[1]);
+ aos::logger::SpanReader reader(argv[1]);
+ absl::Span<const uint8_t> raw_log_file_header_span = reader.ReadMessage();
+ if (raw_log_file_header_span == absl::Span<const uint8_t>()) {
+ LOG(WARNING) << "Empty log file on " << reader.filename();
+ return 0;
+ }
+
+ // Now, reproduce the log file header deduplication logic inline so we can
+ // print out all the headers we find.
+ aos::SizePrefixedFlatbufferVector<aos::logger::LogFileHeader>
+ log_file_header(raw_log_file_header_span);
+ if (!log_file_header.Verify()) {
+ LOG(ERROR) << "Header corrupted on " << reader.filename();
+ return 1;
+ }
+ while (true) {
+ absl::Span<const uint8_t> maybe_header_data = reader.PeekMessage();
+ if (maybe_header_data == absl::Span<const uint8_t>()) {
+ break;
+ }
+
+ aos::SizePrefixedFlatbufferSpan<aos::logger::LogFileHeader> maybe_header(
+ maybe_header_data);
+ if (maybe_header.Verify()) {
+ std::cout << aos::FlatbufferToJson(
+ log_file_header,
+ {.multi_line = FLAGS_pretty,
+ .max_vector_size =
+ static_cast<size_t>(FLAGS_max_vector_size)})
+ << std::endl;
+ LOG(WARNING) << "Found duplicate LogFileHeader in "
+ << reader.filename();
+ log_file_header =
+ aos::SizePrefixedFlatbufferVector<aos::logger::LogFileHeader>(
+ maybe_header_data);
+
+ reader.ConsumeMessage();
+ } else {
+ break;
+ }
+ }
+
+ // And now use the final sha256 to match the raw_header.
std::optional<aos::logger::MessageReader> raw_header_reader;
- const aos::logger::LogFileHeader *full_header = reader.log_file_header();
+ const aos::logger::LogFileHeader *full_header = &log_file_header.message();
if (!FLAGS_raw_header.empty()) {
raw_header_reader.emplace(FLAGS_raw_header);
std::cout << aos::FlatbufferToJson(
- reader.log_file_header(),
- {.multi_line = FLAGS_pretty,
- .max_vector_size =
- static_cast<size_t>(FLAGS_max_vector_size)})
+ full_header, {.multi_line = FLAGS_pretty,
+ .max_vector_size = static_cast<size_t>(
+ FLAGS_max_vector_size)})
<< std::endl;
CHECK_EQ(
- reader.log_file_header()->configuration_sha256()->string_view(),
+ full_header->configuration_sha256()->string_view(),
aos::logger::Sha256(raw_header_reader->raw_log_file_header().span()));
full_header = raw_header_reader->log_file_header();
}
@@ -115,46 +157,45 @@
<< std::endl;
while (true) {
- std::optional<
- aos::SizePrefixedFlatbufferVector<aos::logger::MessageHeader>>
- message = reader.ReadMessage();
- if (!message) {
+ const aos::SizePrefixedFlatbufferSpan<aos::logger::MessageHeader> message(
+ reader.ReadMessage());
+ if (message.span() == absl::Span<const uint8_t>()) {
break;
}
const auto *const channels = full_header->configuration()->channels();
- const size_t channel_index = message.value().message().channel_index();
+ const size_t channel_index = message.message().channel_index();
CHECK_LT(channel_index, channels->size());
const aos::Channel *const channel = channels->Get(channel_index);
- if (message.value().message().data() != nullptr) {
+ CHECK(message.Verify()) << absl::BytesToHexString(std::string_view(
+ reinterpret_cast<const char *>(message.span().data()),
+ message.span().size()));
+
+ if (message.message().data() != nullptr) {
CHECK(channel->has_schema());
- CHECK(flatbuffers::Verify(*channel->schema(),
- *channel->schema()->root_table(),
- message.value().message().data()->data(),
- message.value().message().data()->size()))
+ CHECK(flatbuffers::Verify(
+ *channel->schema(), *channel->schema()->root_table(),
+ message.message().data()->data(), message.message().data()->size()))
<< ": Corrupted flatbuffer on " << channel->name()->c_str() << " "
<< channel->type()->c_str();
}
- if (FLAGS_format_raw && message.value().message().data() != nullptr) {
+ if (FLAGS_format_raw && message.message().data() != nullptr) {
std::cout << aos::configuration::StrippedChannelToString(channel) << " "
- << aos::FlatbufferToJson(
- message.value(),
- {.multi_line = FLAGS_pretty, .max_vector_size = 4})
+ << aos::FlatbufferToJson(message, {.multi_line = FLAGS_pretty,
+ .max_vector_size = 4})
<< ": "
<< aos::FlatbufferToJson(
- channel->schema(),
- message.value().message().data()->data(),
+ channel->schema(), message.message().data()->data(),
{FLAGS_pretty,
static_cast<size_t>(FLAGS_max_vector_size)})
<< std::endl;
} else {
std::cout << aos::configuration::StrippedChannelToString(channel) << " "
<< aos::FlatbufferToJson(
- message.value(),
- {FLAGS_pretty,
- static_cast<size_t>(FLAGS_max_vector_size)})
+ message, {FLAGS_pretty,
+ static_cast<size_t>(FLAGS_max_vector_size)})
<< std::endl;
}
}