LogCategory.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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/LogCategory.h>
  17. #include <cstdio>
  18. #include <cstdlib>
  19. #include <folly/ConstexprMath.h>
  20. #include <folly/ExceptionString.h>
  21. #include <folly/FileUtil.h>
  22. #include <folly/MapUtil.h>
  23. #include <folly/logging/LogHandler.h>
  24. #include <folly/logging/LogMessage.h>
  25. #include <folly/logging/LogName.h>
  26. #include <folly/logging/LoggerDB.h>
  27. namespace folly {
  28. LogCategory::LogCategory(LoggerDB* db)
  29. : effectiveLevel_{LogLevel::ERR},
  30. level_{static_cast<uint32_t>(LogLevel::ERR)},
  31. parent_{nullptr},
  32. name_{},
  33. db_{db} {}
  34. LogCategory::LogCategory(StringPiece name, LogCategory* parent)
  35. : effectiveLevel_{parent->getEffectiveLevel()},
  36. level_{static_cast<uint32_t>(LogLevel::MAX_LEVEL) | FLAG_INHERIT},
  37. parent_{parent},
  38. name_{LogName::canonicalize(name)},
  39. db_{parent->getDB()},
  40. nextSibling_{parent_->firstChild_} {
  41. parent_->firstChild_ = this;
  42. }
  43. void LogCategory::admitMessage(const LogMessage& message) const {
  44. processMessage(message);
  45. // If this is a fatal message, flush the handlers to make sure the log
  46. // message was written out, then crash.
  47. if (isLogLevelFatal(message.getLevel())) {
  48. auto numHandlers = db_->flushAllHandlers();
  49. if (numHandlers == 0) {
  50. // No log handlers were configured.
  51. // Print the message to stderr, to make sure we always print the reason
  52. // we are crashing somewhere.
  53. auto msg = folly::to<std::string>(
  54. "FATAL:",
  55. message.getFileName(),
  56. ":",
  57. message.getLineNumber(),
  58. ": ",
  59. message.getMessage(),
  60. "\n");
  61. folly::writeFull(STDERR_FILENO, msg.data(), msg.size());
  62. }
  63. std::abort();
  64. }
  65. }
  66. void LogCategory::processMessage(const LogMessage& message) const {
  67. // Make a copy of any attached LogHandlers, so we can release the handlers_
  68. // lock before holding them.
  69. //
  70. // In the common case there will only be a small number of handlers. Use a
  71. // std::array in this case to avoid a heap allocation for the vector.
  72. const std::shared_ptr<LogHandler>* handlers = nullptr;
  73. size_t numHandlers = 0;
  74. constexpr uint32_t kSmallOptimizationSize = 5;
  75. std::array<std::shared_ptr<LogHandler>, kSmallOptimizationSize> handlersArray;
  76. std::vector<std::shared_ptr<LogHandler>> handlersVector;
  77. {
  78. auto lockedHandlers = handlers_.rlock();
  79. numHandlers = lockedHandlers->size();
  80. if (numHandlers <= kSmallOptimizationSize) {
  81. for (size_t n = 0; n < numHandlers; ++n) {
  82. handlersArray[n] = (*lockedHandlers)[n];
  83. }
  84. handlers = handlersArray.data();
  85. } else {
  86. handlersVector = *lockedHandlers;
  87. handlers = handlersVector.data();
  88. }
  89. }
  90. for (size_t n = 0; n < numHandlers; ++n) {
  91. try {
  92. handlers[n]->handleMessage(message, this);
  93. } catch (const std::exception& ex) {
  94. // Use LoggerDB::internalWarning() to report the error, but continue
  95. // trying to log the message to any other handlers attached to ourself or
  96. // one of our parent categories.
  97. LoggerDB::internalWarning(
  98. __FILE__,
  99. __LINE__,
  100. "log handler for category \"",
  101. name_,
  102. "\" threw an error: ",
  103. folly::exceptionStr(ex));
  104. }
  105. }
  106. // Propagate the message up to our parent LogCategory.
  107. //
  108. // Maybe in the future it might be worth adding a flag to control if a
  109. // LogCategory should propagate messages to its parent or not. (This would
  110. // be similar to log4j's "additivity" flag.)
  111. // For now I don't have a strong use case for this.
  112. if (parent_) {
  113. parent_->processMessage(message);
  114. }
  115. }
  116. void LogCategory::addHandler(std::shared_ptr<LogHandler> handler) {
  117. auto handlers = handlers_.wlock();
  118. handlers->emplace_back(std::move(handler));
  119. }
  120. void LogCategory::clearHandlers() {
  121. std::vector<std::shared_ptr<LogHandler>> emptyHandlersList;
  122. // Swap out the handlers list with the handlers_ lock held.
  123. {
  124. auto handlers = handlers_.wlock();
  125. handlers->swap(emptyHandlersList);
  126. }
  127. // Destroy emptyHandlersList now that the handlers_ lock is released.
  128. // This way we don't hold the handlers_ lock while invoking any of the
  129. // LogHandler destructors.
  130. }
  131. std::vector<std::shared_ptr<LogHandler>> LogCategory::getHandlers() const {
  132. return *(handlers_.rlock());
  133. }
  134. void LogCategory::replaceHandlers(
  135. std::vector<std::shared_ptr<LogHandler>> handlers) {
  136. return handlers_.wlock()->swap(handlers);
  137. }
  138. void LogCategory::updateHandlers(const std::unordered_map<
  139. std::shared_ptr<LogHandler>,
  140. std::shared_ptr<LogHandler>>& handlerMap) {
  141. auto handlers = handlers_.wlock();
  142. for (auto& entry : *handlers) {
  143. auto* ptr = get_ptr(handlerMap, entry);
  144. if (ptr) {
  145. entry = *ptr;
  146. }
  147. }
  148. }
  149. void LogCategory::setLevel(LogLevel level, bool inherit) {
  150. // We have to set the level through LoggerDB, since we require holding
  151. // the LoggerDB lock to iterate through our children in case our effective
  152. // level changes.
  153. db_->setLevel(this, level, inherit);
  154. }
  155. void LogCategory::setLevelLocked(LogLevel level, bool inherit) {
  156. // Clamp the value to MIN_LEVEL and MAX_LEVEL.
  157. //
  158. // This makes sure that UNINITIALIZED is always less than any valid level
  159. // value, and that level values cannot conflict with our flag bits.
  160. level = constexpr_clamp(level, LogLevel::MIN_LEVEL, LogLevel::MAX_LEVEL);
  161. // Make sure the inherit flag is always off for the root logger.
  162. if (!parent_) {
  163. inherit = false;
  164. }
  165. auto newValue = static_cast<uint32_t>(level);
  166. if (inherit) {
  167. newValue |= FLAG_INHERIT;
  168. }
  169. // Update the stored value
  170. uint32_t oldValue = level_.exchange(newValue, std::memory_order_acq_rel);
  171. // Break out early if the value has not changed.
  172. if (oldValue == newValue) {
  173. return;
  174. }
  175. // Update the effective log level
  176. LogLevel newEffectiveLevel;
  177. if (inherit) {
  178. newEffectiveLevel = std::min(level, parent_->getEffectiveLevel());
  179. } else {
  180. newEffectiveLevel = level;
  181. }
  182. updateEffectiveLevel(newEffectiveLevel);
  183. }
  184. void LogCategory::updateEffectiveLevel(LogLevel newEffectiveLevel) {
  185. auto oldEffectiveLevel =
  186. effectiveLevel_.exchange(newEffectiveLevel, std::memory_order_acq_rel);
  187. // Break out early if the value did not change.
  188. if (newEffectiveLevel == oldEffectiveLevel) {
  189. return;
  190. }
  191. // Update all of the values in xlogLevels_
  192. for (auto* levelPtr : xlogLevels_) {
  193. levelPtr->store(newEffectiveLevel, std::memory_order_release);
  194. }
  195. // Update all children loggers
  196. LogCategory* child = firstChild_;
  197. while (child != nullptr) {
  198. child->parentLevelUpdated(newEffectiveLevel);
  199. child = child->nextSibling_;
  200. }
  201. }
  202. void LogCategory::parentLevelUpdated(LogLevel parentEffectiveLevel) {
  203. uint32_t levelValue = level_.load(std::memory_order_acquire);
  204. auto inherit = (levelValue & FLAG_INHERIT);
  205. if (!inherit) {
  206. return;
  207. }
  208. auto myLevel = static_cast<LogLevel>(levelValue & ~FLAG_INHERIT);
  209. auto newEffectiveLevel = std::min(myLevel, parentEffectiveLevel);
  210. updateEffectiveLevel(newEffectiveLevel);
  211. }
  212. void LogCategory::registerXlogLevel(std::atomic<LogLevel>* levelPtr) {
  213. xlogLevels_.push_back(levelPtr);
  214. }
  215. } // namespace folly