Commit a478d52f authored by Murali Vilayannur's avatar Murali Vilayannur Committed by Facebook Github Bot

Add a LOG_IF equivalent to folly's logging library

Summary: Allows for conditional logging of messages.

Reviewed By: simpkins

Differential Revision: D7888834

fbshipit-source-id: d1fe47d82fe8889f6b597062f5542e7eb61ed9e6
parent df00b343
...@@ -47,8 +47,16 @@ std::string loggingFormatPrintf( ...@@ -47,8 +47,16 @@ std::string loggingFormatPrintf(
* Log a message to the file's default log category using a printf-style format * Log a message to the file's default log category using a printf-style format
* string. * 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( \ XLOG_IMPL( \
::folly::LogLevel::level, \ ::folly::LogLevel::level, \
cond, \
::folly::LogStreamProcessor::APPEND, \ ::folly::LogStreamProcessor::APPEND, \
::folly::loggingFormatPrintf(fmt, ##__VA_ARGS__)) ::folly::loggingFormatPrintf(fmt, ##__VA_ARGS__))
...@@ -90,6 +90,76 @@ TEST(PrintfTest, printfStyleMacros) { ...@@ -90,6 +90,76 @@ TEST(PrintfTest, printfStyleMacros) {
EXPECT_EQ("no xlog format arguments", messages[0].first.getMessage()); EXPECT_EQ("no xlog format arguments", messages[0].first.getMessage());
messages.clear(); 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 // Errors attempting to format the message should not throw
FB_LOGC(footest1234, ERR, "width overflow: %999999999999999999999d", 5); FB_LOGC(footest1234, ERR, "width overflow: %999999999999999999999d", 5);
ASSERT_EQ(1, messages.size()); ASSERT_EQ(1, messages.size());
......
...@@ -43,6 +43,78 @@ TEST(Xlog, xlogName) { ...@@ -43,6 +43,78 @@ TEST(Xlog, xlogName) {
EXPECT_EQ("xlog_test.main_file", XLOG_GET_CATEGORY()->getName()); 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) { TEST(Xlog, xlog) {
auto handler = make_shared<TestLogHandler>(); auto handler = make_shared<TestLogHandler>();
LoggerDB::get().getCategory("xlog_test")->addHandler(handler); LoggerDB::get().getCategory("xlog_test")->addHandler(handler);
......
...@@ -53,21 +53,37 @@ ...@@ -53,21 +53,37 @@
* best if you always invoke the compiler from the root directory of your * best if you always invoke the compiler from the root directory of your
* project repository. * 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( \ XLOG_IMPL( \
::folly::LogLevel::level, \ ::folly::LogLevel::level, \
cond, \
::folly::LogStreamProcessor::APPEND, \ ::folly::LogStreamProcessor::APPEND, \
##__VA_ARGS__) ##__VA_ARGS__)
/** /**
* Log a message to this file's default log category, using a format string. * Log a message to this file's default log category, using a format string.
*/ */
#define XLOGF(level, fmt, arg1, ...) \ #define XLOGF(level, fmt, arg1, ...) \
XLOG_IMPL( \ XLOGF_IF(level, true, fmt, arg1, ##__VA_ARGS__)
::folly::LogLevel::level, \
::folly::LogStreamProcessor::FORMAT, \ /**
fmt, \ * Log a message using a format string if and only if the specified condition
arg1, \ * 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__) ##__VA_ARGS__)
/** /**
...@@ -132,8 +148,8 @@ ...@@ -132,8 +148,8 @@
* skipped with just a single check of the LogLevel. * skipped with just a single check of the LogLevel.
*/ */
/* clang-format off */ /* clang-format off */
#define XLOG_IMPL(level, type, ...) \ #define XLOG_IMPL(level, cond, type, ...) \
(!XLOG_IS_ON_IMPL(level)) \ (!XLOG_IS_ON_IMPL(level) || !(cond)) \
? ::folly::logDisabledHelper( \ ? ::folly::logDisabledHelper( \
std::integral_constant<bool, ::folly::isLogLevelFatal(level)>{}) \ std::integral_constant<bool, ::folly::isLogLevelFatal(level)>{}) \
: ::folly::LogStreamVoidify< ::folly::isLogLevelFatal(level)>{} & \ : ::folly::LogStreamVoidify< ::folly::isLogLevelFatal(level)>{} & \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment