Make default quiche_logging_impl more functional.

Support CHECK(), DCHECK(), and LOG(DFATAL), since those are required for unit tests to work.

PiperOrigin-RevId: 449033718
diff --git a/quiche/common/platform/default/quiche_platform_impl/quiche_logging_impl.h b/quiche/common/platform/default/quiche_platform_impl/quiche_logging_impl.h
index b194bdd..1b0c764 100644
--- a/quiche/common/platform/default/quiche_platform_impl/quiche_logging_impl.h
+++ b/quiche/common/platform/default/quiche_platform_impl/quiche_logging_impl.h
@@ -3,9 +3,10 @@
 // found in the LICENSE file.
 
 // This file does not actually implement logging, it merely provides enough of
-// logging code for QUICHE to compile.  QUICHE embedders are encouraged to
-// override this file with their own logic.  If at some point logging becomes a
-// part of Abseil, this file will likely start using that instead.
+// logging code for QUICHE to compile and pass the unit tests.  QUICHE embedders
+// are encouraged to override this file with their own logic.  If at some point
+// logging becomes a part of Abseil, this file will likely start using that
+// instead.
 
 #ifndef QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_LOGGING_IMPL_H_
 #define QUICHE_COMMON_PLATFORM_DEFAULT_QUICHE_PLATFORM_IMPL_QUICHE_LOGGING_IMPL_H_
@@ -17,9 +18,17 @@
 
 #include "absl/base/attributes.h"
 #include "quiche/common/platform/api/quiche_export.h"
