Untangle and clean up the logging code

It was a mess before because of a combination of having code split out
for cRIO vs Linux and cruft.

Change-Id: Id282e1a7f7988be0441c669a573a5d022ed41fb9
diff --git a/aos/common/BUILD b/aos/common/BUILD
index 4d0127b..8e911de 100644
--- a/aos/common/BUILD
+++ b/aos/common/BUILD
@@ -28,7 +28,7 @@
     ':once',
     ':queues',
     '//aos/testing:googletest',
-    '//aos/common/logging',
+    '//aos/common/logging:implementations',
     '//aos/linux_code/ipc_lib:shared_mem',
     ':mutex',
   ],
@@ -57,7 +57,7 @@
     'time.h',
   ],
   deps = [
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging:logging',
     ':mutex',
     ':macros',
     '//aos/linux_code/ipc_lib:shared_mem',
@@ -99,7 +99,7 @@
   deps = [
     '//aos/linux_code/ipc_lib:aos_sync',
     ':time',
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging:logging',
   ],
 )
 
@@ -125,7 +125,7 @@
     '//aos/linux_code/ipc_lib:shared_mem',
     '//aos/linux_code/ipc_lib:core_lib',
     ':mutex',
-    '//aos/common/logging:logging_printf_formats',
+    '//aos/common/logging:printf_formats',
     ':time',
     ':byteorder'
   ],
@@ -323,7 +323,7 @@
   deps = [
     ':mutex',
     '//aos/linux_code/ipc_lib:aos_sync',
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging:logging',
   ],
 )
 
@@ -379,7 +379,7 @@
   deps = [
     '//aos/linux_code/ipc_lib:aos_sync',
     ':die',
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging:logging',
     ':type_traits',
   ],
 )
@@ -404,7 +404,7 @@
     'transaction.h',
   ],
   deps = [
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging:logging',
     '//aos/common/util:compiler_memory_barrier',
   ],
 )
diff --git a/aos/common/controls/BUILD b/aos/common/controls/BUILD
index a5f3152..08cbd36 100644
--- a/aos/common/controls/BUILD
+++ b/aos/common/controls/BUILD
@@ -10,7 +10,7 @@
   deps = [
     '//aos/common:queues',
     ':control_loop',
-    '//aos/common/logging:log_replay',
+    '//aos/common/logging:replay',
     '//aos/common/logging:queue_logging',
     '//aos/common:time',
   ],
diff --git a/aos/common/controls/replay_control_loop.h b/aos/common/controls/replay_control_loop.h
index fae3ad8..6921a0e 100644
--- a/aos/common/controls/replay_control_loop.h
+++ b/aos/common/controls/replay_control_loop.h
@@ -5,7 +5,7 @@
 
 #include "aos/common/queue.h"
 #include "aos/common/controls/control_loop.h"
-#include "aos/common/logging/log_replay.h"
+#include "aos/common/logging/replay.h"
 #include "aos/common/logging/queue_logging.h"
 #include "aos/common/time.h"
 #include "aos/common/macros.h"
diff --git a/aos/common/libc/BUILD b/aos/common/libc/BUILD
index 5db9257..e2a87cb 100644
--- a/aos/common/libc/BUILD
+++ b/aos/common/libc/BUILD
@@ -9,7 +9,7 @@
     'aos_strsignal.h',
   ],
   deps = [
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging',
   ],
 )
 
