Add logger version and sha1 to the logfile header

This makes it a lot easier to track down where a failure came from.

Change-Id: Ieeb568049b64cb69d990e4c55bb7051225a602f8
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/events/logging/log_namer.cc b/aos/events/logging/log_namer.cc
index f269f43..6fd39f8 100644
--- a/aos/events/logging/log_namer.cc
+++ b/aos/events/logging/log_namer.cc
@@ -268,7 +268,7 @@
   const UUID &source_node_boot_uuid = state[node_index].boot_uuid;
   const Node *const source_node =
       configuration::GetNode(configuration_, node_index);
-  CHECK_EQ(LogFileHeader::MiniReflectTypeTable()->num_elems, 32u);
+  CHECK_EQ(LogFileHeader::MiniReflectTypeTable()->num_elems, 34u);
   flatbuffers::FlatBufferBuilder fbb;
   fbb.ForceDefaults(true);
 
@@ -288,6 +288,14 @@
   CHECK(header_.message().has_name());
   const flatbuffers::Offset<flatbuffers::String> name_offset =
       fbb.CreateString(header_.message().name()->string_view());
+  const flatbuffers::Offset<flatbuffers::String> logger_sha1_offset =
+      header_.message().has_logger_sha1()
+          ? fbb.CreateString(header_.message().logger_sha1()->string_view())
+          : 0;
+  const flatbuffers::Offset<flatbuffers::String> logger_version_offset =
+      header_.message().has_logger_version()
+          ? fbb.CreateString(header_.message().logger_version()->string_view())
+          : 0;
 
   CHECK(header_.message().has_log_event_uuid());
   const flatbuffers::Offset<flatbuffers::String> log_event_uuid_offset =
@@ -441,6 +449,12 @@
   aos::logger::LogFileHeader::Builder log_file_header_builder(fbb);
 
   log_file_header_builder.add_name(name_offset);