+#include "quiche_platform_impl/quiche_stack_trace_impl.h"
 
 namespace quiche {
 
+class QUICHE_EXPORT_PRIVATE LogStreamVoidHelper {
+ public:
+  // This operator has lower precedence than << but higher than ?:, which is
+  // useful for implementing QUICHE_DISREGARD_LOG_STREAM below.
+  constexpr void operator&(std::ostream&) {}
+};
+
 // NoopLogSink provides a log sink that does not put the data that it logs
 // anywhere.
 class QUICHE_EXPORT_PRIVATE NoopLogSink {
@@ -34,9 +43,8 @@
 
   constexpr std::ostream& stream() { return stream_; }
 
-  // This operator has lower precedence than << but higher than ?:, which is
-  // useful for implementing QUICHE_DISREGARD_LOG_STREAM below.
-  void operator&(std::ostream&) {}
+ protected:
+  std::string str() { return stream_.str(); }
 
  private:
   std::stringstream stream_;
@@ -46,74 +54,103 @@
 // to compile due to the "failed to return value from non-void function" error.
 class QUICHE_EXPORT_PRIVATE FatalLogSink : public NoopLogSink {
  public:
-  ABSL_ATTRIBUTE_NORETURN ~FatalLogSink() { abort(); }
+  ABSL_ATTRIBUTE_NORETURN ~FatalLogSink() {
+    std::cerr << str() << std::endl;
+    std::cerr << quiche::QuicheStackTraceImpl() << std::endl;
+    abort();
+  }
+};
+
+class QUICHE_EXPORT_PRIVATE CheckLogSink : public NoopLogSink {
+ public:
+  CheckLogSink(bool condition) : condition_(condition) {}
+  ~CheckLogSink() {
+    if (!condition_) {
+      std::cerr << "Check failed: " << str() << std::endl;
+      std::cerr << quiche::QuicheStackTraceImpl() << std::endl;
+      abort();
+    }
+  }
+
+ private:
+  const bool condition_;
 };
 
 }  // namespace quiche
 
-#define QUICHE_DVLOG_IMPL(verbose_level) \
-  ::quiche::NoopLogSink(#verbose_level).stream()
+// This is necessary because we sometimes call QUICHE_DCHECK inside constexpr
+// functions, and then write non-constexpr expressions into the resulting log.
+#define QUICHE_CONDITIONAL_LOG_STREAM(stream, condition) \
+  !(condition) ? (void)0 : ::quiche::LogStreamVoidHelper() & (stream)
+#define QUICHE_DISREGARD_LOG_STREAM(stream) \
+  QUICHE_CONDITIONAL_LOG_STREAM(stream, /*condition=*/false)
+#define QUICHE_NOOP_STREAM() \
+  QUICHE_DISREGARD_LOG_STREAM(::quiche::NoopLogSink().stream())
+#define QUICHE_NOOP_STREAM_WITH_CONDITION(condition) \
+  QUICHE_DISREGARD_LOG_STREAM(::quiche::NoopLogSink(condition).stream())
+
+#define QUICHE_DVLOG_IMPL(verbose_level) QUICHE_NOOP_STREAM()
 #define QUICHE_DVLOG_IF_IMPL(verbose_level, condition) \
-  ::quiche::NoopLogSink(#verbose_level, condition).stream()
-#define QUICHE_DLOG_IMPL(severity) ::quiche::NoopLogSink(#severity).stream()
-#define QUICHE_DLOG_IF_IMPL(severity, condition) \
-  ::quiche::NoopLogSink(#severity, condition).stream()
-#define QUICHE_VLOG_IMPL(verbose_level) \
-  ::quiche::NoopLogSink(#verbose_level).stream()
-#define QUICHE_LOG_FIRST_N_IMPL(severity, n) \
-  ::quiche::NoopLogSink(#severity, n).stream()
-#define QUICHE_LOG_EVERY_N_SEC_IMPL(severity, seconds) \
-  ::quiche::NoopLogSink(#severity, seconds).stream()
-#define QUICHE_LOG_IF_IMPL(severity, condition) \
-  ::quiche::NoopLogSink(#severity, condition).stream()
+  QUICHE_NOOP_STREAM_WITH_CONDITION(condition)
+#define QUICHE_DLOG_IMPL(severity) QUICHE_NOOP_STREAM()
+#define QUICHE_VLOG_IMPL(verbose_level) QUICHE_NOOP_STREAM()
+#define QUICHE_LOG_FIRST_N_IMPL(severity, n) QUICHE_NOOP_STREAM()
+#define QUICHE_LOG_EVERY_N_SEC_IMPL(severity, seconds) QUICHE_NOOP_STREAM()
 
 #define QUICHE_LOG_IMPL(severity) QUICHE_LOG_IMPL_##severity()
 #define QUICHE_LOG_IMPL_FATAL() ::quiche::FatalLogSink().stream()
-#define QUICHE_LOG_IMPL_DFATAL() ::quiche::NoopLogSink().stream()
 #define QUICHE_LOG_IMPL_ERROR() ::quiche::NoopLogSink().stream()
 #define QUICHE_LOG_IMPL_WARNING() ::quiche::NoopLogSink().stream()
 #define QUICHE_LOG_IMPL_INFO() ::quiche::NoopLogSink().stream()
 
-#define QUICHE_PLOG_IMPL(severity) ::quiche::NoopLogSink(#severity)
+#define QUICHE_LOG_IF_IMPL(severity, condition) \
+  QUICHE_CONDITIONAL_LOG_STREAM(QUICHE_LOG_IMPL_##severity(), condition)
+
+#ifdef NDEBUG
+#define QUICHE_LOG_IMPL_DFATAL() ::quiche::NoopLogSink().stream()
+#define QUICHE_DLOG_IF_IMPL(severity, condition) \
+  QUICHE_NOOP_STREAM_WITH_CONDITION(condition)
+#else
+#define QUICHE_LOG_IMPL_DFATAL() ::quiche::FatalLogSink().stream()
+#define QUICHE_DLOG_IF_IMPL(severity, condition) \
+  QUICHE_CONDITIONAL_LOG_STREAM(QUICHE_LOG_IMPL_##severity(), condition)
+#endif
+
+#define QUICHE_PLOG_IMPL(severity) QUICHE_NOOP_STREAM()
 
 #define QUICHE_DLOG_INFO_IS_ON_IMPL() false
 #define QUICHE_LOG_INFO_IS_ON_IMPL() false
 #define QUICHE_LOG_WARNING_IS_ON_IMPL() false
 #define QUICHE_LOG_ERROR_IS_ON_IMPL() false
 
-// This is necessary because we sometimes call QUICHE_DCHECK inside constexpr
-// functions, and then write non-constexpr expressions into the resulting log.
-#define QUICHE_DISREGARD_LOG_STREAM(stream) \
-  true ? (void)0 : ::quiche::NoopLogSink() & (stream)
-
-#define QUICHE_CHECK_IMPL(condition) ::quiche::NoopLogSink(condition).stream()
+#define QUICHE_CHECK_IMPL(condition) \
+  ::quiche::CheckLogSink(static_cast<bool>(condition)).stream()
 #define QUICHE_CHECK_EQ_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
+  ::quiche::CheckLogSink((val1) == (val2)).stream()
 #define QUICHE_CHECK_NE_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
+  ::quiche::CheckLogSink((val1) != (val2)).stream()
 #define QUICHE_CHECK_LE_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
+  ::quiche::CheckLogSink((val1) <= (val2)).stream()
 #define QUICHE_CHECK_LT_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
+  ::quiche::CheckLogSink((val1) < (val2)).stream()
 #define QUICHE_CHECK_GE_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
+  ::quiche::CheckLogSink((val1) >= (val2)).stream()
 #define QUICHE_CHECK_GT_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
+  ::quiche::CheckLogSink((val1) > (val2)).stream()
 
+#ifdef NDEBUG
 #define QUICHE_DCHECK_IMPL(condition) \
-  QUICHE_DISREGARD_LOG_STREAM(::quiche::NoopLogSink(condition).stream())
-#define QUICHE_DCHECK_EQ_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
-#define QUICHE_DCHECK_NE_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
-#define QUICHE_DCHECK_LE_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
-#define QUICHE_DCHECK_LT_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
-#define QUICHE_DCHECK_GE_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
-#define QUICHE_DCHECK_GT_IMPL(val1, val2) \
-  ::quiche::NoopLogSink(val1, val2).stream()
+  QUICHE_NOOP_STREAM_WITH_CONDITION((condition))
+#else
+#define QUICHE_DCHECK_IMPL(condition) \
+  QUICHE_LOG_IF_IMPL(DFATAL, !static_cast<bool>(condition))
+#endif
+#define QUICHE_DCHECK_EQ_IMPL(val1, val2) QUICHE_DCHECK_IMPL((val1) == (val2))
+#define QUICHE_DCHECK_NE_IMPL(val1, val2) QUICHE_DCHECK_IMPL((val1) != (val2))
+#define QUICHE_DCHECK_LE_IMPL(val1, val2) QUICHE_DCHECK_IMPL((val1) <= (val2))
+#define QUICHE_DCHECK_LT_IMPL(val1, val2) QUICHE_DCHECK_IMPL((val1) < (val2))
+#define QUICHE_DCHECK_GE_IMPL(val1, val2) QUICHE_DCHECK_IMPL((val1) >= (val2))
+#define QUICHE_DCHECK_GT_IMPL(val1, val2) QUICHE_DCHECK_IMPL((val1) > (val2))
 
 #define QUICHE_NOTREACHED_IMPL() QUICHE_DCHECK_IMPL(false)