LogStreamProcessor.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <folly/logging/LogStreamProcessor.h>
  17. #include <folly/logging/LogStream.h>
  18. #include <folly/logging/xlog.h>
  19. namespace folly {
  20. LogStreamProcessor::LogStreamProcessor(
  21. const LogCategory* category,
  22. LogLevel level,
  23. folly::StringPiece filename,
  24. unsigned int lineNumber,
  25. folly::StringPiece functionName,
  26. AppendType) noexcept
  27. : LogStreamProcessor(
  28. category,
  29. level,
  30. filename,
  31. lineNumber,
  32. functionName,
  33. INTERNAL,
  34. std::string()) {}
  35. LogStreamProcessor::LogStreamProcessor(
  36. XlogCategoryInfo<true>* categoryInfo,
  37. LogLevel level,
  38. folly::StringPiece categoryName,
  39. bool isCategoryNameOverridden,
  40. folly::StringPiece filename,
  41. unsigned int lineNumber,
  42. folly::StringPiece functionName,
  43. AppendType) noexcept
  44. : LogStreamProcessor(
  45. categoryInfo,
  46. level,
  47. categoryName,
  48. isCategoryNameOverridden,
  49. filename,
  50. lineNumber,
  51. functionName,
  52. INTERNAL,
  53. std::string()) {}
  54. LogStreamProcessor::LogStreamProcessor(
  55. const LogCategory* category,
  56. LogLevel level,
  57. folly::StringPiece filename,
  58. unsigned int lineNumber,
  59. folly::StringPiece functionName,
  60. InternalType,
  61. std::string&& msg) noexcept
  62. : category_{category},
  63. level_{level},
  64. filename_{filename},
  65. lineNumber_{lineNumber},
  66. functionName_{functionName},
  67. message_{std::move(msg)},
  68. stream_{this} {}
  69. namespace {
  70. LogCategory* getXlogCategory(
  71. XlogCategoryInfo<true>* categoryInfo,
  72. folly::StringPiece categoryName,
  73. bool isCategoryNameOverridden) {
  74. if (!categoryInfo->isInitialized()) {
  75. return categoryInfo->init(categoryName, isCategoryNameOverridden);
  76. }
  77. return categoryInfo->getCategory(&xlog_detail::xlogFileScopeInfo);
  78. }
  79. } // namespace
  80. /**
  81. * Construct a LogStreamProcessor from an XlogCategoryInfo.
  82. *
  83. * We intentionally define this in LogStreamProcessor.cpp instead of
  84. * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
  85. * to reduce the emitted code size.
  86. */
  87. LogStreamProcessor::LogStreamProcessor(
  88. XlogCategoryInfo<true>* categoryInfo,
  89. LogLevel level,
  90. folly::StringPiece categoryName,
  91. bool isCategoryNameOverridden,
  92. folly::StringPiece filename,
  93. unsigned int lineNumber,
  94. folly::StringPiece functionName,
  95. InternalType,
  96. std::string&& msg) noexcept
  97. : category_{getXlogCategory(
  98. categoryInfo,
  99. categoryName,
  100. isCategoryNameOverridden)},
  101. level_{level},
  102. filename_{filename},
  103. lineNumber_{lineNumber},
  104. functionName_{functionName},
  105. message_{std::move(msg)},
  106. stream_{this} {}
  107. #ifdef __INCLUDE_LEVEL__
  108. namespace {
  109. LogCategory* getXlogCategory(XlogFileScopeInfo* fileScopeInfo) {
  110. // By the time a LogStreamProcessor is created, the XlogFileScopeInfo object
  111. // should have already been initialized to perform the log level check.
  112. // Therefore we never need to check if it is initialized here.
  113. return fileScopeInfo->category;
  114. }
  115. } // namespace
  116. /**
  117. * Construct a LogStreamProcessor from an XlogFileScopeInfo.
  118. *
  119. * We intentionally define this in LogStreamProcessor.cpp instead of
  120. * LogStreamProcessor.h to avoid having it inlined at every XLOG() call site,
  121. * to reduce the emitted code size.
  122. *
  123. * This is only defined if __INCLUDE_LEVEL__ is available. The
  124. * XlogFileScopeInfo APIs are only invoked if we can use __INCLUDE_LEVEL__ to
  125. * tell that an XLOG() statement occurs in a non-header file. For compilers
  126. * that do not support __INCLUDE_LEVEL__, the category information is always
  127. * passed in as XlogCategoryInfo<true> rather than as XlogFileScopeInfo.
  128. */
  129. LogStreamProcessor::LogStreamProcessor(
  130. XlogFileScopeInfo* fileScopeInfo,
  131. LogLevel level,
  132. folly::StringPiece filename,
  133. unsigned int lineNumber,
  134. folly::StringPiece functionName,
  135. InternalType,
  136. std::string&& msg) noexcept
  137. : category_{getXlogCategory(fileScopeInfo)},
  138. level_{level},
  139. filename_{filename},
  140. lineNumber_{lineNumber},
  141. functionName_{functionName},
  142. message_{std::move(msg)},
  143. stream_{this} {}
  144. LogStreamProcessor::LogStreamProcessor(
  145. XlogFileScopeInfo* fileScopeInfo,
  146. LogLevel level,
  147. folly::StringPiece filename,
  148. unsigned int lineNumber,
  149. folly::StringPiece functionName,
  150. AppendType) noexcept
  151. : LogStreamProcessor(
  152. fileScopeInfo,
  153. level,
  154. filename,
  155. lineNumber,
  156. functionName,
  157. INTERNAL,
  158. std::string()) {}
  159. #endif
  160. /*
  161. * We intentionally define the LogStreamProcessor destructor in
  162. * LogStreamProcessor.cpp instead of LogStreamProcessor.h to avoid having it
  163. * emitted inline at every log statement site. This helps reduce the emitted
  164. * code size for each log statement.
  165. */
  166. LogStreamProcessor::~LogStreamProcessor() noexcept {
  167. // The LogStreamProcessor destructor is responsible for logging the message.
  168. // Doing this in the destructor avoids an separate function call to log the
  169. // message being emitted inline at every log statement site.
  170. logNow();
  171. }
  172. void LogStreamProcessor::logNow() noexcept {
  173. // Note that admitMessage() is not noexcept and theoretically may throw.
  174. // However, the only exception that should be possible is std::bad_alloc if
  175. // we fail to allocate memory. We intentionally let our noexcept specifier
  176. // crash in that case, since the program likely won't be able to continue
  177. // anyway.
  178. //
  179. // Any other error here is unexpected and we also want to fail hard
  180. // in that situation too.
  181. category_->admitMessage(LogMessage{category_,
  182. level_,
  183. filename_,
  184. lineNumber_,
  185. functionName_,
  186. extractMessageString(stream_)});
  187. }
  188. std::string LogStreamProcessor::extractMessageString(
  189. LogStream& stream) noexcept {
  190. if (stream.empty()) {
  191. return std::move(message_);
  192. }
  193. if (message_.empty()) {
  194. return stream.extractString();
  195. }
  196. message_.append(stream.extractString());
  197. return std::move(message_);
  198. }
  199. void LogStreamVoidify<true>::operator&(std::ostream& stream) {
  200. // Non-fatal log messages wait until the LogStreamProcessor destructor to log
  201. // the message. However for fatal messages we log immediately in the &
  202. // operator, since it is marked noreturn.
  203. //
  204. // This does result in slightly larger emitted code for fatal log messages
  205. // (since the operator & call cannot be completely omitted). However, fatal
  206. // log messages should typically be much more rare than non-fatal messages,
  207. // so the small amount of extra overhead shouldn't be a big deal.
  208. auto& logStream = static_cast<LogStream&>(stream);
  209. logStream.getProcessor()->logNow();
  210. abort();
  211. }
  212. void logDisabledHelper(std::true_type) noexcept {
  213. // This function can only be reached if we had a disabled fatal log message.
  214. // This should never happen: LogCategory::setLevelLocked() does not allow
  215. // setting the threshold for a category lower than FATAL (in production
  216. // builds) or DFATAL (in debug builds).
  217. abort();
  218. }
  219. } // namespace folly