Minimize platform/api/logging.h, consolidate macros/impl elsewhere.

Reduces the logging API that must be implemented by embedders to three
simple functions: IsLoggingOn(), LogWithLevel(), and Break(). Added
documentation for these functions.

All logging convenience macros that OpenScreen code uses have been moved
to platform/api/internal/logging_macros.h, and are being #included from
platform/api/logging.h. This is to make it easier for embedder
developers to identify what is being required from them.

All standalone impl for logging has been consolidated into
platform/impl/logging.h (declaration of init routines) and
logging_posix.cc (POSIX implementation, writing to stderr or a FIFO).

Bug: openscreen:77
Change-Id: Id14a380569373a443a81b7bb5139b4648643495e
Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/1900333
Reviewed-by: Yuri Wiitala <miu@chromium.org>
Reviewed-by: mark a. foltz <mfoltz@chromium.org>
Commit-Queue: Yuri Wiitala <miu@chromium.org>
diff --git a/platform/impl/logging_posix.cc b/platform/impl/logging_posix.cc
new file mode 100644
index 0000000..f0c862a
--- /dev/null
+++ b/platform/impl/logging_posix.cc
@@ -0,0 +1,113 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdlib>
+#include <iostream>
+#include <sstream>
+
+#include "platform/api/trace_logging.h"
+#include "platform/impl/logging.h"
+
+namespace openscreen {
+namespace platform {
+namespace {
+
+int g_log_fd = STDERR_FILENO;
+LogLevel g_log_level = LogLevel::kWarning;
+
+std::ostream& operator<<(std::ostream& os, const LogLevel& level) {
+  const char* level_string = "";
+  switch (level) {
+    case LogLevel::kVerbose:
+      level_string = "VERBOSE";
+      break;
+    case LogLevel::kInfo:
+      level_string = "INFO";
+      break;
+    case LogLevel::kWarning:
+      level_string = "WARNING";
+      break;
+    case LogLevel::kError:
+      level_string = "ERROR";
+      break;
+    case LogLevel::kFatal:
+      level_string = "FATAL";
+      break;
+  }
+  os << level_string;
+  return os;
+}
+
+}  // namespace
+
+void SetLogFifoOrDie(const char* filename) {
+  if (g_log_fd != STDERR_FILENO) {
+    close(g_log_fd);
+    g_log_fd = STDERR_FILENO;
+  }
+
+  // Note: The use of OSP_CHECK/OSP_LOG here will log to stderr.
+  struct stat st = {};
+  int open_result = -1;
+  if (stat(filename, &st) == -1 && errno == ENOENT) {
+    if (mkfifo(filename, 0644) == 0) {
+      open_result = open(filename, O_WRONLY);
+      OSP_CHECK_NE(open_result, -1)
+          << "open(" << filename << ") failed: " << strerror(errno);
+    } else {
+      OSP_LOG_FATAL << "mkfifo(" << filename << ") failed: " << strerror(errno);
+    }
+  } else if (S_ISFIFO(st.st_mode)) {
+    open_result = open(filename, O_WRONLY);
+    OSP_CHECK_NE(open_result, -1)
+        << "open(" << filename << ") failed: " << strerror(errno);
+  } else {
+    OSP_LOG_FATAL << "not a FIFO special file: " << filename;
+  }
+
+  // Direct all logging to the opened FIFO file.
+  g_log_fd = open_result;
+}
+
+void SetLogLevel(LogLevel level) {
+  g_log_level = level;
+}
+
+bool IsLoggingOn(LogLevel level, absl::string_view file) {
+  // Possible future enhancement: Use glob patterns passed on the command-line
+  // to use a different logging level for certain files, like in Chromium.
+  return level >= g_log_level;
+}
+
+void LogWithLevel(LogLevel level,
+                  absl::string_view file,
+                  int line,
+                  absl::string_view msg) {
+  if (level < g_log_level)
+    return;
+
+  std::stringstream ss;
+  ss << "[" << level << ":" << file << "(" << line << "):T" << std::hex
+     << TRACE_CURRENT_ID << "] " << msg << '\n';
+  const auto ss_str = ss.str();
+  const auto bytes_written = write(g_log_fd, ss_str.c_str(), ss_str.size());
+  OSP_DCHECK(bytes_written);
+}
+
+void Break() {
+#if defined(_DEBUG)
+  __builtin_trap();
+#else
+  std::abort();
+#endif
+}
+
+}  // namespace platform
+}  // namespace openscreen