diff --git a/folly/logging/printf.h b/folly/logging/printf.h
index 9ba34b2900b82bbf090464972748da73d5a63fef..3a0b6b47c388ab307e6b4c7846eb46e814abb093 100644
--- a/folly/logging/printf.h
+++ b/folly/logging/printf.h
@@ -47,8 +47,16 @@ std::string loggingFormatPrintf(
  * Log a message to the file's default log category using a printf-style format
  * string.
  */
-#define XLOGC(level, fmt, ...)             \
+#define XLOGC(level, fmt, ...) XLOGC_IF(level, true, fmt, ##__VA_ARGS__)
+
+/**
+ * Log a message using a printf-style format string if and only if the
+ * specified condition predicate evaluates to true. Note that the condition
+ * is *only* evaluated if the log-level check passes.
+ */
+#define XLOGC_IF(level, cond, fmt, ...)    \
   XLOG_IMPL(                               \
       ::folly::LogLevel::level,            \
+      cond,                                \
       ::folly::LogStreamProcessor::APPEND, \
       ::folly::loggingFormatPrintf(fmt, ##__VA_ARGS__))
diff --git a/folly/logging/test/PrintfTest.cpp b/folly/logging/test/PrintfTest.cpp
index 785a85bc945dbd9d56b4fd4c02651202f1ef5283..423c95711f7d7a2b3d0bd2c9df29d9b880956a80 100644
--- a/folly/logging/test/PrintfTest.cpp
+++ b/folly/logging/test/PrintfTest.cpp
@@ -90,6 +90,76 @@ TEST(PrintfTest, printfStyleMacros) {
   EXPECT_EQ("no xlog format arguments", messages[0].first.getMessage());
   messages.clear();
 
+  XLOGC_IF(DBG1, false, "no xlog format arguments");
+  ASSERT_EQ(0, messages.size());
+  XLOGC_IF(DBG1, true, "xlog format arguments");
+  ASSERT_EQ(1, messages.size());
+  messages.clear();
+
+  argumentEvaluated = false;
+  XLOGC_IF(DBG1, true, "xlog format string %d", getValue());
+  ASSERT_EQ(1, messages.size());
+  EXPECT_TRUE(argumentEvaluated);
+  messages.clear();
+
+  argumentEvaluated = false;
+  XLOGC_IF(DBG1, false, "xlog format string %d", getValue());
+  ASSERT_EQ(0, messages.size());
+  EXPECT_FALSE(argumentEvaluated);
+  messages.clear();
+
+  // more complex conditional expressions
+  std::array<bool, 2> conds = {false, true};
+  for (unsigned i = 0; i < conds.size(); i++) {
+    for (unsigned j = 0; j < conds.size(); j++) {
+      argumentEvaluated = false;
+      XLOGC_IF(
+          DBG1, conds[i] && conds[j], "testing conditional %d", getValue());
+      EXPECT_EQ((conds[i] && conds[j]) ? 1 : 0, messages.size());
+      messages.clear();
+      if (conds[i] && conds[j]) {
+        EXPECT_TRUE(argumentEvaluated);
+      } else {
+        EXPECT_FALSE(argumentEvaluated);
+      }
+
+      argumentEvaluated = false;
+      XLOGC_IF(
+          DBG1, conds[i] || conds[j], "testing conditional %d", getValue());
+      EXPECT_EQ((conds[i] || conds[j]) ? 1 : 0, messages.size());
+      messages.clear();
+      if (conds[i] || conds[j]) {
+        EXPECT_TRUE(argumentEvaluated);
+      } else {
+        EXPECT_FALSE(argumentEvaluated);
+      }
+    }
+  }
+
+  XLOGC_IF(DBG1, 0x6 & 0x2, "More conditional 1");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOGC_IF(DBG1, 0x6 | 0x2, "More conditional 2");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOGC_IF(DBG1, 0x6 | 0x2 ? true : false, "More conditional 3");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOGC_IF(DBG1, 0x6 | 0x2 ? true : false, "More conditional 3");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOGC_IF(DBG1, 0x3 & 0x4 ? true : false, "More conditional 4");
+  EXPECT_EQ(0, messages.size());
+  messages.clear();
+
+  XLOGC_IF(DBG1, false ? true : false, "More conditional 5");
+  EXPECT_EQ(0, messages.size());
+  messages.clear();
+
   // Errors attempting to format the message should not throw
   FB_LOGC(footest1234, ERR, "width overflow: %999999999999999999999d", 5);
   ASSERT_EQ(1, messages.size());
diff --git a/folly/logging/test/XlogTest.cpp b/folly/logging/test/XlogTest.cpp
index 89a003d6264ac942b188d0edec5d08a9bd5154e4..2206d9ca27e86ad5da53738537eb91261a8dbae8 100644
--- a/folly/logging/test/XlogTest.cpp
+++ b/folly/logging/test/XlogTest.cpp
@@ -43,6 +43,78 @@ TEST(Xlog, xlogName) {
   EXPECT_EQ("xlog_test.main_file", XLOG_GET_CATEGORY()->getName());
 }
 
+TEST(Xlog, xlogIf) {
+  auto handler = make_shared<TestLogHandler>();
+  LoggerDB::get().getCategory("xlog_test")->addHandler(handler);
+  auto& messages = handler->getMessages();
+
+  // info messages are not enabled initially.
+  EXPECT_FALSE(XLOG_IS_ON(INFO));
+  EXPECT_TRUE(XLOG_IS_ON(ERR));
+  XLOG_IF(INFO, false, "testing 1");
+  EXPECT_EQ(0, messages.size());
+  messages.clear();
+
+  XLOG_IF(INFO, true, "testing 1");
+  EXPECT_EQ(0, messages.size());
+  messages.clear();
+
+  // Increase the log level, then log a message.
+  LoggerDB::get().setLevel("xlog_test.main_file", LogLevel::DBG1);
+  XLOG_IF(DBG1, false, "testing: ", 1, 2, 3);
+  ASSERT_EQ(0, messages.size());
+  messages.clear();
+
+  XLOG_IF(DBG1, true, "testing: ", 1, 2, 3);
+  ASSERT_EQ(1, messages.size());
+  messages.clear();
+
+  // more complex conditional expressions
+  std::array<bool, 2> conds = {false, true};
+  for (unsigned i = 0; i < conds.size(); i++) {
+    for (unsigned j = 0; j < conds.size(); j++) {
+      XLOG_IF(DBG1, conds[i] && conds[j], "testing conditional");
+      EXPECT_EQ((conds[i] && conds[j]) ? 1 : 0, messages.size());
+      messages.clear();
+
+      XLOG_IF(DBG1, conds[i] || conds[j], "testing conditional");
+      EXPECT_EQ((conds[i] || conds[j]) ? 1 : 0, messages.size());
+      messages.clear();
+    }
+  }
+
+  XLOG_IF(DBG1, 0x6 & 0x2, "More conditional 1");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOG_IF(DBG1, 0x6 | 0x2, "More conditional 2");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOG_IF(DBG1, 0x6 | 0x2 ? true : false, "More conditional 3");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOG_IF(DBG1, 0x6 | 0x2 ? true : false, "More conditional 3");
+  EXPECT_EQ(1, messages.size());
+  messages.clear();
+
+  XLOG_IF(DBG1, 0x3 & 0x4 ? true : false, "More conditional 4");
+  EXPECT_EQ(0, messages.size());
+  messages.clear();
+
+  XLOG_IF(DBG1, false ? true : false, "More conditional 5");
+  EXPECT_EQ(0, messages.size());
+  messages.clear();
+
+  XLOGF_IF(DBG1, false, "number: {:>3d}; string: {}", 12, "foo");
+  ASSERT_EQ(0, messages.size());
+  messages.clear();
+  XLOGF_IF(DBG1, true, "number: {:>3d}; string: {}", 12, "foo");
+  ASSERT_EQ(1, messages.size());
+  messages.clear();
+}
+
 TEST(Xlog, xlog) {
   auto handler = make_shared<TestLogHandler>();
   LoggerDB::get().getCategory("xlog_test")->addHandler(handler);
diff --git a/folly/logging/xlog.h b/folly/logging/xlog.h
index a101a4e45ae2997f681294c64b2caec8de7481b9..7080a34e58a15e62b2863c168cf6cf528198ac09 100644
--- a/folly/logging/xlog.h
+++ b/folly/logging/xlog.h
@@ -53,21 +53,37 @@
  * best if you always invoke the compiler from the root directory of your
  * project repository.
  */
-#define XLOG(level, ...)                   \
+#define XLOG(level, ...) XLOG_IF(level, true, ##__VA_ARGS__)
+
+/**
+ * Log a message if and only if the specified condition predicate evaluates
+ * to true. Note that the condition is *only* evaluated if the log-level check
+ * passes.
+ */
+#define XLOG_IF(level, cond, ...)          \
   XLOG_IMPL(                               \
       ::folly::LogLevel::level,            \
+      cond,                                \
       ::folly::LogStreamProcessor::APPEND, \
       ##__VA_ARGS__)
-
 /**
  * Log a message to this file's default log category, using a format string.
  */
-#define XLOGF(level, fmt, arg1, ...)       \
-  XLOG_IMPL(                               \
-      ::folly::LogLevel::level,            \
-      ::folly::LogStreamProcessor::FORMAT, \
-      fmt,                                 \
-      arg1,                                \
+#define XLOGF(level, fmt, arg1, ...) \
+  XLOGF_IF(level, true, fmt, arg1, ##__VA_ARGS__)
+
+/**
+ * Log a message using a format string if and only if the specified condition
+ * predicate evaluates to true. Note that the condition is *only* evaluated
+ * if the log-level check passes.
+ */
+#define XLOGF_IF(level, cond, fmt, arg1, ...) \
+  XLOG_IMPL(                                  \
+      ::folly::LogLevel::level,               \
+      cond,                                   \
+      ::folly::LogStreamProcessor::FORMAT,    \
+      fmt,                                    \
+      arg1,                                   \
       ##__VA_ARGS__)
 
 /**
@@ -132,8 +148,8 @@
  *   skipped with just a single check of the LogLevel.
  */
 /* clang-format off */
-#define XLOG_IMPL(level, type, ...)                                          \
-  (!XLOG_IS_ON_IMPL(level))                                                  \
+#define XLOG_IMPL(level, cond, type, ...)                                    \
+  (!XLOG_IS_ON_IMPL(level) || !(cond))                                       \
       ? ::folly::logDisabledHelper(                                          \
             std::integral_constant<bool, ::folly::isLogLevelFatal(level)>{}) \
       : ::folly::LogStreamVoidify< ::folly::isLogLevelFatal(level)>{} &      \