Commit 634f2652 authored by Adam Simpkins's avatar Adam Simpkins Committed by Facebook Github Bot

logging: add an FB_LOG_RAW() macro

Summary:
`FB_LOG_RAW()` is similar to `FB_LOG()` but allows the caller to pass in the
log level as a variable, and to specify an alternate file name and line number.

This is useful for callers that wish to implement their own logging utility
functions that log a message, but pass through their caller's file name and
line number.

Reviewed By: wez

Differential Revision: D7128091

fbshipit-source-id: 1fec158a9312b9c9dc53cf3dc87004d42f9806c6
parent b2b96f59
......@@ -22,24 +22,6 @@
#include <folly/experimental/logging/LogStream.h>
#include <folly/experimental/logging/LogStreamProcessor.h>
/**
* Helper macro for implementing FB_LOG() and FB_LOGF().
*
* This macro generally should not be used directly by end users.
*/
#define FB_LOG_IMPL(logger, level, type, ...) \
(!(logger).getCategory()->logCheck(level)) \
? ::folly::logDisabledHelper( \
std::integral_constant<bool, ::folly::isLogLevelFatal(level)>{}) \
: ::folly::LogStreamVoidify<::folly::isLogLevelFatal(level)>{} & \
::folly::LogStreamProcessor{(logger).getCategory(), \
(level), \
__FILE__, \
__LINE__, \
(type), \
##__VA_ARGS__} \
.stream()
/**
* Log a message to the specified logger.
*
......@@ -77,6 +59,82 @@
arg1, \
##__VA_ARGS__)
/**
* FB_LOG_RAW() can be used by callers that want to pass in the log level as a
* variable, and/or who want to explicitly specify the filename and line
* number.
*
* This is useful for callers implementing their own log wrapper functions
* that want to pass in their caller's filename and line number rather than
* their own.
*
* The log level parameter must be an explicitly qualified LogLevel value, or a
* LogLevel variable. (This differs from FB_LOG() and FB_LOGF() which accept
* an unqualified LogLevel name.)
*/
#define FB_LOG_RAW(logger, level, filename, linenumber, ...) \
FB_LOG_RAW_IMPL( \
logger, \
level, \
filename, \
linenumber, \
::folly::LogStreamProcessor::APPEND, \
##__VA_ARGS__)
/**
* FB_LOGF_RAW() is similar to FB_LOG_RAW(), but formats the log arguments
* using folly::format().
*/
#define FB_LOGF_RAW(logger, level, filename, linenumber, fmt, arg1, ...) \
FB_LOG_RAW_IMPL( \
logger, \
level, \
filename, \
linenumber, \
::folly::LogStreamProcessor::FORMAT, \
fmt, \
arg1, \
##__VA_ARGS__)
/**
* Helper macro for implementing FB_LOG() and FB_LOGF().
*
* This macro generally should not be used directly by end users.
*/
#define FB_LOG_IMPL(logger, level, type, ...) \
(!(logger).getCategory()->logCheck(level)) \
? ::folly::logDisabledHelper( \
std::integral_constant<bool, ::folly::isLogLevelFatal(level)>{}) \
: ::folly::LogStreamVoidify<::folly::isLogLevelFatal(level)>{} & \
::folly::LogStreamProcessor{(logger).getCategory(), \
(level), \
__FILE__, \
__LINE__, \
(type), \
##__VA_ARGS__} \
.stream()
/**
* Helper macro for implementing FB_LOG_RAW() and FB_LOGF_RAW().
*
* This macro generally should not be used directly by end users.
*
* This is very similar to FB_LOG_IMPL(), but since the level may be a variable
* instead of a compile-time constant, we cannot detect at compile time if this
* is a fatal log message or not.
*/
#define FB_LOG_RAW_IMPL(logger, level, filename, line, type, ...) \
(!(logger).getCategory()->logCheck(level)) \
? static_cast<void>(0) \
: ::folly::LogStreamVoidify<false>{} & \
::folly::LogStreamProcessor{(logger).getCategory(), \
(level), \
(filename), \
(line), \
(type), \
##__VA_ARGS__} \
.stream()
namespace folly {
class LoggerDB;
......
......@@ -40,12 +40,8 @@ std::string loggingFormatPrintf(
/**
* Log a message to the specified logger using a printf-style format string.
*/
#define FB_LOGC(logger, level, fmt, ...) \
FB_LOG_IMPL( \
logger, \
::folly::LogLevel::level, \
::folly::LogStreamProcessor::APPEND, \
::folly::loggingFormatPrintf(fmt, ##__VA_ARGS__))
#define FB_LOGC(logger, level, fmt, ...) \
FB_LOG(logger, level, ::folly::loggingFormatPrintf(fmt, ##__VA_ARGS__))
/**
* Log a message to the file's default log category using a printf-style format
......
......@@ -21,6 +21,7 @@
#include <folly/experimental/logging/test/TestLogHandler.h>
#include <folly/portability/GMock.h>
#include <folly/portability/GTest.h>
#include <folly/test/TestUtils.h>
using namespace folly;
using std::make_shared;
......@@ -349,3 +350,29 @@ TEST_F(LoggerTest, logMacros) {
R"(format string: "whoops: \{\}, \{\}", arguments: \((.*: )?5\))"));
messages.clear();
}
TEST_F(LoggerTest, logRawMacros) {
Logger foobar{&db_, "test.foo.bar"};
db_.setLevel("test.foo", LogLevel::DBG2);
auto& messages = handler_->getMessages();
FB_LOG_RAW(foobar, LogLevel::DBG1, "src/some/file.c", 1234, "hello", ' ', 1)
<< " world";
ASSERT_EQ(1, messages.size());
EXPECT_EQ("hello 1 world", messages[0].first.getMessage());
EXPECT_EQ("src/some/file.c", messages[0].first.getFileName());
EXPECT_EQ("file.c", messages[0].first.getFileBaseName());
EXPECT_EQ(1234, messages[0].first.getLineNumber());
messages.clear();
auto level = LogLevel::DBG1;
FB_LOGF_RAW(foobar, level, "test/mytest.c", 99, "{}: num={}", "test", 42)
<< " plus extra stuff";
ASSERT_EQ(1, messages.size());
EXPECT_EQ("test: num=42 plus extra stuff", messages[0].first.getMessage());
EXPECT_EQ("test/mytest.c", messages[0].first.getFileName());
EXPECT_EQ("mytest.c", messages[0].first.getFileBaseName());
EXPECT_EQ(99, messages[0].first.getLineNumber());
messages.clear();
}
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