Implement RTC_LOG_IF and RTC_DLOG_IF

and
RTC_LOG_IF_F and RTC_DLOG_IF_F


Bug: webrtc:14505
Change-Id: I5df1e920831f545752f6d7433f0ae853e58c0b9f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/277441
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Commit-Queue: Per Kjellander <perkj@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38258}
diff --git a/rtc_base/logging.h b/rtc_base/logging.h
index 2c3a6dc..d59b9a0 100644
--- a/rtc_base/logging.h
+++ b/rtc_base/logging.h
@@ -21,9 +21,13 @@
 // RTC_LOG(sev) logs the given stream at severity "sev", which must be a
 //     compile-time constant of the LoggingSeverity type, without the namespace
 //     prefix.
+// RTC_LOG_IF(sev, condition) logs the given stream at severitye "sev" if
+//     "condition" is true.
 // RTC_LOG_V(sev) Like RTC_LOG(), but sev is a run-time variable of the
 //     LoggingSeverity type (basically, it just doesn't prepend the namespace).
 // RTC_LOG_F(sev) Like RTC_LOG(), but includes the name of the current function.
+// RTC_LOG_IF_F(sev, condition), Like RTC_LOG_IF(), but includes the name of
+//     the current function.
 // RTC_LOG_T(sev) Like RTC_LOG(), but includes the this pointer.
 // RTC_LOG_T_F(sev) Like RTC_LOG_F(), but includes the this pointer.
 // RTC_LOG_GLE(sev [, mod]) attempt to add a string description of the
@@ -647,6 +651,10 @@
   !rtc::LogMessage::IsNoop<::rtc::sev>() && \
       RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__)
 
+#define RTC_LOG_IF(sev, condition)                         \
+  !rtc::LogMessage::IsNoop<::rtc::sev>() && (condition) && \
+      RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__)
+
 // The _V version is for when a variable is passed in.
 #define RTC_LOG_V(sev) \
   !rtc::LogMessage::IsNoop(sev) && RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__)
@@ -654,10 +662,14 @@
 // The _F version prefixes the message with the current function name.
 #if (defined(__GNUC__) && !defined(NDEBUG)) || defined(WANT_PRETTY_LOG_F)
 #define RTC_LOG_F(sev) RTC_LOG(sev) << __PRETTY_FUNCTION__ << ": "
+#define RTC_LOG_IF_F(sev, condition) \
+  RTC_LOG_IF(sev, condition) << __PRETTY_FUNCTION__ << ": "
 #define RTC_LOG_T_F(sev) \
   RTC_LOG(sev) << this << ": " << __PRETTY_FUNCTION__ << ": "
 #else
 #define RTC_LOG_F(sev) RTC_LOG(sev) << __FUNCTION__ << ": "
+#define RTC_LOG_IF_F(sev, condition) \
+  RTC_LOG_IF(sev, condition) << __FUNCTION__ << ": "
 #define RTC_LOG_T_F(sev) RTC_LOG(sev) << this << ": " << __FUNCTION__ << ": "
 #endif
 
@@ -725,16 +737,20 @@
 // they only generate code in debug builds.
 #if RTC_DLOG_IS_ON
 #define RTC_DLOG(sev) RTC_LOG(sev)
+#define RTC_DLOG_IF(sev, condition) RTC_LOG_IF(sev, condition)
 #define RTC_DLOG_V(sev) RTC_LOG_V(sev)
 #define RTC_DLOG_F(sev) RTC_LOG_F(sev)
+#define RTC_DLOG_IF_F(sev, condition) RTC_LOG_IF_F(sev, condition)
 #else
 #define RTC_DLOG_EAT_STREAM_PARAMS()                \
   while (false)                                     \
   ::rtc::webrtc_logging_impl::LogMessageVoidify() & \
       (::rtc::webrtc_logging_impl::LogStreamer<>())
 #define RTC_DLOG(sev) RTC_DLOG_EAT_STREAM_PARAMS()
+#define RTC_DLOG_IF(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS()
 #define RTC_DLOG_V(sev) RTC_DLOG_EAT_STREAM_PARAMS()
 #define RTC_DLOG_F(sev) RTC_DLOG_EAT_STREAM_PARAMS()
+#define RTC_DLOG_IF_F(sev, condition) RTC_DLOG_EAT_STREAM_PARAMS()
 #endif
 
 }  // namespace rtc
diff --git a/rtc_base/logging_unittest.cc b/rtc_base/logging_unittest.cc
index 70c1fef..b05907e 100644
--- a/rtc_base/logging_unittest.cc
+++ b/rtc_base/logging_unittest.cc
@@ -144,6 +144,52 @@
   EXPECT_EQ(sev, LogMessage::GetLogToStream(nullptr));
 }
 
+TEST(LogTest, LogIfLogIfConditionIsTrue) {
+  std::string str;
+  LogSinkImpl stream(&str);
+  LogMessage::AddLogToStream(&stream, LS_INFO);
+
+  RTC_LOG_IF(LS_INFO, true) << "Hello";
+  EXPECT_NE(std::string::npos, str.find("Hello"));
+
+  LogMessage::RemoveLogToStream(&stream);
+}
+
+TEST(LogTest, LogIfDontLogIfConditionIsFalse) {
+  std::string str;
+  LogSinkImpl stream(&str);
+  LogMessage::AddLogToStream(&stream, LS_INFO);
+
+  RTC_LOG_IF(LS_INFO, false) << "Hello";
+  EXPECT_EQ(std::string::npos, str.find("Hello"));
+
+  LogMessage::RemoveLogToStream(&stream);
+}
+
+TEST(LogTest, LogIfFLogIfConditionIsTrue) {
+  std::string str;
+  LogSinkImpl stream(&str);
+  LogMessage::AddLogToStream(&stream, LS_INFO);
+
+  RTC_LOG_IF_F(LS_INFO, true) << "Hello";
+  EXPECT_NE(std::string::npos, str.find(__FUNCTION__));
+  EXPECT_NE(std::string::npos, str.find("Hello"));
+
+  LogMessage::RemoveLogToStream(&stream);
+}
+
+TEST(LogTest, LogIfFDontLogIfConditionIsFalse) {
+  std::string str;
+  LogSinkImpl stream(&str);
+  LogMessage::AddLogToStream(&stream, LS_INFO);
+
+  RTC_LOG_IF_F(LS_INFO, false) << "Not";
+  EXPECT_EQ(std::string::npos, str.find(__FUNCTION__));
+  EXPECT_EQ(std::string::npos, str.find("Not"));
+
+  LogMessage::RemoveLogToStream(&stream);
+}
+
 // Test using multiple log streams. The INFO stream should get the INFO message,
 // the VERBOSE stream should get the INFO and the VERBOSE.
 // We should restore the correct global state at the end.