[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_