Fix copyright lines
[folly.git] / folly / experimental / logging / LogStreamProcessor.cpp
index e70df787fa8e3af2522196b3e4c03f3e5abd949e..b9fd164c57ab6f641f2e19e070314649b3af3f05 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-present Facebook, Inc.
+ * Copyright 2017-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 #include <folly/experimental/logging/LogStreamProcessor.h>
 
-#include <cassert>
-
 #include <folly/experimental/logging/LogStream.h>
+#include <folly/experimental/logging/xlog.h>
 
 namespace folly {
-void LogStreamProcessor::operator&(std::ostream& stream) noexcept {
-  // Note that processMessage() is not noexcept and theoretically may throw.
+
+LogStreamProcessor::LogStreamProcessor(
+    const LogCategory* category,
+    LogLevel level,
+    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(
+    const LogCategory* category,
+    LogLevel level,
+    folly::StringPiece filename,
+    unsigned int lineNumber,
+    InternalType,
+    std::string&& msg) noexcept
+    : category_{category},
+      level_{level},
+      filename_{filename},
+      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);
+}
+} // namespace
+
+/**
+ * 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} {}
+
+#ifdef __INCLUDE_LEVEL__
+namespace {
+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;
+}
+} // namespace
+
+/**
+ * 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.
+ *
+ * This is only defined if __INCLUDE_LEVEL__ is available.  The
+ * XlogFileScopeInfo APIs are only invoked if we can use __INCLUDE_LEVEL__ to
+ * tell that an XLOG() statement occurs in a non-header file.  For compilers
+ * that do not support __INCLUDE_LEVEL__, the category information is always
+ * passed in as XlogCategoryInfo<true> rather than as XlogFileScopeInfo.
+ */
+LogStreamProcessor::LogStreamProcessor(
+    XlogFileScopeInfo* fileScopeInfo,
+    LogLevel level,
+    folly::StringPiece filename,
+    unsigned int lineNumber,
+    InternalType,
+    std::string&& msg) noexcept
+    : category_{getXlogCategory(fileScopeInfo)},
+      level_{level},
+      filename_{filename},
+      lineNumber_{lineNumber},
+      message_{std::move(msg)},
+      stream_{this} {}
+
+LogStreamProcessor::LogStreamProcessor(
+    XlogFileScopeInfo* fileScopeInfo,
+    LogLevel level,
+    folly::StringPiece filename,
+    unsigned int lineNumber,
+    AppendType) noexcept
+    : LogStreamProcessor(
+          fileScopeInfo,
+          level,
+          filename,
+          lineNumber,
+          INTERNAL,
+          std::string()) {}
+#endif
+
+/*
+ * 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
   // crash in that case, since the program likely won't be able to continue
@@ -29,23 +178,11 @@ void LogStreamProcessor::operator&(std::ostream& stream) noexcept {
   //
   // Any other error here is unexpected and we also want to fail hard
   // in that situation too.
-  auto& logStream = static_cast<LogStream&>(stream);
-  category_->processMessage(LogMessage{category_,
-                                       level_,
-                                       filename_,
-                                       lineNumber_,
-                                       extractMessageString(logStream)});
-}
-
-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_.
-  assert(stream.empty());
-
-  category_->processMessage(LogMessage{
-      category_, level_, filename_, lineNumber_, std::move(message_)});
+  category_->admitMessage(LogMessage{category_,
+                                     level_,
+                                     filename_,
+                                     lineNumber_,
+                                     extractMessageString(stream_)});
 }
 
 std::string LogStreamProcessor::extractMessageString(
@@ -60,4 +197,26 @@ std::string LogStreamProcessor::extractMessageString(
   message_.append(stream.extractString());
   return 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();
+}
+
+void logDisabledHelper(std::integral_constant<bool, true>) noexcept {
+  // This function can only be reached if we had a disabled fatal log message.
+  // This should never happen: LogCategory::setLevelLocked() does not allow
+  // setting the threshold for a category lower than FATAL (in production
+  // builds) or DFATAL (in debug builds).
+  abort();
 }
+} // namespace folly