#include <folly/experimental/logging/LogStreamProcessor.h>
#include <folly/experimental/logging/LogStream.h>
+#include <folly/experimental/logging/xlog.h>
namespace folly {
folly::StringPiece filename,
unsigned int lineNumber,
AppendType) noexcept
+ : LogStreamProcessor(
+ category,
+ level,
+ filename,
+ lineNumber,
+ INTERNAL,
+ std::string()) {}
+
+LogStreamProcessor::LogStreamProcessor(
+ XlogCategoryInfo<true>* categoryInfo,
+ LogLevel level,
+ folly::StringPiece categoryName,
+ bool isCategoryNameOverridden,
+ folly::StringPiece filename,
+ unsigned int lineNumber,
+ AppendType) noexcept
+ : LogStreamProcessor(
+ categoryInfo,
+ level,
+ categoryName,
+ isCategoryNameOverridden,
+ filename,
+ lineNumber,
+ INTERNAL,
+ std::string()) {}
+
+LogStreamProcessor::LogStreamProcessor(
+ XlogFileScopeInfo* fileScopeInfo,
+ LogLevel level,
+ folly::StringPiece filename,
+ unsigned int lineNumber,
+ AppendType) noexcept
+ : LogStreamProcessor(
+ fileScopeInfo,
+ level,
+ filename,
+ lineNumber,
+ INTERNAL,
+ std::string()) {}
+
+LogStreamProcessor::LogStreamProcessor(
+ const LogCategory* category,
+ LogLevel level,
+ folly::StringPiece filename,
+ unsigned int lineNumber,
+ InternalType,
+ std::string&& msg) noexcept
: category_{category},
level_{level},
filename_{filename},
- lineNumber_{lineNumber} {}
+ lineNumber_{lineNumber},
+ message_{std::move(msg)},
+ stream_{this} {}
+
+namespace {
+LogCategory* getXlogCategory(
+ XlogCategoryInfo<true>* categoryInfo,
+ folly::StringPiece categoryName,
+ bool isCategoryNameOverridden) {
+ if (!categoryInfo->isInitialized()) {
+ return categoryInfo->init(categoryName, isCategoryNameOverridden);
+ }
+ return categoryInfo->getCategory(&xlog_detail::xlogFileScopeInfo);
+}
+
+LogCategory* getXlogCategory(XlogFileScopeInfo* fileScopeInfo) {
+ // By the time a LogStreamProcessor is created, the XlogFileScopeInfo object
+ // should have already been initialized to perform the log level check.
+ // Therefore we never need to check if it is initialized here.
+ return fileScopeInfo->category;
+}
+}
+
+/**
+ * Construct a LogStreamProcessor from an XlogCategoryInfo.
+ *
+ * We intentionally define this in LogStreamProcessor.cpp instead of
+ * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
+ * to reduce the emitted code size.
+ */
+LogStreamProcessor::LogStreamProcessor(
+ XlogCategoryInfo<true>* categoryInfo,
+ LogLevel level,
+ folly::StringPiece categoryName,
+ bool isCategoryNameOverridden,
+ folly::StringPiece filename,
+ unsigned int lineNumber,
+ InternalType,
+ std::string&& msg) noexcept
+ : category_{getXlogCategory(
+ categoryInfo,
+ categoryName,
+ isCategoryNameOverridden)},
+ level_{level},
+ filename_{filename},
+ lineNumber_{lineNumber},
+ message_{std::move(msg)},
+ stream_{this} {}
+/**
+ * Construct a LogStreamProcessor from an XlogFileScopeInfo.
+ *
+ * We intentionally define this in LogStreamProcessor.cpp instead of
+ * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
+ * to reduce the emitted code size.
+ */
LogStreamProcessor::LogStreamProcessor(
- const LogCategory* category,
+ XlogFileScopeInfo* fileScopeInfo,
LogLevel level,
- const char* filename,
+ folly::StringPiece filename,
unsigned int lineNumber,
InternalType,
std::string&& msg) noexcept
- : category_{category},
+ : category_{getXlogCategory(fileScopeInfo)},
level_{level},
filename_{filename},
lineNumber_{lineNumber},
- message_{std::move(msg)} {}
+ message_{std::move(msg)},
+ stream_{this} {}
-void LogStreamProcessor::operator&(std::ostream& stream) noexcept {
+/*
+ * We intentionally define the LogStreamProcessor destructor in
+ * LogStreamProcessor.cpp instead of LogStreamProcessor.h to avoid having it
+ * emitted inline at every log statement site. This helps reduce the emitted
+ * code size for each log statement.
+ */
+LogStreamProcessor::~LogStreamProcessor() noexcept {
+ // The LogStreamProcessor destructor is responsible for logging the message.
+ // Doing this in the destructor avoids an separate function call to log the
+ // message being emitted inline at every log statement site.
+ logNow();
+}
+
+void LogStreamProcessor::logNow() noexcept {
// Note that admitMessage() is not noexcept and theoretically may throw.
// However, the only exception that should be possible is std::bad_alloc if
// we fail to allocate memory. We intentionally let our noexcept specifier
//
// Any other error here is unexpected and we also want to fail hard
// in that situation too.
- auto& logStream = static_cast<LogStream&>(stream);
category_->admitMessage(LogMessage{category_,
level_,
filename_,
lineNumber_,
- extractMessageString(logStream)});
+ extractMessageString(stream_)});
}
-void LogStreamProcessor::operator&(LogStream&& stream) noexcept {
- // This version of operator&() is generally only invoked when
- // no streaming arguments were supplied to the logging macro.
- // Therefore we don't bother calling extractMessageString(stream),
- // and just directly use message_.
- DCHECK(stream.empty());
-
- category_->admitMessage(LogMessage{
- category_, level_, filename_, lineNumber_, std::move(message_)});
+void LogStreamVoidify<true>::operator&(std::ostream& stream) {
+ // Non-fatal log messages wait until the LogStreamProcessor destructor to log
+ // the message. However for fatal messages we log immediately in the &
+ // operator, since it is marked noreturn.
+ //
+ // This does result in slightly larger emitted code for fatal log messages
+ // (since the operator & call cannot be completely omitted). However, fatal
+ // log messages should typically be much more rare than non-fatal messages,
+ // so the small amount of extra overhead shouldn't be a big deal.
+ auto& logStream = static_cast<LogStream&>(stream);
+ logStream.getProcessor()->logNow();
+ abort();
}
std::string LogStreamProcessor::extractMessageString(