diff --git a/aos/common/logging/BUILD b/aos/common/logging/BUILD
index b3e358d..adddb4b 100644
--- a/aos/common/logging/BUILD
+++ b/aos/common/logging/BUILD
@@ -1,30 +1,54 @@
-package(default_visibility = ['//visibility:public'])
+# The primary client logging interface.
+cc_library(
+  name = 'logging',
+  visibility = ['//visibility:public'],
+  hdrs = [
+    'logging.h',
+    'interface.h',
+    'context.h',
+  ],
+  srcs = [
+    'interface.cc',
+    'context.cc',
+  ],
+  deps = [
+    '//aos/common:die',
+    '//aos/common/libc:aos_strerror',
+    '//aos/common:macros',
+    '//aos/linux_code:complex_thread_local',
+    ':sizes',
+  ],
+)
 
 cc_library(
-  name = 'log_replay',
+  name = 'replay',
+  visibility = ['//visibility:public'],
   srcs = [
-    'log_replay.cc',
+    'replay.cc',
   ],
   hdrs = [
-    'log_replay.h',
+    'replay.h',
   ],
   deps = [
     ':binary_log_file',
     '//aos/common:queues',
-    '//aos/common/logging',
+    ':logging',
     '//aos/linux_code/ipc_lib:queue',
   ],
 )
 
 cc_binary(
   name = 'binary_log_writer',
+  visibility = ['//visibility:public'],
   srcs = [
     'binary_log_writer.cc',
   ],
   deps = [
-    '//aos/common/logging',
+    ':logging',
+    ':implementations',
     '//aos/linux_code:init',
     '//aos/linux_code:configuration',
+    '//aos/linux_code/ipc_lib:queue',
     '//aos/common:die',
     ':binary_log_file',
     '//aos/common:queue_types',
@@ -33,11 +57,13 @@
 
 cc_binary(
   name = 'log_streamer',
+  visibility = ['//visibility:public'],
   srcs = [
     'log_streamer.cc',
   ],
   deps = [
-    '//aos/common/logging',
+    ':logging',
+    ':implementations',
     '//aos/linux_code:init',
     '//aos/common:time',
     '//aos/linux_code/ipc_lib:queue',
@@ -46,11 +72,13 @@
 
 cc_binary(
   name = 'log_displayer',
+  visibility = ['//visibility:public'],
   srcs = [
     'log_displayer.cc',
   ],
   deps = [
-    '//aos/common/logging',
+    ':logging',
+    ':implementations',
     '//aos/linux_code:init',
     ':binary_log_file',
     '//aos/common:queue_types',
@@ -68,65 +96,7 @@
     'binary_log_file.h',
   ],
   deps = [
-    '//aos/common/logging',
-  ],
-)
-
-cc_library(
-  name = 'linux_interface',
-  visibility = ['//aos/common/logging:__pkg__'],
-  srcs = [
-    'linux_interface.cc',
-  ],
-  deps = [
-    '//aos/linux_code:complex_thread_local',
-    '//aos/common:die',
-    '//aos/common/logging:context',
-  ],
-)
-
-cc_library(
-  name = 'linux_logging',
-  visibility = [
-    '//aos/linux_code:__subpackages__'
-  ],
-  hdrs = [
-    'linux_logging.h',
-  ],
-  srcs = [
-    'linux_logging.cc',
-  ],
-  deps = [
-    '//aos/linux_code/ipc_lib:queue',
-    '//aos/common:time',
-    '//aos/common/logging:logging',
-  ],
-)
-
-cc_test(
-  name = 'logging_impl_test',
-  srcs = [
-    'logging_impl_test.cc',
-  ],
-  deps = [
-    '//aos/testing:googletest',
-    '//aos/common/logging',
-  ],
-)
-
-cc_library(
-  name = 'queue_logging',
-  srcs = [
-    'queue_logging.cc',
-    'queue_logging-tmpl.h',
-  ],
-  hdrs = [
-    'queue_logging.h',
-  ],
-  deps = [
-    '//aos/common/logging',
-    '//aos/common:die',
-    '//aos/common:queue_types',
+    ':implementations',
   ],
 )
 
@@ -137,18 +107,48 @@
   ],
 )
 
+cc_test(
+  name = 'implementations_test',
+  srcs = [
+    'implementations_test.cc',
+  ],
+  deps = [
+    '//aos/testing:googletest',
+    ':logging',
+    ':implementations',
+  ],
+)
+
+cc_library(
+  name = 'queue_logging',
+  visibility = ['//visibility:public'],
+  srcs = [
+    'queue_logging.cc',
+  ],
+  hdrs = [
+    'queue_logging.h',
+  ],
+  deps = [
+    ':logging',
+    ':sizes',
+    '//aos/common:die',
+    '//aos/common:queue_types',
+  ],
+)
+
 cc_library(
   name = 'matrix_logging',
+  visibility = ['//visibility:public'],
   srcs = [
     'matrix_logging.cc',
-    'matrix_logging-tmpl.h',
   ],
   hdrs = [
     'matrix_logging.h',
   ],
   deps = [
     '//aos/common:generated_queue_headers',
-    '//aos/common/logging',
+    ':logging',
+    ':sizes',
     '//aos/common:die',
     '//aos/common:queue_types',
     '//third_party/eigen',
@@ -156,9 +156,10 @@
 )
 
 cc_library(
-  name = 'logging_printf_formats',
+  name = 'printf_formats',
+  visibility = ['//visibility:public'],
   hdrs = [
-    'logging_printf_formats.h',
+    'printf_formats.h',
   ],
   deps = [
     '//aos/common:macros',
@@ -166,46 +167,24 @@
 )
 
 cc_library(
-  name = 'logging_interface',
-  hdrs = [
-    'logging.h',
-    'logging_interface.h',
-  ],
+  name = 'implementations',
+  visibility = ['//visibility:public'],
   srcs = [
-    'logging_interface.cc',
+    'implementations.cc',
+  ],
+  hdrs = [
+    'implementations.h',
   ],
   deps = [
     '//aos/common:die',
-    '//aos/common/libc:aos_strerror',
-    '//aos/common/logging:linux_interface',
-    '//aos/common:macros',
-  ],
-)
-
-cc_library(
-  name = 'context',
-  hdrs = [
-    'context.h',
-  ],
-  srcs = [
-    'context.cc',
-  ],
-  deps = [
-    ':sizes',
-  ],
-)
-
-cc_library(
-  name = 'logging',
-  srcs = [
-    'logging_impl.cc',
-  ],
-  hdrs = [
-    'logging_impl.h',
-  ],
-  deps = [
     '//aos/common:time',
     '//aos/common:once',
     '//aos/common:queue_types',
+    ':logging',
+    '//aos/common:type_traits',
+    '//aos/common:mutex',
+    '//aos/common:macros',
+    ':sizes',
+    '//aos/linux_code/ipc_lib:queue',
   ],
 )
diff --git a/aos/common/logging/binary_log_file.h b/aos/common/logging/binary_log_file.h
index b753699..7f9506e 100644
--- a/aos/common/logging/binary_log_file.h
+++ b/aos/common/logging/binary_log_file.h
@@ -7,7 +7,7 @@
 
 #include <algorithm>
 
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/implementations.h"
 
 namespace aos {
 namespace logging {
diff --git a/aos/common/logging/binary_log_writer.cc b/aos/common/logging/binary_log_writer.cc
index d4e6685..56949b5 100644
--- a/aos/common/logging/binary_log_writer.cc
+++ b/aos/common/logging/binary_log_writer.cc
@@ -14,10 +14,11 @@
 #include <map>
 #include <unordered_set>
 
-#include "aos/common/logging/linux_logging.h"
+#include "aos/common/logging/implementations.h"
 #include "aos/common/logging/binary_log_file.h"
 #include "aos/linux_code/init.h"
 #include "aos/linux_code/configuration.h"
+#include "aos/linux_code/ipc_lib/queue.h"
 #include "aos/common/queue_types.h"
 #include "aos/common/die.h"
 
@@ -198,11 +199,14 @@
   }
   LogFileWriter writer(fd);
 
+  RawQueue *queue = GetLoggingQueue();
+
   ::std::unordered_set<uint32_t> written_type_ids;
   off_t clear_type_ids_cookie = 0;
 
   while (true) {
-    const LogMessage *const msg = ReadNext();
+    const LogMessage *const msg =
+        static_cast<const LogMessage *>(queue->ReadMessage(RawQueue::kBlock));
     if (msg == NULL) continue;
 
     const size_t raw_output_length =
@@ -294,7 +298,7 @@
 
     futex_set(&output->marker);
 
-    logging::linux_code::Free(msg);
+    queue->FreeMessage(msg);
   }
 
   Cleanup();
diff --git a/aos/common/logging/context.cc b/aos/common/logging/context.cc
index 8874edb..aebee02 100644
--- a/aos/common/logging/context.cc
+++ b/aos/common/logging/context.cc
@@ -1,10 +1,59 @@
 #include "aos/common/logging/context.h"
 
 #include <string.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "aos/common/die.h"
+#include "aos/linux_code/complex_thread_local.h"
 
 namespace aos {
 namespace logging {
 namespace internal {
+namespace {
+
+// TODO(brians): Differentiate between threads with the same name in the same
+// process.
+
+::std::string GetMyName() {
+  // The maximum number of characters that can make up a thread name.
+  // The docs are unclear if it can be 16 characters with no '\0', so we'll be
+  // safe by adding our own where necessary.
+  static const size_t kThreadNameLength = 16;
+
+  ::std::string process_name(program_invocation_short_name);
+
+  char thread_name_array[kThreadNameLength + 1];
+  if (prctl(PR_GET_NAME, thread_name_array) != 0) {
+    PDie("prctl(PR_GET_NAME, %p) failed", thread_name_array);
+  }
+  thread_name_array[sizeof(thread_name_array) - 1] = '\0';
+  ::std::string thread_name(thread_name_array);
+
+  // If the first bunch of characters are the same.
+  // We cut off comparing at the shorter of the 2 strings because one or the
+  // other often ends up cut off.
+  if (strncmp(thread_name.c_str(), process_name.c_str(),
+              ::std::min(thread_name.length(), process_name.length())) == 0) {
+    // This thread doesn't have an actual name.
+    return process_name;
+  }
+
+  return process_name + '.' + thread_name;
+}
+
+::aos::ComplexThreadLocal<Context> my_context;
+
+// True if we're going to delete the current Context object ASAP. The
+// reason for doing this instead of just deleting them is that tsan (at least)
+// doesn't like it when pthread_atfork handlers do complicated stuff and it's
+// not a great idea anyways.
+thread_local bool delete_current_context(false);
+
+}  // namespace
 
 ::std::atomic<LogImplementation *> global_top_implementation(NULL);
 
@@ -14,6 +63,36 @@
   cork_data.Reset();
 }
 
+// Used in aos/linux_code/init.cc when a thread's name is changed.
+void ReloadThreadName() {
+  if (my_context.created()) {
+    ::std::string my_name = GetMyName();
+    if (my_name.size() + 1 > sizeof(Context::name)) {
+      Die("logging: process/thread name '%s' is too long\n",
+          my_name.c_str());
+    }
+    strcpy(my_context->name, my_name.c_str());
+    my_context->name_size = my_name.size();
+  }
+}
+
+Context *Context::Get() {
+  if (__builtin_expect(delete_current_context, false)) {
+    my_context.Clear();
+    delete_current_context = false;
+  }
+  if (__builtin_expect(!my_context.created(), false)) {
+    my_context.Create();
+    ReloadThreadName();
+    my_context->source = getpid();
+  }
+  return my_context.get();
+}
+
+void Context::Delete() {
+  delete_current_context = true;
+}
+
 }  // namespace internal
 }  // namespace logging
 }  // namespace aos
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/implementations.cc
similarity index 73%
rename from aos/common/logging/logging_impl.cc
rename to aos/common/logging/implementations.cc
index 34c3816..2f17f7a 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/implementations.cc
@@ -1,35 +1,36 @@
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/implementations.h"
 
 #include <stdarg.h>
 #include <inttypes.h>
 
+#include <algorithm>
+
+#include "aos/common/die.h"
 #include "aos/common/once.h"
 #include "aos/common/time.h"
 #include "aos/common/queue_types.h"
-#include "aos/common/logging/logging_printf_formats.h"
+#include "aos/common/logging/printf_formats.h"
+#include "aos/linux_code/ipc_lib/queue.h"
 
 namespace aos {
 namespace logging {
 namespace {
 
-using internal::Context;
-using internal::global_top_implementation;
-
 // The root LogImplementation. It only logs to stderr/stdout.
 // Some of the things specified in the LogImplementation documentation doesn't
 // apply here (mostly the parts about being able to use LOG) because this is the
 // root one.
-class RootLogImplementation : public LogImplementation {
+class RootLogImplementation : public SimpleLogImplementation {
  public:
   void have_other_implementation() { only_implementation_ = false; }
 
  private:
-  virtual void set_next(LogImplementation *) {
+  void set_next(LogImplementation *) override {
     LOG(FATAL, "can't have a next logger from here\n");
   }
 
   __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
-  virtual void DoLog(log_level level, const char *format, va_list ap) {
+  void DoLog(log_level level, const char *format, va_list ap) override {
     LogMessage message;
     internal::FillInMessage(level, format, ap, &message);
     internal::PrintMessage(stderr, message);
@@ -49,14 +50,14 @@
     abort();
   }
 
-  Context *context = Context::Get();
+  internal::Context *context = internal::Context::Get();
 
   context->implementation = implementation;
-  global_top_implementation.store(implementation);
+  internal::global_top_implementation.store(implementation);
 }
 
 void NewContext() {
-  Context::Delete();
+  internal::Context::Delete();
 }
 
 void *DoInit() {
@@ -215,7 +216,7 @@
 
 }  // namespace internal
 
-void LogImplementation::LogStruct(
+void SimpleLogImplementation::LogStruct(
     log_level level, const ::std::string &message, size_t size,
     const MessageType *type, const ::std::function<size_t(char *)> &serialize) {
   char serialized[1024];
@@ -236,7 +237,7 @@
                 static_cast<int>(sizeof(printed) - printed_bytes), printed);
 }
 
-void LogImplementation::LogMatrix(
+void SimpleLogImplementation::LogMatrix(
     log_level level, const ::std::string &message, uint32_t type_id,
     int rows, int cols, const void *data) {
   char serialized[1024];
@@ -290,15 +291,8 @@
   internal::PrintMessage(stream_, message);
 }
 
-void LogNext(log_level level, const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  LogImplementation::DoVLog(level, format, ap, 2);
-  va_end(ap);
-}
-
 void AddImplementation(LogImplementation *implementation) {
-  Context *context = Context::Get();
+  internal::Context *context = internal::Context::Get();
 
   if (implementation->next() != NULL) {
     LOG(FATAL, "%p already has a next implementation, but it's not"
@@ -319,11 +313,109 @@
 }
 
 void Load() {
-  Context::Get();
+  internal::Context::Get();
 }
 
 void Cleanup() {
-  Context::Delete();
+  internal::Context::Delete();
+}
+
+namespace {
+
+RawQueue *queue = NULL;
+
+int dropped_messages = 0;
+::aos::time::Time dropped_start, backoff_start;
+// Wait this long after dropping a message before even trying to write any more.
+constexpr ::aos::time::Time kDropBackoff = ::aos::time::Time::InSeconds(0.1);
+
+LogMessage *GetMessageOrDie() {
+  LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
+  if (message == NULL) {
+    LOG(FATAL, "%p->GetMessage() failed\n", queue);
+  } else {
+    return message;
+  }
+}
+
+void Write(LogMessage *msg) {
+  if (__builtin_expect(dropped_messages > 0, false)) {
+    ::aos::time::Time message_time =
+        ::aos::time::Time(msg->seconds, msg->nseconds);
+    if (message_time - backoff_start < kDropBackoff) {
+      ++dropped_messages;
+      queue->FreeMessage(msg);
+      return;
+    }
+
+    LogMessage *dropped_message = GetMessageOrDie();
+    internal::FillInMessageVarargs(
+        ERROR, dropped_message,
+        "%d logs starting at %" PRId32 ".%" PRId32 " dropped\n",
+        dropped_messages, dropped_start.sec(), dropped_start.nsec());
+    if (queue->WriteMessage(dropped_message, RawQueue::kNonBlock)) {
+      dropped_messages = 0;
+    } else {
+      // Don't even bother trying to write this message because it's not likely
+      // to work and it would be confusing to have one log in the middle of a
+      // string of failures get through.
+      ++dropped_messages;
+      backoff_start = message_time;
+      queue->FreeMessage(msg);
+      return;
+    }
+  }
+  if (!queue->WriteMessage(msg, RawQueue::kNonBlock)) {
+    if (dropped_messages == 0) {
+      dropped_start = backoff_start =
+          ::aos::time::Time(msg->seconds, msg->nseconds);
+    }
+    ++dropped_messages;
+  }
+}
+
+class LinuxQueueLogImplementation : public LogImplementation {
+  __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, format, ap, message);
+    Write(message);
+  }
+
+  void LogStruct(log_level level, const ::std::string &message_string,
+                 size_t size, const MessageType *type,
+                 const ::std::function<size_t(char *)> &serialize) override {
+    LogMessage *message = GetMessageOrDie();
+    internal::FillInMessageStructure(level, message_string, size, type,
+                                     serialize, message);
+    Write(message);
+  }
+
+  void LogMatrix(log_level level, const ::std::string &message_string,
+                 uint32_t type_id, int rows, int cols,
+                 const void *data) override {
+    LogMessage *message = GetMessageOrDie();
+    internal::FillInMessageMatrix(level, message_string, type_id, rows, cols,
+                                  data, message);
+    Write(message);
+  }
+};
+
+}  // namespace
+
+RawQueue *GetLoggingQueue() {
+  return RawQueue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 40000);
+}
+
+void RegisterQueueImplementation() {
+  Init();
+
+  queue = GetLoggingQueue();
+  if (queue == NULL) {
+    Die("logging: couldn't fetch queue\n");
+  }
+
+  AddImplementation(new LinuxQueueLogImplementation());
 }
 
 }  // namespace logging
diff --git a/aos/common/logging/logging_impl.h b/aos/common/logging/implementations.h
similarity index 75%
rename from aos/common/logging/logging_impl.h
rename to aos/common/logging/implementations.h
index 5fdeec7..48b5f0b 100644
--- a/aos/common/logging/logging_impl.h
+++ b/aos/common/logging/implementations.h
@@ -1,5 +1,5 @@
-#ifndef AOS_COMMON_LOGGING_LOGGING_IMPL_H_
-#define AOS_COMMON_LOGGING_LOGGING_IMPL_H_
+#ifndef AOS_COMMON_LOGGING_IMPLEMENTATIONS_H_
+#define AOS_COMMON_LOGGING_IMPLEMENTATIONS_H_
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -18,25 +18,18 @@
 #include "aos/common/mutex.h"
 #include "aos/common/macros.h"
 #include "aos/common/logging/sizes.h"
-#include "aos/common/logging/logging_interface.h"
+#include "aos/common/logging/interface.h"
 #include "aos/common/logging/context.h"
 #include "aos/common/once.h"
 
 namespace aos {
 
 struct MessageType;
+class RawQueue;
 
 }  // namespace aos
 
-// This file has all of the logging implementation. It can't be #included by C
-// code like logging.h can.
-// It is useful for the rest of the logging implementation and other C++ code
-// that needs to do special things with logging.
-//
-// It is implemented in logging_impl.cc and logging_interface.cc. They are
-// separate so that code used by logging_impl.cc can link in
-// logging_interface.cc to use logging without creating a circular dependency.
-// However, any executables with such code still need logging_impl.cc linked in.
+// This file has various concrete LogImplementations.
 
 namespace aos {
 namespace logging {
@@ -44,9 +37,9 @@
 // Unless explicitly stated otherwise, format must always be a string constant,
 // args are printf-style arguments for format, and ap is a va_list of args.
 // The validity of format and args together will be checked at compile time
-// using a gcc function attribute.
+// using a function attribute.
 
-// The struct that the code uses for making logging calls.
+// Contains all of the information about a given logging call.
 struct LogMessage {
   enum class Type : uint8_t {
     kString, kStruct, kMatrix
@@ -106,31 +99,30 @@
   return LOG_UNKNOWN;
 }
 
-// Will call VLog with the given arguments for the next logger in the chain.
-void LogNext(log_level level, const char *format, ...)
-  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 3)));
-
-// Takes a structure and log it.
-template <class T>
-void DoLogStruct(log_level, const ::std::string &, const T &);
-// Takes a matrix and logs it.
-template <class T>
-void DoLogMatrix(log_level, const ::std::string &, const T &);
-
+// A LogImplementation where LogStruct and LogMatrix just create a string with
+// PrintMessage and then forward on to DoLog.
+class SimpleLogImplementation : public LogImplementation {
+ private:
+  void LogStruct(log_level level, const ::std::string &message, size_t size,
+                 const MessageType *type,
+                 const ::std::function<size_t(char *)> &serialize) override;
+  void LogMatrix(log_level level, const ::std::string &message,
+                 uint32_t type_id, int rows, int cols,
+                 const void *data) override;
+};
 
 // Implements all of the DoLog* methods in terms of a (pure virtual in this
 // class) HandleMessage method that takes a pointer to the message.
 class HandleMessageLogImplementation : public LogImplementation {
- public:
+ private:
   __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
-  virtual void DoLog(log_level level, const char *format, va_list ap) override;
-  virtual void LogStruct(log_level level, const ::std::string &message_string,
-                         size_t size, const MessageType *type,
-                         const ::std::function<size_t(char *)> &serialize)
-      override;
-  virtual void LogMatrix(log_level level, const ::std::string &message_string,
-                         uint32_t type_id, int rows, int cols, const void *data)
-      override;
+  void DoLog(log_level level, const char *format, va_list ap) override;
+  void LogStruct(log_level level, const ::std::string &message_string,
+                 size_t size, const MessageType *type,
+                 const ::std::function<size_t(char *)> &serialize) override;
+  void LogMatrix(log_level level, const ::std::string &message_string,
+                 uint32_t type_id, int rows, int cols,
+                 const void *data) override;
 
   virtual void HandleMessage(const LogMessage &message) = 0;
 };
@@ -141,7 +133,7 @@
   StreamLogImplementation(FILE *stream);
 
  private:
-  virtual void HandleMessage(const LogMessage &message) override;
+  void HandleMessage(const LogMessage &message) override;
 
   FILE *const stream_;
 };
@@ -163,11 +155,22 @@
 // Forces all of the state that is usually lazily created when first needed to
 // be created when called. Cleanup() will delete it.
 void Load();
+
 // Resets all information in this task/thread to its initial state.
 // NOTE: This is not the opposite of Init(). The state that this deletes is
 // lazily created when needed. It is actually the opposite of Load().
 void Cleanup();
 
+// Returns a queue which deals with LogMessage-sized messages.
+// The caller takes ownership.
+RawQueue *GetLoggingQueue();
+
+// Calls AddImplementation to register the standard linux logging implementation
+// which sends the messages through a queue. This implementation relies on
+// another process(es) to read the log messages that it puts into the queue.
+// This function is usually called by aos::Init*.
+void RegisterQueueImplementation();
+
 // This is where all of the code that is only used by actual LogImplementations
 // goes.
 namespace internal {
@@ -209,4 +212,4 @@
 }  // namespace logging
 }  // namespace aos
 
-#endif  // AOS_COMMON_LOGGING_LOGGING_IMPL_H_
+#endif  // AOS_COMMON_LOGGING_IMPLEMENTATIONS_H_
diff --git a/aos/common/logging/logging_impl_test.cc b/aos/common/logging/implementations_test.cc
similarity index 95%
rename from aos/common/logging/logging_impl_test.cc
rename to aos/common/logging/implementations_test.cc
index dec962b..bbee5b7 100644
--- a/aos/common/logging/logging_impl_test.cc
+++ b/aos/common/logging/implementations_test.cc
@@ -4,9 +4,9 @@
 
 #include "gtest/gtest.h"
 
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/implementations.h"
 #include "aos/common/time.h"
-#include "aos/common/logging/logging_printf_formats.h"
+#include "aos/common/logging/printf_formats.h"
 
 using ::testing::AssertionResult;
 using ::testing::AssertionSuccess;
@@ -16,9 +16,9 @@
 namespace logging {
 namespace testing {
 
-class TestLogImplementation : public LogImplementation {
+class TestLogImplementation : public SimpleLogImplementation {
   __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
-  virtual void DoLog(log_level level, const char *format, va_list ap) {
+  void DoLog(log_level level, const char *format, va_list ap) override {
     internal::FillInMessage(level, format, ap, &message_);
 
     if (level == FATAL) {
@@ -83,7 +83,7 @@
   }
 
  private:
-  virtual void SetUp() {
+  void SetUp() override {
     static bool first = true;
     if (first) {
       first = false;
@@ -94,7 +94,7 @@
 
     log_implementation->reset_used();
   }
-  virtual void TearDown() {
+  void TearDown() override {
     Cleanup();
   }
 
@@ -128,7 +128,7 @@
   static const int end_line = __LINE__;
   LOG_UNCORK(WARNING, "last part %d\n", 5);
   std::stringstream expected;
-  expected << "logging_impl_test.cc: ";
+  expected << "implementations_test.cc: ";
   expected << (begin_line + 1);
   expected << "-";
   expected << (end_line + 1);
diff --git a/aos/common/logging/logging_interface.cc b/aos/common/logging/interface.cc
similarity index 95%
rename from aos/common/logging/logging_interface.cc
rename to aos/common/logging/interface.cc
index 0a6c968..72431e8 100644
--- a/aos/common/logging/logging_interface.cc
+++ b/aos/common/logging/interface.cc
@@ -1,4 +1,4 @@
-#include "aos/common/logging/logging_interface.h"
+#include "aos/common/logging/interface.h"
 
 #include <stdarg.h>
 #include <stdio.h>
@@ -10,9 +10,6 @@
 #include "aos/common/die.h"
 #include "aos/common/logging/context.h"
 
-// This file only contains the code necessary to link (ie no implementations).
-// See logging_impl.h for why this is necessary.
-
 namespace aos {
 namespace logging {
 namespace internal {
diff --git a/aos/common/logging/logging_interface.h b/aos/common/logging/interface.h
similarity index 74%
rename from aos/common/logging/logging_interface.h
rename to aos/common/logging/interface.h
index 97587bf..dc59858 100644
--- a/aos/common/logging/logging_interface.h
+++ b/aos/common/logging/interface.h
@@ -1,5 +1,5 @@
-#ifndef AOS_COMMON_LOGGING_LOGGING_INTERFACE_H_
-#define AOS_COMMON_LOGGING_LOGGING_INTERFACE_H_
+#ifndef AOS_COMMON_LOGGING_INTERFACE_H_
+#define AOS_COMMON_LOGGING_INTERFACE_H_
 
 #include <stdarg.h>
 
@@ -9,14 +9,26 @@
 #include "aos/common/logging/logging.h"
 #include "aos/common/macros.h"
 
+// This file has the non-C-compatible parts of the logging client interface.
+
 namespace aos {
 
 struct MessageType;
 
-}  // namespace aos
-
-namespace aos {
 namespace logging {
+namespace internal {
+
+// Defined in queue_logging.cc.
+void DoLogStruct(log_level level, const ::std::string &message, size_t size,
+                 const MessageType *type,
+                 const ::std::function<size_t(char *)> &serialize, int levels);
+
+// Defined in matrix_logging.cc.
+void DoLogMatrix(log_level level, const ::std::string &message,
+                 uint32_t type_id, int rows, int cols, const void *data,
+                 int levels);
+
+}  // namespace internal
 
 // Takes a message and logs it. It will set everything up and then call DoLog
 // for the current LogImplementation.
@@ -48,7 +60,7 @@
   // logger other than this one available while this is called.
   virtual void set_next(LogImplementation *next) { next_ = next; }
 
- private:
+ protected:
   // Actually logs the given message. Implementations should somehow create a
   // LogMessage and then call internal::FillInMessage.
   __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
@@ -61,44 +73,36 @@
     va_end(ap);
   }
 
-  // Logs the contents of an auto-generated structure. The implementation here
-  // just converts it to a string with PrintMessage and then calls DoLog with
-  // that, however some implementations can be a lot more efficient than that.
+  // Logs the contents of an auto-generated structure.
   // size and type are the result of calling Size() and Type() on the type of
   // the message.
   // serialize will call Serialize on the message.
   virtual void LogStruct(log_level level, const ::std::string &message,
                          size_t size, const MessageType *type,
-                         const ::std::function<size_t(char *)> &serialize);
+                         const ::std::function<size_t(char *)> &serialize) = 0;
   // Similiar to LogStruct, except for matrixes.
   // type_id is the type of the elements of the matrix.
   // data points to rows*cols*type_id.Size() bytes of data in row-major order.
   virtual void LogMatrix(log_level level, const ::std::string &message,
                          uint32_t type_id, int rows, int cols,
-                         const void *data);
+                         const void *data) = 0;
 
+ private:
   // These functions call similar methods on the "current" LogImplementation or
   // Die if they can't find one.
   // levels is how many LogImplementations to not use off the stack.
   static void DoVLog(log_level, const char *format, va_list ap, int levels)
       __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 2, 0)));
-  // This one is implemented in queue_logging.cc.
-  static void DoLogStruct(log_level level, const ::std::string &message,
-                          size_t size, const MessageType *type,
-                          const ::std::function<size_t(char *)> &serialize,
-                          int levels);
-  // This one is implemented in matrix_logging.cc.
-  static void DoLogMatrix(log_level level, const ::std::string &message,
-                          uint32_t type_id, int rows, int cols,
-                          const void *data, int levels);
 
-  // Friends so that they can access the static Do* functions.
   friend void VLog(log_level, const char *, va_list);
-  friend void LogNext(log_level, const char *, ...);
-  template <class T>
-  friend void DoLogStruct(log_level, const ::std::string &, const T &);
-  template <class T>
-  friend void DoLogMatrix(log_level, const ::std::string &, const T &);
+  friend void internal::DoLogStruct(
+      log_level level, const ::std::string &message, size_t size,
+      const MessageType *type, const ::std::function<size_t(char *)> &serialize,
+      int levels);
+  friend void internal::DoLogMatrix(log_level level,
+                                    const ::std::string &message,
+                                    uint32_t type_id, int rows, int cols,
+                                    const void *data, int levels);
 
   LogImplementation *next_;
 };
@@ -121,4 +125,4 @@
 }  // namespace logging
 }  // namespace aos
 
-#endif  // AOS_COMMON_LOGGING_LOGGING_INTERFACE_H_
+#endif  // AOS_COMMON_LOGGING_INTERFACE_H_
diff --git a/aos/common/logging/linux_interface.cc b/aos/common/logging/linux_interface.cc
deleted file mode 100644
index dff48e1..0000000
--- a/aos/common/logging/linux_interface.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "aos/common/logging/context.h"
-
-#include <string>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "aos/linux_code/complex_thread_local.h"
-#include "aos/common/die.h"
-
-namespace aos {
-namespace logging {
-namespace internal {
-namespace {
-
-// TODO(brians): Differentiate between threads with the same name in the same
-// process.
-
-::std::string GetMyName() {
-  // The maximum number of characters that can make up a thread name.
-  // The docs are unclear if it can be 16 characters with no '\0', so we'll be
-  // safe by adding our own where necessary.
-  static const size_t kThreadNameLength = 16;
-
-  ::std::string process_name(program_invocation_short_name);
-
-  char thread_name_array[kThreadNameLength + 1];
-  if (prctl(PR_GET_NAME, thread_name_array) != 0) {
-    PDie("prctl(PR_GET_NAME, %p) failed", thread_name_array);
-  }
-  thread_name_array[sizeof(thread_name_array) - 1] = '\0';
-  ::std::string thread_name(thread_name_array);
-
-  // If the first bunch of characters are the same.
-  // We cut off comparing at the shorter of the 2 strings because one or the
-  // other often ends up cut off.
-  if (strncmp(thread_name.c_str(), process_name.c_str(),
-              ::std::min(thread_name.length(), process_name.length())) == 0) {
-    // This thread doesn't have an actual name.
-    return process_name;
-  }
-
-  return process_name + '.' + thread_name;
-}
-
-::aos::ComplexThreadLocal<Context> my_context;
-
-// True if we're going to delete the current Context object ASAP. The
-// reason for doing this instead of just deleting them is that tsan (at least)
-// doesn't like it when pthread_atfork handlers do complicated stuff and it's
-// not a great idea anyways.
-thread_local bool delete_current_context(false);
-
-}  // namespace
-
-// Used in aos/linux_code/init.cc when a thread's name is changed.
-void ReloadThreadName() {
-  if (my_context.created()) {
-    ::std::string my_name = GetMyName();
-    if (my_name.size() + 1 > sizeof(Context::name)) {
-      Die("logging: process/thread name '%s' is too long\n",
-          my_name.c_str());
-    }
-    strcpy(my_context->name, my_name.c_str());
-    my_context->name_size = my_name.size();
-  }
-}
-
-Context *Context::Get() {
-  if (__builtin_expect(delete_current_context, false)) {
-    my_context.Clear();
-    delete_current_context = false;
-  }
-  if (__builtin_expect(!my_context.created(), false)) {
-    my_context.Create();
-    ReloadThreadName();
-    my_context->source = getpid();
-  }
-  return my_context.get();
-}
-
-void Context::Delete() {
-  delete_current_context = true;
-}
-
-}  // namespace internal
-}  // namespace logging
-}  // namespace aos
diff --git a/aos/common/logging/linux_logging.cc b/aos/common/logging/linux_logging.cc
deleted file mode 100644
index 14ce72b..0000000
--- a/aos/common/logging/linux_logging.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-#include "aos/common/logging/linux_logging.h"
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <inttypes.h>
-
-#include <algorithm>
-
-#include "aos/common/die.h"
-#include "aos/common/logging/logging_interface.h"
-#include "aos/linux_code/ipc_lib/queue.h"
-#include "aos/common/time.h"
-
-namespace aos {
-namespace logging {
-namespace linux_code {
-namespace {
-
-RawQueue *queue = NULL;
-
-int dropped_messages = 0;
-::aos::time::Time dropped_start, backoff_start;
-// Wait this long after dropping a message before even trying to write any more.
-constexpr ::aos::time::Time kDropBackoff = ::aos::time::Time::InSeconds(0.1);
-
-LogMessage *GetMessageOrDie() {
-  LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
-  if (message == NULL) {
-    LOG(FATAL, "%p->GetMessage() failed\n", queue);
-  } else {
-    return message;
-  }
-}
-
-class LinuxQueueLogImplementation : public LogImplementation {
-  __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
-  virtual void DoLog(log_level level, const char *format, va_list ap) override {
-    LogMessage *message = GetMessageOrDie();
-    internal::FillInMessage(level, format, ap, message);
-    Write(message);
-  }
-
-  virtual void LogStruct(log_level level, const ::std::string &message_string,
-                         size_t size, const MessageType *type,
-                         const ::std::function<size_t(char *)> &serialize)
-      override {
-    LogMessage *message = GetMessageOrDie();
-    internal::FillInMessageStructure(level, message_string, size, type,
-                                     serialize, message);
-    Write(message);
-  }
-
-  virtual void LogMatrix(log_level level, const ::std::string &message_string,
-                         uint32_t type_id, int rows, int cols, const void *data)
-      override {
-    LogMessage *message = GetMessageOrDie();
-    internal::FillInMessageMatrix(level, message_string, type_id, rows, cols,
-                                  data, message);
-    Write(message);
-  }
-};
-
-}  // namespace
-
-void Register() {
-  Init();
-
-  queue = RawQueue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 40000);
-  if (queue == NULL) {
-    Die("logging: couldn't fetch queue\n");
-  }
-
-  AddImplementation(new LinuxQueueLogImplementation());
-}
-
-const LogMessage *ReadNext(Options<RawQueue> flags, int *index) {
-  return static_cast<const LogMessage *>(queue->ReadMessageIndex(flags, index));
-}
-
-const LogMessage *ReadNext() {
-  return ReadNext(RawQueue::kBlock);
-}
-
-const LogMessage *ReadNext(Options<RawQueue> flags) {
-  const LogMessage *r = NULL;
-  do {
-    r = static_cast<const LogMessage *>(queue->ReadMessage(flags));
-    // not blocking means return a NULL if that's what it gets
-  } while ((flags & RawQueue::kBlock) && r == NULL);
-  return r;
-}
-
-LogMessage *Get() {
-  return static_cast<LogMessage *>(queue->GetMessage());
-}
-
-void Free(const LogMessage *msg) {
-  queue->FreeMessage(msg);
-}
-
-void Write(LogMessage *msg) {
-  if (__builtin_expect(dropped_messages > 0, false)) {
-    ::aos::time::Time message_time =
-        ::aos::time::Time(msg->seconds, msg->nseconds);
-    if (message_time - backoff_start < kDropBackoff) {
-      ++dropped_messages;
-      queue->FreeMessage(msg);
-      return;
-    }
-
-    LogMessage *dropped_message = GetMessageOrDie();
-    internal::FillInMessageVarargs(
-        ERROR, dropped_message,
-        "%d logs starting at %" PRId32 ".%" PRId32 " dropped\n",
-        dropped_messages, dropped_start.sec(), dropped_start.nsec());
-    if (queue->WriteMessage(dropped_message, RawQueue::kNonBlock)) {
-      dropped_messages = 0;
-    } else {
-      // Don't even bother trying to write this message because it's not likely
-      // to work and it would be confusing to have one log in the middle of a
-      // string of failures get through.
-      ++dropped_messages;
-      backoff_start = message_time;
-      queue->FreeMessage(msg);
-      return;
-    }
-  }
-  if (!queue->WriteMessage(msg, RawQueue::kNonBlock)) {
-    if (dropped_messages == 0) {
-      dropped_start = backoff_start =
-          ::aos::time::Time(msg->seconds, msg->nseconds);
-    }
-    ++dropped_messages;
-  }
-}
-
-}  // namespace linux_code
-}  // namespace logging
-}  // namespace aos
diff --git a/aos/common/logging/linux_logging.h b/aos/common/logging/linux_logging.h
deleted file mode 100644
index 3f74fa8..0000000
--- a/aos/common/logging/linux_logging.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef AOS_COMMON_LOGGING_LINUX_LOGGING_H_
-#define AOS_COMMON_LOGGING_LINUX_LOGGING_H_
-
-#include "aos/common/logging/logging_impl.h"
-#include "aos/common/util/options.h"
-
-namespace aos {
-
-class RawQueue;
-
-namespace logging {
-namespace linux_code {
-
-// Calls AddImplementation to register the usual linux logging implementation
-// which sends the messages through a queue. This implementation relies on
-// another process(es) to read the log messages that it puts into the queue.
-// This function is usually called by aos::Init*.
-void Register();
-
-// Fairly simple wrappers around the raw queue calls.
-
-// This one never returns NULL if flags contains BLOCK.
-const LogMessage *ReadNext(Options<RawQueue> flags);
-const LogMessage *ReadNext(Options<RawQueue> flags, int *index);
-const LogMessage *ReadNext();
-LogMessage *Get();
-void Free(const LogMessage *msg);
-void Write(LogMessage *msg);
-
-}  // namespace linux_code
-}  // namespace logging
-}  // namespace aos
-
-#endif  // AOS_COMMON_LOGGING_LINUX_LOGGING_H_
diff --git a/aos/common/logging/log_displayer.cc b/aos/common/logging/log_displayer.cc
index 70d2ad5..fba48c4 100644
--- a/aos/common/logging/log_displayer.cc
+++ b/aos/common/logging/log_displayer.cc
@@ -14,8 +14,9 @@
 #include "aos/linux_code/configuration.h"
 #include "aos/common/logging/binary_log_file.h"
 #include "aos/common/queue_types.h"
-#include "aos/common/logging/logging_impl.h"
-#include "aos/common/logging/logging_printf_formats.h"
+#include "aos/common/logging/logging.h"
+#include "aos/common/logging/implementations.h"
+#include "aos/common/logging/printf_formats.h"
 #include "aos/common/util/string_to_num.h"
 
 using ::aos::logging::linux_code::LogFileMessageHeader;
diff --git a/aos/common/logging/log_streamer.cc b/aos/common/logging/log_streamer.cc
index 506a92b..f214d99 100644
--- a/aos/common/logging/log_streamer.cc
+++ b/aos/common/logging/log_streamer.cc
@@ -10,10 +10,10 @@
 #include <fcntl.h>
 #include <inttypes.h>
 
-#include "aos/common/logging/linux_logging.h"
 #include "aos/linux_code/init.h"
 #include "aos/linux_code/ipc_lib/queue.h"
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/logging.h"
+#include "aos/common/logging/implementations.h"
 #include "aos/common/time.h"
 
 namespace aos {
@@ -24,17 +24,20 @@
 int LogStreamerMain() {
   InitNRT();
 
+  RawQueue *queue = GetLoggingQueue();
+
   const time::Time now = time::Time::Now();
   printf("starting at %" PRId32 "s%" PRId32 "ns-----------------------------\n",
          now.sec(), now.nsec());
 
   while (true) {
-    const LogMessage *const msg = ReadNext();
+    const LogMessage *const msg =
+        static_cast<const LogMessage *>(queue->ReadMessage(RawQueue::kBlock));
     if (msg == NULL) continue;
 
     internal::PrintMessage(stdout, *msg);
 
-    logging::linux_code::Free(msg);
+    queue->FreeMessage(msg);
   }
 
   Cleanup();
diff --git a/aos/common/logging/matrix_logging-tmpl.h b/aos/common/logging/matrix_logging-tmpl.h
deleted file mode 100644
index 9e458fb..0000000
--- a/aos/common/logging/matrix_logging-tmpl.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "aos/common/logging/logging_impl.h"
-
-#include <functional>
-
-#include "aos/common/queue_primitives.h"
-
-namespace aos {
-namespace logging {
-
-template <class T>
-void DoLogMatrix(log_level level, const ::std::string &message,
-                 const T &matrix) {
-  static_assert(!T::IsRowMajor, "we only handle column-major storage");
-  LogImplementation::DoLogMatrix(level, message, TypeID<typename T::Scalar>::id,
-                                 matrix.rows(), matrix.cols(), matrix.data(),
-                                 1);
-}
-
-}  // namespace logging
-}  // namespace aos
diff --git a/aos/common/logging/matrix_logging.cc b/aos/common/logging/matrix_logging.cc
index 6173074..7c90632 100644
--- a/aos/common/logging/matrix_logging.cc
+++ b/aos/common/logging/matrix_logging.cc
@@ -1,18 +1,21 @@
 #include "aos/common/logging/matrix_logging.h"
 
 #include "aos/common/queue_types.h"
+#include "aos/common/logging/sizes.h"
 
 namespace aos {
 namespace logging {
+namespace internal {
 
-void LogImplementation::DoLogMatrix(log_level level,
-                                    const ::std::string &message,
-                                    uint32_t type_id, int rows, int cols,
-                                    const void *data, int levels) {
-  internal::RunWithCurrentImplementation(
-      levels, [&](LogImplementation * implementation) {
-    implementation->LogMatrix(level, message, type_id, rows, cols, data);
-  });
+void DoLogMatrix(log_level level, const ::std::string &message,
+                 uint32_t type_id, int rows, int cols, const void *data,
+                 int levels) {
+  {
+    auto fn = [&](LogImplementation *implementation) {
+      implementation->LogMatrix(level, message, type_id, rows, cols, data);
+    };
+    RunWithCurrentImplementation(levels, ::std::ref(fn));
+  }
 
   if (level == FATAL) {
     char serialized[1024];
@@ -31,5 +34,6 @@
   }
 }
 
+}  // namespace internal
 }  // namespace logging
 }  // namespace aos
diff --git a/aos/common/logging/matrix_logging.h b/aos/common/logging/matrix_logging.h
index 6efaa06..e763ed5 100644
--- a/aos/common/logging/matrix_logging.h
+++ b/aos/common/logging/matrix_logging.h
@@ -2,35 +2,39 @@
 #define AOS_COMMON_LOGGING_MATRIX_LOGGING_H_
 
 #include <string>
+#include <functional>
 
 #include "Eigen/Dense"
 
-#include "aos/common/logging/logging.h"
+#include "aos/common/logging/interface.h"
 #include "aos/common/die.h"
+#include "aos/common/queue_primitives.h"
 
 namespace aos {
 namespace logging {
 
 // Logs the contents of a matrix and a constant string.
 // matrix must be an instance of an Eigen matrix (or something similar).
-#define LOG_MATRIX(level, message, matrix)                          \
-  do {                                                              \
-    static const ::std::string kAosLoggingMessage(                  \
-        LOG_SOURCENAME ": " STRINGIFY(__LINE__) ": " message);      \
-    ::aos::logging::DoLogMatrix(level, kAosLoggingMessage, matrix); \
-    /* so that GCC knows that it won't return */                    \
-    if (level == FATAL) {                                           \
-      ::aos::Die("DoLogStruct(FATAL) fell through!!!!!\n");         \
-    }                                                               \
+#define LOG_MATRIX(level, message, matrix)                                   \
+  do {                                                                       \
+    static const ::std::string kAosLoggingMessage(                           \
+        LOG_SOURCENAME ": " STRINGIFY(__LINE__) ": " message);               \
+    ::aos::logging::DoLogMatrixTemplated(level, kAosLoggingMessage, matrix); \
+    /* so that GCC knows that it won't return */                             \
+    if (level == FATAL) {                                                    \
+      ::aos::Die("DoLogStruct(FATAL) fell through!!!!!\n");                  \
+    }                                                                        \
   } while (false)
 
 template <class T>
-void DoLogMatrix(log_level level, const ::std::string &message,
-                 const T &matrix);
+void DoLogMatrixTemplated(log_level level, const ::std::string &message,
+                          const T &matrix) {
+  static_assert(!T::IsRowMajor, "we only handle column-major storage");
+  internal::DoLogMatrix(level, message, TypeID<typename T::Scalar>::id,
+                        matrix.rows(), matrix.cols(), matrix.data(), 1);
+}
 
 }  // namespace logging
 }  // namespace aos
 
-#include "aos/common/logging/matrix_logging-tmpl.h"
-
 #endif  // AOS_COMMON_LOGGING_MATRIX_LOGGING_H_
diff --git a/aos/common/logging/logging_printf_formats.h b/aos/common/logging/printf_formats.h
similarity index 86%
rename from aos/common/logging/logging_printf_formats.h
rename to aos/common/logging/printf_formats.h
index 57a83c3..b098865 100644
--- a/aos/common/logging/logging_printf_formats.h
+++ b/aos/common/logging/printf_formats.h
@@ -1,5 +1,5 @@
-#ifndef AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
-#define AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
+#ifndef AOS_COMMON_LOGGING_PRINTF_FORMATS_H_
+#define AOS_COMMON_LOGGING_PRINTF_FORMATS_H_
 
 #include "aos/common/macros.h"
 
@@ -7,7 +7,7 @@
 // times and log messages.
 // They are all split out as macros because there are 2 things that want to
 // print using the same format: log_displayer and PrintMessage in
-// logging_impl.cc.
+// implementations.cc.
 
 #define AOS_TIME_FORMAT \
   "%010" PRId32 ".%0" STRINGIFY(AOS_TIME_NSECONDS_DIGITS) PRId32 "s"
@@ -27,4 +27,4 @@
 #define AOS_TIME_NSECONDS_DIGITS 6
 #define AOS_TIME_NSECONDS_DENOMINATOR 1000
 
-#endif  // AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
+#endif  // AOS_COMMON_LOGGING_PRINTF_FORMATS_H_
diff --git a/aos/common/logging/queue_logging-tmpl.h b/aos/common/logging/queue_logging-tmpl.h
deleted file mode 100644
index b4c3696..0000000
--- a/aos/common/logging/queue_logging-tmpl.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "aos/common/logging/logging_impl.h"
-
-#include <functional>
-
-namespace aos {
-namespace logging {
-
-template <class T>
-void DoLogStruct(log_level level, const ::std::string &message,
-                 const T &structure) {
-  auto fn = [&structure](char *buffer)
-                -> size_t { return structure.Serialize(buffer); };
-
-  LogImplementation::DoLogStruct(level, message, T::Size(), T::GetType(),
-                                 ::std::ref(fn), 1);
-}
-
-}  // namespace logging
-}  // namespace aos
diff --git a/aos/common/logging/queue_logging.cc b/aos/common/logging/queue_logging.cc
index 14559fb..0f1227c 100644
--- a/aos/common/logging/queue_logging.cc
+++ b/aos/common/logging/queue_logging.cc
@@ -1,21 +1,21 @@
 #include "aos/common/logging/queue_logging.h"
 
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/interface.h"
+#include "aos/common/logging/sizes.h"
 #include "aos/common/queue_types.h"
 
 namespace aos {
 namespace logging {
+namespace internal {
 
-void LogImplementation::DoLogStruct(
-    log_level level, const ::std::string &message, size_t size,
-    const MessageType *type, const ::std::function<size_t(char *)> &serialize,
-    int levels) {
-
+void DoLogStruct(log_level level, const ::std::string &message, size_t size,
+                 const MessageType *type,
+                 const ::std::function<size_t(char *)> &serialize, int levels) {
   {
     auto fn = [&](LogImplementation *implementation) {
       implementation->LogStruct(level, message, size, type, serialize);
     };
-    internal::RunWithCurrentImplementation(levels, ::std::ref(fn));
+    RunWithCurrentImplementation(levels, ::std::ref(fn));
   }
 
   if (level == FATAL) {
@@ -34,5 +34,6 @@
   }
 }
 
+}  // namespace internal
 }  // namespace logging
 }  // namespace aos
diff --git a/aos/common/logging/queue_logging.h b/aos/common/logging/queue_logging.h
index ff0167a..888f808 100644
--- a/aos/common/logging/queue_logging.h
+++ b/aos/common/logging/queue_logging.h
@@ -4,9 +4,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <functional>
 #include <string>
 
-#include "aos/common/logging/logging.h"
+#include "aos/common/logging/interface.h"
 #include "aos/common/die.h"
 
 namespace aos {
@@ -14,24 +15,29 @@
 
 // Logs the contents of a structure (or Queue message) and a constant string.
 // structure must be an instance of one of the generated queue types.
-#define LOG_STRUCT(level, message, structure)                          \
-  do {                                                                 \
-    static const ::std::string kAosLoggingMessage(                     \
-        LOG_SOURCENAME ": " STRINGIFY(__LINE__) ": " message);         \
-    ::aos::logging::DoLogStruct(level, kAosLoggingMessage, structure); \
-    /* so that GCC knows that it won't return */                       \
-    if (level == FATAL) {                                              \
-      ::aos::Die("DoLogStruct(FATAL) fell through!!!!!\n");            \
-    }                                                                  \
+#define LOG_STRUCT(level, message, structure)                       \
+  do {                                                              \
+    static const ::std::string kAosLoggingMessage(                  \
+        LOG_SOURCENAME ": " STRINGIFY(__LINE__) ": " message);      \
+    ::aos::logging::DoLogStructTemplated(level, kAosLoggingMessage, \
+                                         structure);                \
+    /* so that GCC knows that it won't return */                    \
+    if (level == FATAL) {                                           \
+      ::aos::Die("DoLogStruct(FATAL) fell through!!!!!\n");         \
+    }                                                               \
   } while (false)
 
 template <class T>
-void DoLogStruct(log_level level, const ::std::string &message,
-                 const T &structure);
+void DoLogStructTemplated(log_level level, const ::std::string &message,
+                          const T &structure) {
+  auto fn = [&structure](char *buffer)
+                -> size_t { return structure.Serialize(buffer); };
+
+  internal::DoLogStruct(level, message, T::Size(), T::GetType(), ::std::ref(fn),
+                        1);
+}
 
 }  // namespace logging
 }  // namespace aos
 
-#include "aos/common/logging/queue_logging-tmpl.h"
-
 #endif  // AOS_COMMON_LOGGING_QUEUE_LOGGING_H_
diff --git a/aos/common/logging/log_replay.cc b/aos/common/logging/replay.cc
similarity index 96%
rename from aos/common/logging/log_replay.cc
rename to aos/common/logging/replay.cc
index a1efcca..7180c96 100644
--- a/aos/common/logging/log_replay.cc
+++ b/aos/common/logging/replay.cc
@@ -1,4 +1,4 @@
-#include "aos/common/logging/log_replay.h"
+#include "aos/common/logging/replay.h"
 
 namespace aos {
 namespace logging {
diff --git a/aos/common/logging/log_replay.h b/aos/common/logging/replay.h
similarity index 97%
rename from aos/common/logging/log_replay.h
rename to aos/common/logging/replay.h
index 6fb230c..38f7120 100644
--- a/aos/common/logging/log_replay.h
+++ b/aos/common/logging/replay.h
@@ -1,5 +1,5 @@
-#ifndef AOS_COMMON_LOGGING_LOG_REPLAY_H_
-#define AOS_COMMON_LOGGING_LOG_REPLAY_H_
+#ifndef AOS_COMMON_LOGGING_REPLAY_H_
+#define AOS_COMMON_LOGGING_REPLAY_H_
 
 #include <unordered_map>
 #include <string>
@@ -161,4 +161,4 @@
 }  // namespace logging
 }  // namespace aos
 
-#endif  // AOS_COMMON_LOGGING_LOG_REPLAY_H_
+#endif  // AOS_COMMON_LOGGING_REPLAY_H_
diff --git a/aos/common/queue_testutils.cc b/aos/common/queue_testutils.cc
index a40b5e9..5843e67 100644
--- a/aos/common/queue_testutils.cc
+++ b/aos/common/queue_testutils.cc
@@ -8,7 +8,7 @@
 #include "gtest/gtest.h"
 
 #include "aos/common/queue.h"
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/implementations.h"
 #include "aos/common/once.h"
 #include "aos/common/mutex.h"
 
diff --git a/aos/common/util/BUILD b/aos/common/util/BUILD
index d176733..35d8e87 100644
--- a/aos/common/util/BUILD
+++ b/aos/common/util/BUILD
@@ -9,7 +9,7 @@
     'run_command.h',
   ],
   deps = [
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging',
   ],
 )
 
@@ -32,7 +32,7 @@
     'death_test_log_implementation.h',
   ],
   deps = [
-    '//aos/common/logging',
+    '//aos/common/logging:implementations',
   ],
 )
 
@@ -104,7 +104,7 @@
   ],
   deps = [
     '//aos/common:macros',
-    '//aos/common/logging:logging_interface',
+    '//aos/common/logging',
   ],
 )
 
diff --git a/aos/common/util/death_test_log_implementation.h b/aos/common/util/death_test_log_implementation.h
index c1b12c0..c1b1da2 100644
--- a/aos/common/util/death_test_log_implementation.h
+++ b/aos/common/util/death_test_log_implementation.h
@@ -3,7 +3,7 @@
 
 #include <stdlib.h>
 
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/implementations.h"
 
 namespace aos {
 namespace util {