Merge //aos/linux_code/logging into //aos/common/logging

Shuffling files+targets to clean it up further is coming next.

Change-Id: Iae716b07b340a66502f8e0964281c10fae0fcb7a
diff --git a/aos/common/logging/log_replay.h b/aos/common/logging/log_replay.h
new file mode 100644
index 0000000..6fb230c
--- /dev/null
+++ b/aos/common/logging/log_replay.h
@@ -0,0 +1,164 @@
+#ifndef AOS_COMMON_LOGGING_LOG_REPLAY_H_
+#define AOS_COMMON_LOGGING_LOG_REPLAY_H_
+
+#include <unordered_map>
+#include <string>
+#include <functional>
+#include <memory>
+
+#include "aos/common/logging/binary_log_file.h"
+#include "aos/common/queue.h"
+#include "aos/common/logging/logging.h"
+#include "aos/common/macros.h"
+#include "aos/linux_code/ipc_lib/queue.h"
+#include "aos/common/queue_types.h"
+
+namespace aos {
+namespace logging {
+namespace linux_code {
+
+// Manages pulling logged queue messages out of log files.
+//
+// Basic usage:
+//   - Use the Add* methods to register handlers for various message sources.
+//   - Call OpenFile to open a log file.
+//   - Call ProcessMessage repeatedly until it returns true.
+//
+// This code could do something to adapt similar-but-not-identical
+// messages to the current versions, but currently it will LOG(FATAL) if any of
+// the messages don't match up exactly.
+class LogReplayer {
+ public:
+  LogReplayer() {}
+
+  // Gets ready to read messages from fd.
+  // Does not take ownership of fd.
+  void OpenFile(int fd) {
+    reader_.reset(new LogFileReader(fd));
+  }
+  // Closes the currently open file.
+  void CloseCurrentFile() { reader_.reset(); }
+  // Returns true if we have a file which is currently open.
+  bool HasCurrentFile() const { return reader_.get() != nullptr; }
+
+  // Processes a single message from the currently open file.
+  // Returns true if there are no more messages in the file.
+  // This will not call any of the handlers if the next message either has no
+  // registered handlers or is not a queue message.
+  bool ProcessMessage();
+
+  // Adds a handler for messages with a certain string from a certain process.
+  // T must be a Message with the same format as the messages generated by
+  // the .q files.
+  // LOG(FATAL)s for duplicate handlers.
+  template <class T>
+  void AddHandler(const ::std::string &process_name,
+                  const ::std::string &log_message,
+                  ::std::function<void(const T &message)> handler) {
+    CHECK(handlers_.emplace(
+        ::std::piecewise_construct,
+        ::std::forward_as_tuple(process_name, log_message),
+        ::std::forward_as_tuple(::std::unique_ptr<StructHandlerInterface>(
+            new TypedStructHandler<T>(handler)))).second);
+  }
+
+  // Adds a handler which takes messages and places them directly on a queue.
+  // T must be a Message with the same format as the messages generated by
+  // the .q files.
+  template <class T>
+  void AddDirectQueueSender(const ::std::string &process_name,
+                            const ::std::string &log_message,
+                            const ::aos::Queue<T> &queue) {
+    AddHandler(process_name, log_message,
+               ::std::function<void(const T &)>(
+                   QueueDumpStructHandler<T>(queue.name())));
+  }
+
+ private:
+  // A generic handler of struct log messages.
+  class StructHandlerInterface {
+   public:
+    virtual ~StructHandlerInterface() {}
+
+    virtual void HandleStruct(::aos::time::Time log_time, uint32_t type_id,
+                              const void *data, size_t data_size) = 0;
+  };
+
+  // Converts struct log messages to a message type and passes it to an
+  // ::std::function.
+  template <class T>
+  class TypedStructHandler : public StructHandlerInterface {
+   public:
+    TypedStructHandler(::std::function<void(const T &message)> handler)
+        : handler_(handler) {}
+
+    void HandleStruct(::aos::time::Time log_time, uint32_t type_id,
+                      const void *data, size_t data_size) override {
+      CHECK_EQ(type_id, T::GetType()->id);
+      T message;
+      CHECK_EQ(data_size, T::Size());
+      CHECK_EQ(data_size, message.Deserialize(static_cast<const char *>(data)));
+      message.sent_time = log_time;
+      handler_(message);
+    }
+
+   private:
+    const ::std::function<void(T message)> handler_;
+  };
+
+  // A callable class which dumps messages straight to a queue.
+  template <class T>
+  class QueueDumpStructHandler {
+   public:
+    QueueDumpStructHandler(const ::std::string &queue_name)
+        : queue_(RawQueue::Fetch(queue_name.c_str(), sizeof(T), T::kHash,
+                                 T::kQueueLength)) {}
+
+    void operator()(const T &message) {
+      LOG_STRUCT(DEBUG, "re-sending", message);
+      void *raw_message = queue_->GetMessage();
+      CHECK_NOTNULL(raw_message);
+      memcpy(raw_message, &message, sizeof(message));
+      CHECK(queue_->WriteMessage(raw_message, RawQueue::kOverride));
+    }
+
+   private:
+    ::aos::RawQueue *const queue_;
+  };
+
+  // A key for specifying log messages to give to a certain handler.
+  struct Key {
+    Key(const ::std::string &process_name, const ::std::string &log_message)
+        : process_name(process_name), log_message(log_message) {}
+
+    ::std::string process_name;
+    ::std::string log_message;
+  };
+
+  struct KeyHash {
+    size_t operator()(const Key &key) const {
+      return string_hash(key.process_name) ^
+             (string_hash(key.log_message) << 1);
+    }
+
+   private:
+    const ::std::hash<::std::string> string_hash = ::std::hash<::std::string>();
+  };
+  struct KeyEqual {
+    bool operator()(const Key &a, const Key &b) const {
+      return a.process_name == b.process_name && a.log_message == b.log_message;
+    }
+  };
+
+  ::std::unordered_map<const Key, ::std::unique_ptr<StructHandlerInterface>,
+                       KeyHash, KeyEqual> handlers_;
+  ::std::unique_ptr<LogFileReader> reader_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogReplayer);
+};
+
+}  // namespace linux_code
+}  // namespace logging
+}  // namespace aos
+
+#endif  // AOS_COMMON_LOGGING_LOG_REPLAY_H_