+  if (!logger_sha1_offset.IsNull()) {
+    log_file_header_builder.add_logger_sha1(logger_sha1_offset);
+  }
+  if (!logger_version_offset.IsNull()) {
+    log_file_header_builder.add_logger_version(logger_version_offset);
+  }
 
   // Only add the node if we are running in a multinode configuration.
   if (!logger_node_offset.IsNull()) {
diff --git a/aos/events/logging/log_writer.cc b/aos/events/logging/log_writer.cc
index 2a53f05..0dc4468 100644
--- a/aos/events/logging/log_writer.cc
+++ b/aos/events/logging/log_writer.cc
@@ -658,6 +658,11 @@
   const flatbuffers::Offset<flatbuffers::String> name_offset =
       fbb.CreateString(name_);
 
+  const flatbuffers::Offset<flatbuffers::String> logger_sha1_offset =
+      logger_sha1_.empty() ? 0 : fbb.CreateString(logger_sha1_);
+  const flatbuffers::Offset<flatbuffers::String> logger_version_offset =
+      logger_version_.empty() ? 0 : fbb.CreateString(logger_version_);
+
   CHECK(log_event_uuid_ != UUID::Zero());
   const flatbuffers::Offset<flatbuffers::String> log_event_uuid_offset =
       log_event_uuid_.PackString(&fbb);
@@ -687,6 +692,12 @@
   aos::logger::LogFileHeader::Builder log_file_header_builder(fbb);
 
   log_file_header_builder.add_name(name_offset);
+  if (!logger_sha1_offset.IsNull()) {
+    log_file_header_builder.add_logger_sha1(logger_sha1_offset);
+  }
+  if (!logger_version_offset.IsNull()) {
+    log_file_header_builder.add_logger_version(logger_version_offset);
+  }
 
   // Only add the node if we are running in a multinode configuration.
   if (configuration::MultiNode(configuration_)) {
diff --git a/aos/events/logging/log_writer.h b/aos/events/logging/log_writer.h
index 7beef03..23ab349 100644
--- a/aos/events/logging/log_writer.h
+++ b/aos/events/logging/log_writer.h
@@ -43,6 +43,11 @@
   // Overrides the name in the log file header.
   void set_name(std::string_view name) { name_ = name; }
 
+  void set_logger_sha1(std::string_view sha1) { logger_sha1_ = sha1; }
+  void set_logger_version(std::string_view version) {
+    logger_version_ = version;
+  }
+
   // Sets the callback to run after each period of data is logged. Defaults to
   // doing nothing.
   //
@@ -289,6 +294,8 @@
 
   // Name to save in the log file.  Defaults to hostname.
   std::string name_;
+  std::string logger_sha1_;
+  std::string logger_version_;
 
   std::function<void()> on_logged_period_ = []() {};
 
diff --git a/aos/events/logging/logfile_sorting.cc b/aos/events/logging/logfile_sorting.cc
index e0c378e..82b4684 100644
--- a/aos/events/logging/logfile_sorting.cc
+++ b/aos/events/logging/logfile_sorting.cc
@@ -93,7 +93,7 @@
 }
 
 bool ConfigOnly(const LogFileHeader *header) {
-  CHECK_EQ(LogFileHeader::MiniReflectTypeTable()->num_elems, 32u);
+  CHECK_EQ(LogFileHeader::MiniReflectTypeTable()->num_elems, 34u);
   if (header->has_monotonic_start_time()) return false;
   if (header->has_realtime_start_time()) return false;
   if (header->has_max_out_of_order_duration()) return false;
@@ -123,6 +123,8 @@
     return false;
   if (header->has_oldest_logger_local_unreliable_monotonic_timestamps())
     return false;
+  if (header->has_logger_sha1()) return false;
+  if (header->has_logger_version()) return false;
 
   return header->has_configuration();
 }
@@ -219,6 +221,10 @@
   // Name from a log.  All logs below have been confirmed to match.
   std::string name;
 
+  // Logger version info from the log.
+  std::string logger_sha1;
+  std::string logger_version;
+
   // Mapping from parts_uuid, source_boot_uuid -> parts.  We have log files
   // where the parts_uuid stays constant across reboots.
   std::map<std::pair<std::string, std::string>, UnsortedLogParts>
@@ -411,6 +417,16 @@
             ? log_header->message().name()->string_view()
             : "";
 
+    const std::string_view logger_sha1 =
+        log_header->message().has_logger_sha1()
+            ? log_header->message().logger_sha1()->string_view()
+            : "";
+
+    const std::string_view logger_version =
+        log_header->message().has_logger_version()
+            ? log_header->message().logger_version()->string_view()
+            : "";
+
     const std::string_view logger_node =
         log_header->message().has_logger_node()
             ? log_header->message().logger_node()->name()->string_view()
@@ -557,12 +573,16 @@
       log_it->second.log_start_uuid = log_start_uuid;
       log_it->second.logger_instance_uuid = logger_instance_uuid;
       log_it->second.name = name;
+      log_it->second.logger_sha1 = logger_sha1;
+      log_it->second.logger_version = logger_version;
     } else {
       CHECK_EQ(log_it->second.logger_node, logger_node);
       CHECK_EQ(log_it->second.logger_boot_uuid, logger_boot_uuid);
       CHECK_EQ(log_it->second.log_start_uuid, log_start_uuid);
       CHECK_EQ(log_it->second.logger_instance_uuid, logger_instance_uuid);
       CHECK_EQ(log_it->second.name, name);
+      CHECK_EQ(log_it->second.logger_sha1, logger_sha1);
+      CHECK_EQ(log_it->second.logger_version, logger_version);
     }
 
     if (node == log_it->second.logger_node) {
@@ -1825,6 +1845,8 @@
     new_file.monotonic_start_time = logs.second.monotonic_start_time;
     new_file.realtime_start_time = logs.second.realtime_start_time;
     new_file.name = logs.second.name;
+    new_file.logger_sha1 = logs.second.logger_sha1;
+    new_file.logger_version = logs.second.logger_version;
     new_file.corrupted = corrupted;
     new_file.boots = boot_counts;
     bool seen_part = false;
@@ -1994,6 +2016,15 @@
   if (!file.log_start_uuid.empty()) {
     stream << " \"log_start_uuid\": \"" << file.log_start_uuid << "\",\n";
   }
+  if (!file.name.empty()) {
+    stream << " \"name\": \"" << file.name << "\",\n";
+  }
+  if (!file.logger_sha1.empty()) {
+    stream << " \"logger_sha1\": \"" << file.logger_sha1 << "\",\n";
+  }
+  if (!file.logger_version.empty()) {
+    stream << " \"logger_version\": \"" << file.logger_version << "\",\n";
+  }
   stream << " \"config\": \"" << file.config.get() << "\"";
   if (!file.config_sha256.empty()) {
     stream << ",\n \"config_sha256\": \"" << file.config_sha256 << "\"";
diff --git a/aos/events/logging/logfile_sorting.h b/aos/events/logging/logfile_sorting.h
index 6e4b9b4..9e99bb2 100644
--- a/aos/events/logging/logfile_sorting.h
+++ b/aos/events/logging/logfile_sorting.h
@@ -110,6 +110,10 @@
   // The name field in the log file headers.
   std::string name;
 
+  // The logger version info in the logfile headers, if available.
+  std::string logger_sha1;
+  std::string logger_version;
+
   // All the parts, unsorted.
   std::vector<LogParts> parts;
 
diff --git a/aos/events/logging/logger.fbs b/aos/events/logging/logger.fbs
index 0fe6253..71a7b02 100644
--- a/aos/events/logging/logger.fbs
+++ b/aos/events/logging/logger.fbs
@@ -191,6 +191,13 @@
   // timestamps.
   oldest_logger_remote_unreliable_monotonic_timestamps:[int64] (id: 30);
   oldest_logger_local_unreliable_monotonic_timestamps:[int64] (id: 31);
+
+  // Logger build version.  This is normally the git sha1 that the logger was
+  // built from.
+  logger_sha1:string (id:32);
+  // Logger textual version.  This is normally the release name stamped into
+  // the binary.
+  logger_version:string (id:33);
 }
 
 // Table holding a message.
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index aee2883..ec273a8 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -556,6 +556,10 @@
     logger->set_polling_period(std::chrono::milliseconds(100));
     logger->set_name(
         absl::StrCat("name_prefix_", event_loop->node()->name()->str()));
+    logger->set_logger_sha1(
+        absl::StrCat("logger_sha1_", event_loop->node()->name()->str()));
+    logger->set_logger_version(
+        absl::StrCat("logger_version_", event_loop->node()->name()->str()));
     event_loop->OnRun([this, logfile_base]() {
       std::unique_ptr<MultiNodeLogNamer> namer =
           std::make_unique<MultiNodeLogNamer>(logfile_base, configuration,
@@ -991,6 +995,10 @@
       EXPECT_TRUE(log_file.config);
       EXPECT_EQ(log_file.name,
                 absl::StrCat("name_prefix_", log_file.logger_node));
+      EXPECT_EQ(log_file.logger_sha1,
+                absl::StrCat("logger_sha1_", log_file.logger_node));
+      EXPECT_EQ(log_file.logger_version,
+                absl::StrCat("logger_version_", log_file.logger_node));
 
       for (const LogParts &part : log_file.parts) {
         EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)