Add callback log implementation

Change-Id: If37d1cd421f688258d1fa4bfb89e840df0334060
diff --git a/aos/logging/implementations.cc b/aos/logging/implementations.cc
index 89fc904..b35414e 100644
--- a/aos/logging/implementations.cc
+++ b/aos/logging/implementations.cc
@@ -1,16 +1,16 @@
 #include "aos/logging/implementations.h"
 
-#include <stdarg.h>
 #include <inttypes.h>
+#include <stdarg.h>
 
 #include <algorithm>
 #include <chrono>
 
+#include "absl/base/call_once.h"
 #include "aos/die.h"
+#include "aos/ipc_lib/queue.h"
 #include "aos/logging/printf_formats.h"
 #include "aos/time/time.h"
-#include "aos/ipc_lib/queue.h"
-#include "absl/base/call_once.h"
 
 namespace aos {
 namespace logging {
@@ -36,8 +36,8 @@
     AOS_LOG(FATAL, "can't have a next logger from here\n");
   }
 
-  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
-  void DoLog(log_level level, const char *format, va_list ap) override {
+  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
+      log_level level, const char *format, va_list ap) override {
     LogMessage message;
     internal::FillInMessage(level, monotonic_now(), format, ap, &message);
     internal::PrintMessage(stderr, message);
@@ -63,15 +63,13 @@
   internal::global_top_implementation.store(implementation);
 }
 
-void NewContext() {
-  internal::Context::Delete();
-}
+void NewContext() { internal::Context::Delete(); }
 
 void DoInit() {
   SetGlobalImplementation(root_implementation = new RootLogImplementation());
 
-  if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/,
-                     NewContext /*child*/) != 0) {
+  if (pthread_atfork(NULL /*prepare*/, NULL /*parent*/, NewContext /*child*/) !=
+      0) {
     AOS_LOG(FATAL, "pthread_atfork(NULL, NULL, %p) failed\n", NewContext);
   }
 }
@@ -165,13 +163,9 @@
   absl::call_once(once, DoInit);
 }
 
-void Load() {
-  internal::Context::Get();
-}
+void Load() { internal::Context::Get(); }
 
-void Cleanup() {
-  internal::Context::Delete();
-}
+void Cleanup() { internal::Context::Delete(); }
 
 namespace {
 
@@ -239,14 +233,26 @@
     return ::aos::monotonic_clock::now();
   }
 
-  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
-  void DoLog(log_level level, const char *format, va_list ap) override {
+  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
+      log_level level, const char *format, va_list ap) override {
     LogMessage *message = GetMessageOrDie();
     internal::FillInMessage(level, monotonic_now(), format, ap, message);
     Write(message);
   }
 };
 
+class CallbackLogImplementation : public HandleMessageLogImplementation {
+ public:
+  CallbackLogImplementation(
+      const ::std::function<void(const LogMessage &)> &callback)
+      : callback_(callback) {}
+
+ private:
+  void HandleMessage(const LogMessage &message) override { callback_(message); }
+
+  ::std::function<void(const LogMessage &)> callback_;
+};
+
 }  // namespace
 
 RawQueue *GetLoggingQueue() {
@@ -264,5 +270,11 @@
   AddImplementation(new LinuxQueueLogImplementation());
 }
 
+void RegisterCallbackImplementation(
+    const ::std::function<void(const LogMessage &)> &callback) {
+  Init();
+  AddImplementation(new CallbackLogImplementation(callback));
+}
+
 }  // namespace logging
 }  // namespace aos
diff --git a/aos/logging/implementations.h b/aos/logging/implementations.h
index 27c0472..ce8271f 100644
--- a/aos/logging/implementations.h
+++ b/aos/logging/implementations.h
@@ -1,17 +1,17 @@
 #ifndef AOS_LOGGING_IMPLEMENTATIONS_H_
 #define AOS_LOGGING_IMPLEMENTATIONS_H_
 
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <stdint.h>
-#include <limits.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdarg.h>
 
-#include <string>
-#include <functional>
 #include <atomic>
+#include <functional>
+#include <string>
 
 #include "aos/logging/context.h"
 #include "aos/logging/interface.h"
@@ -42,9 +42,7 @@
 
 // Contains all of the information about a given logging call.
 struct LogMessage {
-  enum class Type : uint8_t {
-    kString
-  };
+  enum class Type : uint8_t { kString };
 
   int32_t seconds, nseconds;
   // message_length is just the length of the actual data (which member depends
@@ -71,8 +69,7 @@
       int rows, cols;
       size_t string_length;
       // The message string and then the serialized matrix.
-      char
-          data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
+      char data[LOG_MESSAGE_LEN - sizeof(type) - sizeof(rows) - sizeof(cols)];
     } matrix;
   };
 };
@@ -87,14 +84,16 @@
 
 // Returns a string representing level or "unknown".
 static inline const char *log_str(log_level level) {
-#define DECL_LEVEL(name, value) if (level == name) return #name;
+#define DECL_LEVEL(name, value) \
+  if (level == name) return #name;
   DECL_LEVELS;
 #undef DECL_LEVEL
   return "unknown";
 }
 // Returns the log level represented by str or LOG_UNKNOWN.
 static inline log_level str_log(const char *str) {
-#define DECL_LEVEL(name, value) if (!strcmp(str, #name)) return name;
+#define DECL_LEVEL(name, value) \
+  if (!strcmp(str, #name)) return name;
   DECL_LEVELS;
 #undef DECL_LEVEL
   return LOG_UNKNOWN;
@@ -109,8 +108,8 @@
   }
 
  private:
-  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
-  void DoLog(log_level level, const char *format, va_list ap) override;
+  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
+      log_level level, const char *format, va_list ap) override;
 
   virtual void HandleMessage(const LogMessage &message) = 0;
 };
@@ -159,6 +158,9 @@
 // This function is usually called by aos::Init*.
 void RegisterQueueImplementation();
 
+void RegisterCallbackImplementation(
+    const ::std::function<void(const LogMessage &)> &callback);
+
 // This is where all of the code that is only used by actual LogImplementations
 // goes.
 namespace internal {