[embedder] Forked fuchsia logger to access FX_CHECK OOT

Change-Id: I95523c301a00c6dd0c1652a9172d1bc2e2b09ce8
Reviewed-on: https://fuchsia-review.googlesource.com/c/flutter-embedder/+/738383
Reviewed-by: Alexander Biggs <akbiggs@google.com>
Reviewed-by: Naud Ghebre <naudzghebre@google.com>
diff --git a/src/embedder/BUILD.bazel b/src/embedder/BUILD.bazel
index 746e25d..10f4c0a 100644
--- a/src/embedder/BUILD.bazel
+++ b/src/embedder/BUILD.bazel
@@ -25,6 +25,8 @@
         "main.cc",
         "software_surface.cc",
         "software_surface.h",
+        "fuchsia_logger.h",
+        "fuchsia_logger.cc",
     ],
     deps = [
         "//src/embedder/engine:embedder_header",
diff --git a/src/embedder/fuchsia_logger.cc b/src/embedder/fuchsia_logger.cc
new file mode 100644
index 0000000..e522522
--- /dev/null
+++ b/src/embedder/fuchsia_logger.cc
@@ -0,0 +1,53 @@
+// Copyright 2022 The Fuchsia 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 "fuchsia_logger.h"
+
+#include <lib/syslog/global.h>
+#include <zircon/status.h>
+
+// TODO (see note on fuchsia_logger.h)
+
+namespace syslog {
+
+namespace internal {
+
+LogMessage::LogMessage(fx_log_severity_t severity, const char* file, int line, const char* tag,
+                       zx_status_t status, const char* condition)
+    : severity_(severity), file_(file), line_(line), tag_(tag), status_(status) {
+  if (condition)
+    stream_ << "Check failed: " << condition << ": ";
+}
+
+void FxLogFatal() { abort(); }
+
+LogMessage::~LogMessage() {
+  fx_logger_t* logger = fx_log_get_logger();
+  if (logger) {
+    if (status_ != INT32_MAX) {
+      stream_ << ": " << status_ << " (" << zx_status_get_string(status_) << ")";
+    }
+    fx_logger_log_with_source(logger, severity_, tag_, file_, line_, stream_.str().c_str());
+  } else if (severity_ == FX_LOG_FATAL) {
+    // FX_LOG_FATAL should abort regardless of whether a logger exists
+    FxLogFatal();
+  }
+}
+
+// Note that this implementation allows a data race on counter_, but
+// we consider that harmless because, as specified by the comments on
+// FX_LOGS_FIRST_N, we allow for the possibility that the message might get
+// logged more than |n| times if a single callsite of that macro is invoked by
+// multiple threads.
+bool LogFirstNState::ShouldLog(int n) {
+  const int32_t counter_value = counter_.load(std::memory_order_relaxed);
+  if (counter_value < n) {
+    counter_.store(counter_value + 1, std::memory_order_relaxed);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace internal
+}  // namespace syslog
diff --git a/src/embedder/fuchsia_logger.h b/src/embedder/fuchsia_logger.h
new file mode 100644
index 0000000..8106aaf
--- /dev/null
+++ b/src/embedder/fuchsia_logger.h
@@ -0,0 +1,185 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_EMBEDDER_FUCHSIA_LOGGER_H_
+#define SRC_EMBEDDER_FUCHSIA_LOGGER_H_
+
+#include <lib/syslog/global.h>
+#include <stdint.h>
+#include <zircon/types.h>
+
+#include <initializer_list>
+#include <ostream>
+#include <sstream>
+#include <string>
+
+// TODO (benbergkamp)
+// This logic is forked from fuchsia to support the FX_CHECK macro OOT
+// We should discuss with the SDK team about whether this is the correct
+// approach vs exposing the APIS via the SDK
+
+namespace syslog {
+namespace internal {
+
+class LogMessageVoidify {
+ public:
+  void operator&(std::ostream&) {}
+};
+
+class LogMessage {
+ public:
+  LogMessage(fx_log_severity_t severity, const char* file, int line, const char* tag,
+             zx_status_t status, const char* condition);
+  ~LogMessage();
+
+  std::ostream& stream() { return stream_; }
+
+ private:
+  std::ostringstream stream_;
+  const fx_log_severity_t severity_;
+  const char* file_;
+  const int line_;
+  const char* tag_;
+  const zx_status_t status_;
+
+  LogMessage(const LogMessage&) = delete;
+  LogMessage& operator=(const LogMessage&) = delete;
+};
+
+// LogFirstNState is used by the macro FX_LOGS_FIRST_N below.
+class LogFirstNState {
+ public:
+  bool ShouldLog(int n);
+
+ private:
+  std::atomic<int32_t> counter_{0};
+};
+
+}  // namespace internal
+
+}  // namespace syslog
+
+#define _FX_LOG_STREAM(severity, tag, status) \
+  ::syslog::internal::LogMessage((severity), __FILE__, __LINE__, (tag), (status), nullptr).stream()
+
+#define FX_LOG_STREAM(severity, tag, status) _FX_LOG_STREAM(FX_LOG_##severity, (tag), (status))
+
+#define FX_LOG_LAZY_STREAM(stream, condition) \
+  !(condition) ? (void)0 : ::syslog::internal::LogMessageVoidify() & (stream)
+
+#define _FX_EAT_STREAM_PARAMETERS(ignored, tag)                                                  \
+  true || (ignored) || (tag) != nullptr                                                          \
+      ? (void)0                                                                                  \
+      : FX_LOG_LAZY_STREAM(::syslog::internal::LogMessage(FX_LOG_FATAL, __FILE__, __LINE__, tag, \
+                                                          INT32_MAX, #ignored)                   \
+                               .stream(),                                                        \
+                           !(ignored))
+
+// Writes a message to the global logger.
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+// |tag| is a tag to associated with the message, or NULL if none.
+#define FX_LOGST(severity, tag) \
+  FX_LOG_LAZY_STREAM(FX_LOG_STREAM(severity, (tag), INT32_MAX), FX_LOG_IS_ENABLED(severity))
+
+// Writes a message to the global logger.
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+// |tag| is a tag to associated with the message, or NULL if none.
+// |status| is a zx_status_t which will be appended in decimal and string forms
+// after the message.
+#define FX_PLOGST(severity, tag, status) \
+  FX_LOG_LAZY_STREAM(FX_LOG_STREAM(severity, (tag), (status)), FX_LOG_IS_ENABLED(severity))
+
+// Writes a message to the global logger.
+// |severity| is one of FX_LOG_DEBUG, FX_LOG_INFO, FX_LOG_WARNING,
+// FX_LOG_ERROR, FX_LOG_FATAL
+// |tag| is a tag to associated with the message, or NULL if none.
+#define FX_LOGST_WITH_SEVERITY(severity, tag) \
+  FX_LOG_LAZY_STREAM(_FX_LOG_STREAM((severity), (tag), INT32_MAX), fx_log_is_enabled((severity)))
+
+// Writes a message to the global logger.
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+#define FX_LOGS(severity) FX_LOGST(severity, nullptr)
+
+// Writes a message to the global logger.
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+// |status| is a zx_status_t which will be appended in decimal and string forms
+// after the message.
+#define FX_PLOGS(severity, status) FX_PLOGST(severity, nullptr, status)
+
+// Writes a message to the global logger, the first |n| times that any callsite
+// of this macro is invoked. |n| should be a positive integer literal. If a
+// single callsite is invoked by multiple threads it is possible that the
+// number of times the message is written could be greater than |n| but will
+// never be greater than n-1 + #(calling threads).
+// |severity| is one of DEBUG, INFO, WARNING, ERROR, FATAL
+//
+// Implementation notes:
+// The outer for loop is a trick to allow us to introduce a new scope and
+// introduce the variable |syslog_internal_do_log| into that scope. It
+// executes exactly once.
+//
+// The inner for loop is a trick to allow us to introduce a new scope
+// and introduce the static variable |syslog_internal_state| into that
+// new scope. It executes either zero or one times.
+//
+// C++ does not allow us to introduce two new variables into
+// a single for loop scope and we need |syslog_internal_do_log| so that
+// the inner for loop doesn't execute twice.
+#define FX_LOGS_FIRST_N(severity, n) FX_LOGST_FIRST_N(severity, n, nullptr)
+
+#define FX_LOGST_FIRST_N(severity, n, tag)                                                         \
+  for (bool syslog_internal_do_log = true; syslog_internal_do_log; syslog_internal_do_log = false) \
+    for (static syslog::internal::LogFirstNState syslog_internal_state;                            \
+         syslog_internal_do_log && syslog_internal_state.ShouldLog(n);                             \
+         syslog_internal_do_log = false)                                                           \
+  FX_LOGST(severity, (tag))
+
+// Writes a message to the global logger.
+// |severity| is one of FX_LOG_DEBUG, FX_LOG_INFO, FX_LOG_WARNING,
+// FX_LOG_ERROR, FX_LOG_FATAL
+#define FX_LOGS_WITH_SEVERITY(severity) FX_LOGST_WITH_SEVERITY((severity), nullptr)
+
+// Writes error message to the global logger if |condition| fails.
+// |tag| is a tag to associated with the message, or NULL if none.
+#define FX_CHECKT(condition, tag)                                                                  \
+  FX_LOG_LAZY_STREAM(                                                                              \
+      ::syslog::internal::LogMessage(FX_LOG_FATAL, __FILE__, __LINE__, tag, INT32_MAX, #condition) \
+          .stream(),                                                                               \
+      !(condition))
+
+// Writes error message to the global logger if |condition| fails.
+#define FX_CHECK(condition) FX_CHECKT(condition, nullptr)
+
+// Writes error message to the global logger if |condition| fails in debug
+// build.
+#ifndef NDEBUG
+#define FX_DCHECK(condition) FX_CHECK(condition)
+#define FX_DCHECKT(condition, tag) FX_CHECKT(condition, tag)
+#else
+#define FX_DCHECK(condition) _FX_EAT_STREAM_PARAMETERS(condition, nullptr)
+#define FX_DCHECKT(condition, tag) _FX_EAT_STREAM_PARAMETERS(condition, tag)
+#endif
+
+#define FX_NOTREACHED() FX_DCHECK(false)
+
+#define FX_NOTIMPLEMENTED() FX_LOGS(ERROR) << "Not implemented in: " << __PRETTY_FUNCTION__
+
+// VLOG macros log with negative verbosities.
+#define FX_VLOG_STREAM(verbose_level, tag, status)                                               \
+  ::syslog::internal::LogMessage(-(verbose_level), __FILE__, __LINE__, (tag), (status), nullptr) \
+      .stream()
+
+#define FX_VLOGST(verbose_level, tag)                                   \
+  FX_LOG_LAZY_STREAM(FX_VLOG_STREAM((verbose_level), (tag), INT32_MAX), \
+                     FX_VLOG_IS_ENABLED((verbose_level)))
+
+#define FX_VPLOGST(verbose_level, tag, status)                         \
+  FX_LOG_LAZY_STREAM(FX_VLOG_STREAM((verbose_level), (tag), (status)), \
+                     FX_VLOG_IS_ENABLED((verbose_level)))
+
+#define FX_VLOGS(verbose_level) FX_VLOGST((verbose_level), nullptr)
+
+#define FX_VPLOGS(verbose_level, status) FX_VPLOGST((verbose_level), nullptr, status)
+
+#endif  // SRC_EMBEDDER_FUCHSIA_LOGGER_H_